mirror of
https://github.com/livingcomputermuseum/sImlac.git
synced 2026-01-11 23:53:24 +00:00
Fixes for disassembly of uncached instructions; enhancements of display instruction disassembly. More refactoring of display processor code.
This commit is contained in:
parent
fcf0c96b6c
commit
4c65f894be
@ -210,7 +210,7 @@ namespace imlac
|
||||
|
||||
public abstract void InvalidateCache(ushort address);
|
||||
|
||||
public abstract string Disassemble(ushort address, DisplayProcessorMode mode);
|
||||
public abstract string Disassemble(ushort address, DisplayProcessorMode mode, out int length);
|
||||
|
||||
public abstract void Clock();
|
||||
|
||||
@ -291,10 +291,11 @@ namespace imlac
|
||||
|
||||
protected abstract class DisplayInstructionBase
|
||||
{
|
||||
public DisplayInstructionBase(ushort word, DisplayProcessorMode mode)
|
||||
public DisplayInstructionBase(ushort word, ushort address, DisplayProcessorMode mode)
|
||||
{
|
||||
_usageMode = mode;
|
||||
_word = word;
|
||||
_address = address;
|
||||
Decode();
|
||||
}
|
||||
|
||||
@ -324,17 +325,182 @@ namespace imlac
|
||||
/// </summary>
|
||||
/// <param name="mode"></param>
|
||||
/// <returns></returns>
|
||||
public abstract string Disassemble(DisplayProcessorMode mode);
|
||||
public abstract string Disassemble(DisplayProcessorMode mode, Memory mem, out int length);
|
||||
|
||||
/// <summary>
|
||||
/// Implemented to provide decoding of this instruction word.
|
||||
/// </summary>
|
||||
protected abstract void Decode();
|
||||
|
||||
protected string DisassembleIncrement()
|
||||
{
|
||||
return DisassembleIncrementHalf(ImmediateHalf.First) + " | " + DisassembleIncrementHalf(ImmediateHalf.Second);
|
||||
}
|
||||
|
||||
private string DisassembleIncrementHalf(ImmediateHalf half)
|
||||
{
|
||||
string ret = string.Empty;
|
||||
int halfWord = half == ImmediateHalf.First ? (_word & 0xff00) >> 8 : (_word & 0xff);
|
||||
|
||||
// translate the half word to vector movements or escapes
|
||||
// special case for "Enter Immediate mode" halfword (030) in first half.
|
||||
if (half == ImmediateHalf.First && halfWord == 0x30)
|
||||
{
|
||||
ret += "E";
|
||||
}
|
||||
else if ((halfWord & 0x80) == 0)
|
||||
{
|
||||
if ((halfWord & 0x10) != 0)
|
||||
{
|
||||
ret += "IX ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x08) != 0)
|
||||
{
|
||||
ret += "ZX ";
|
||||
}
|
||||
|
||||
if (half == ImmediateHalf.Second &&
|
||||
(halfWord & 0x04) != 0)
|
||||
{
|
||||
ret += "E PPM ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x02) != 0)
|
||||
{
|
||||
ret += "IY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x01) != 0)
|
||||
{
|
||||
ret += "ZY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x40) != 0)
|
||||
{
|
||||
if ((halfWord & 0x20) != 0)
|
||||
{
|
||||
// escape and return
|
||||
ret += "F RJM";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Escape
|
||||
ret += "F";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int xSign = ((halfWord & 0x20) == 0) ? 1 : -1;
|
||||
int xMag = (int)(((halfWord & 0x18) >> 3));
|
||||
|
||||
int ySign = (int)(((halfWord & 0x04) == 0) ? 1 : -1);
|
||||
int yMag = (int)((halfWord & 0x03));
|
||||
|
||||
ret += String.Format("{0},{1} {2}", xMag * xSign, yMag * ySign, (halfWord & 0x40) == 0 ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected string DisassembleProcessor(Memory mem, out int length)
|
||||
{
|
||||
length = 1;
|
||||
|
||||
string ret = String.Empty;
|
||||
if (_opcode == DisplayOpcode.DOPR)
|
||||
{
|
||||
string[] codes = { "INV0 ", "INV1 ", "INV2 ", "INV3 ", "DDSP ", "DRJM ", "DDYM ", "DDXM ", "DIYM ", "DIXM ", "DHVC ", "DHLT " };
|
||||
|
||||
for (int i = 4; i < 11; i++)
|
||||
{
|
||||
if ((_data & (0x01) << i) != 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ret))
|
||||
{
|
||||
ret += ",";
|
||||
}
|
||||
|
||||
ret += codes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// display halt if bit 4 is unset
|
||||
if ((_data & 0x800) == 0)
|
||||
{
|
||||
ret += " DHLT ";
|
||||
}
|
||||
|
||||
// F/C ops:
|
||||
int f = (_data & 0xc) >> 2;
|
||||
int c = _data & 0x3;
|
||||
|
||||
switch (f)
|
||||
{
|
||||
case 0x0:
|
||||
// nothing
|
||||
if (c == 1)
|
||||
{
|
||||
ret += String.Format("DADR");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
ret += String.Format("DSTS {0}", c);
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
ret += String.Format("DSTB {0}", c);
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
ret += String.Format("DLPN {0}", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (_opcode)
|
||||
{
|
||||
case DisplayOpcode.DEIM:
|
||||
ret = String.Format("DEIM | {0} {1}",
|
||||
DisassembleIncrementHalf(ImmediateHalf.Second),
|
||||
(_word & 0xff00) == 0x3800 ? "Enter PPM" : String.Empty);
|
||||
break;
|
||||
|
||||
case DisplayOpcode.DLXA:
|
||||
ret = String.Format("DLXA {0} ({1})", Helpers.ToOctal(_data), _data);
|
||||
break;
|
||||
|
||||
case DisplayOpcode.DLYA:
|
||||
ret = String.Format("DLXA {0} ({1})", Helpers.ToOctal(_data), _data);
|
||||
break;
|
||||
|
||||
case DisplayOpcode.DJMS:
|
||||
ret = String.Format("DJMS {0}", Helpers.ToOctal(_data));
|
||||
break;
|
||||
|
||||
case DisplayOpcode.DJMP:
|
||||
ret = String.Format("DJMP {0}", Helpers.ToOctal(_data));
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = DisassembleExtended(mem, out length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected abstract string DisassembleExtended(Memory mem, out int length);
|
||||
|
||||
protected DisplayOpcode _opcode;
|
||||
protected ushort _data;
|
||||
protected DisplayProcessorMode _usageMode;
|
||||
protected ushort _word;
|
||||
protected ushort _address;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ namespace imlac
|
||||
_instructionCache[address & Memory.SizeMask] = null;
|
||||
}
|
||||
|
||||
public override string Disassemble(ushort address, DisplayProcessorMode mode)
|
||||
public override string Disassemble(ushort address, DisplayProcessorMode mode, out int length)
|
||||
{
|
||||
//
|
||||
// Return a precached instruction if we have it due to previous execution
|
||||
@ -62,11 +62,11 @@ namespace imlac
|
||||
//
|
||||
if (_instructionCache[address & Memory.SizeMask] != null)
|
||||
{
|
||||
return _instructionCache[address & Memory.SizeMask].Disassemble(mode);
|
||||
return _instructionCache[address & Memory.SizeMask].Disassemble(mode, _mem, out length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new PDS1DisplayInstruction((ushort)(address & Memory.SizeMask), mode).Disassemble(mode);
|
||||
return new PDS1DisplayInstruction(_mem.Fetch(address), address, mode).Disassemble(mode, _mem, out length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,7 +545,7 @@ namespace imlac
|
||||
{
|
||||
if (_instructionCache[address & Memory.SizeMask] == null)
|
||||
{
|
||||
_instructionCache[address & Memory.SizeMask] = new PDS1DisplayInstruction(_mem.Fetch(address), mode);
|
||||
_instructionCache[address & Memory.SizeMask] = new PDS1DisplayInstruction(_mem.Fetch(address), address, mode);
|
||||
}
|
||||
|
||||
return _instructionCache[address & Memory.SizeMask];
|
||||
@ -568,11 +568,11 @@ namespace imlac
|
||||
/// </summary>
|
||||
private class PDS1DisplayInstruction : DisplayInstructionBase
|
||||
{
|
||||
public PDS1DisplayInstruction(ushort word, DisplayProcessorMode mode) : base (word, mode)
|
||||
public PDS1DisplayInstruction(ushort word, ushort address, DisplayProcessorMode mode) : base (word, address, mode)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Disassemble(DisplayProcessorMode mode)
|
||||
public override string Disassemble(DisplayProcessorMode mode, Memory mem, out int length)
|
||||
{
|
||||
if (mode == DisplayProcessorMode.Indeterminate)
|
||||
{
|
||||
@ -582,12 +582,14 @@ namespace imlac
|
||||
switch (mode)
|
||||
{
|
||||
case DisplayProcessorMode.Increment:
|
||||
length = 1;
|
||||
return DisassembleIncrement();
|
||||
|
||||
case DisplayProcessorMode.Processor:
|
||||
return DisassembleProcessor();
|
||||
return DisassembleProcessor(mem, out length);
|
||||
|
||||
case DisplayProcessorMode.Indeterminate:
|
||||
length = 1;
|
||||
return "Indeterminate";
|
||||
|
||||
default:
|
||||
@ -712,132 +714,75 @@ namespace imlac
|
||||
|
||||
}
|
||||
|
||||
private string DisassembleIncrement()
|
||||
{
|
||||
return DisassembleIncrementHalf(ImmediateHalf.First) + " | " + DisassembleIncrementHalf(ImmediateHalf.Second);
|
||||
}
|
||||
|
||||
private string DisassembleIncrementHalf(ImmediateHalf half)
|
||||
{
|
||||
string ret = string.Empty;
|
||||
int halfWord = half == ImmediateHalf.First ? (_word & 0xff00) >> 8 : (_word & 0xff);
|
||||
|
||||
// translate the half word to vector movements or escapes
|
||||
// special case for "Enter Immediate mode" halfword (030) in first half.
|
||||
if (half == ImmediateHalf.First && halfWord == 0x30)
|
||||
{
|
||||
ret += "E";
|
||||
}
|
||||
else if ((halfWord & 0x80) == 0)
|
||||
{
|
||||
if ((halfWord & 0x10) != 0)
|
||||
{
|
||||
ret += "IX ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x08) != 0)
|
||||
{
|
||||
ret += "ZX ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x02) != 0)
|
||||
{
|
||||
ret += "IY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x01) != 0)
|
||||
{
|
||||
ret += "ZY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x40) != 0)
|
||||
{
|
||||
if ((halfWord & 0x20) != 0)
|
||||
{
|
||||
// escape and return
|
||||
ret += "F RJM";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Escape
|
||||
ret += "F";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int xSign = ((halfWord & 0x20) == 0) ? 1 : -1;
|
||||
int xMag = (int)(((halfWord & 0x18) >> 3));
|
||||
|
||||
int ySign = (int)(((halfWord & 0x04) == 0) ? 1 : -1);
|
||||
int yMag = (int)((halfWord & 0x03));
|
||||
|
||||
ret += String.Format("{0},{1} {2}", xMag * xSign, yMag * ySign, (halfWord & 0x40) == 0 ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void DecodeImmediate()
|
||||
{
|
||||
// TODO: eventually actually precache movement calculations.
|
||||
}
|
||||
|
||||
private string DisassembleProcessor()
|
||||
protected override string DisassembleExtended(Memory mem, out int length)
|
||||
{
|
||||
string ret = String.Empty;
|
||||
if (_opcode == DisplayOpcode.DOPR)
|
||||
{
|
||||
string[] codes = { "INV0 ", "INV1 ", "INV2 ", "INV3 ", "DDSP ", "DRJM ", "DDYM ", "DDXM ", "DIYM ", "DIXM ", "DHVC ", "DHLT " };
|
||||
|
||||
for (int i = 4; i < 12; i++)
|
||||
{
|
||||
if ((_data & (0x01) << i) != 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ret))
|
||||
{
|
||||
ret += ",";
|
||||
}
|
||||
|
||||
ret += codes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// F/C ops:
|
||||
int f = (_data & 0xc) >> 2;
|
||||
int c = _data & 0x3;
|
||||
|
||||
switch (f)
|
||||
{
|
||||
case 0x0:
|
||||
// nothing
|
||||
if (c == 1)
|
||||
{
|
||||
ret += String.Format("DADR");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
ret += String.Format("DSTS {0}", c);
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
ret += String.Format("DSTB {0}", c);
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
ret += String.Format("DLPN {0}", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
switch (_opcode)
|
||||
{
|
||||
// keep things simple -- should add special support for extended instructions at some point...
|
||||
ret = String.Format("{0} {1} ", _opcode, Helpers.ToOctal(_data));
|
||||
case DisplayOpcode.DLVH:
|
||||
length = 3;
|
||||
ret = DecodeLongVector(mem);
|
||||
break;
|
||||
|
||||
default:
|
||||
length = 1;
|
||||
// Handle as yet not-special-cased opcodes
|
||||
ret = String.Format("{0} {1}", _opcode, Helpers.ToOctal(_data));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private string DecodeLongVector(Memory mem)
|
||||
{
|
||||
//
|
||||
// A Long Vector instruction is 3 words long:
|
||||
// Word 0: upper 4 bits indicate the opcode (4), lower 12 specify N-M
|
||||
// Word 1: upper 3 bits specify beam options (dotted, solid, etc) and the lower 12 specify the larger increment "M"
|
||||
// Word 2: upper 3 bits specify signs, lower 12 specify the smaller increment "N"
|
||||
// M is the larger absolute value between dX and dY
|
||||
// N is the smaller.
|
||||
//
|
||||
// TODO: Would make sense to precache this during decoding, would require
|
||||
// modifications to cache invalidation logic.
|
||||
ushort word1 = mem.Fetch((ushort)(_address + 1));
|
||||
ushort word2 = mem.Fetch((ushort)(_address + 2));
|
||||
|
||||
uint M = (uint)(word1 & 0x3ff);
|
||||
uint N = (uint)(word2 & 0x3ff);
|
||||
|
||||
bool beamOn = (word1 & 0x2000) != 0;
|
||||
bool dotted = (word1 & 0x4000) != 0;
|
||||
|
||||
int dySign = (word2 & 0x2000) != 0 ? -1 : 1;
|
||||
int dxSign = (word2 & 0x4000) != 0 ? -1 : 1;
|
||||
bool dyGreater = (word2 & 0x1000) != 0;
|
||||
|
||||
uint dx = 0;
|
||||
uint dy = 0;
|
||||
|
||||
if (dyGreater)
|
||||
{
|
||||
dy = M;
|
||||
dx = N;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = M;
|
||||
dy = N;
|
||||
}
|
||||
|
||||
return String.Format("DLVH ({0},{1}) {2} {3}",
|
||||
dx * dxSign, dy * dySign,
|
||||
beamOn ? "ON" : "OFF",
|
||||
dotted ? "DOTTED" : String.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ namespace imlac
|
||||
_instructionCache[address & Memory.SizeMask] = null;
|
||||
}
|
||||
|
||||
public override string Disassemble(ushort address, DisplayProcessorMode mode)
|
||||
public override string Disassemble(ushort address, DisplayProcessorMode mode, out int length)
|
||||
{
|
||||
//
|
||||
// Return a precached instruction if we have it due to previous execution
|
||||
@ -68,11 +68,11 @@ namespace imlac
|
||||
//
|
||||
if (_instructionCache[address & Memory.SizeMask] != null)
|
||||
{
|
||||
return _instructionCache[address & Memory.SizeMask].Disassemble(mode);
|
||||
return _instructionCache[address & Memory.SizeMask].Disassemble(mode, _mem, out length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new PDS4DisplayInstruction((ushort)(address & Memory.SizeMask), mode).Disassemble(mode);
|
||||
return new PDS4DisplayInstruction(_mem.Fetch(address), address, mode).Disassemble(mode, _mem, out length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,7 +678,7 @@ namespace imlac
|
||||
{
|
||||
if (_instructionCache[address & Memory.SizeMask] == null)
|
||||
{
|
||||
_instructionCache[address & Memory.SizeMask] = new PDS4DisplayInstruction(_mem.Fetch(address), mode);
|
||||
_instructionCache[address & Memory.SizeMask] = new PDS4DisplayInstruction(_mem.Fetch(address), address, mode);
|
||||
}
|
||||
|
||||
return _instructionCache[address & Memory.SizeMask];
|
||||
@ -716,11 +716,11 @@ namespace imlac
|
||||
/// </summary>
|
||||
private class PDS4DisplayInstruction : DisplayInstructionBase
|
||||
{
|
||||
public PDS4DisplayInstruction(ushort word, DisplayProcessorMode mode) : base (word, mode)
|
||||
public PDS4DisplayInstruction(ushort word, ushort address, DisplayProcessorMode mode) : base (word, address, mode)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Disassemble(DisplayProcessorMode mode)
|
||||
public override string Disassemble(DisplayProcessorMode mode, Memory mem, out int length)
|
||||
{
|
||||
if (mode == DisplayProcessorMode.Indeterminate)
|
||||
{
|
||||
@ -730,12 +730,14 @@ namespace imlac
|
||||
switch (mode)
|
||||
{
|
||||
case DisplayProcessorMode.Increment:
|
||||
length = 1;
|
||||
return DisassembleIncrement();
|
||||
|
||||
case DisplayProcessorMode.Processor:
|
||||
return DisassembleProcessor();
|
||||
return DisassembleProcessor(mem, out length);
|
||||
|
||||
case DisplayProcessorMode.Indeterminate:
|
||||
length = 1;
|
||||
return "Indeterminate";
|
||||
|
||||
default:
|
||||
@ -909,132 +911,90 @@ namespace imlac
|
||||
}
|
||||
}
|
||||
|
||||
private string DisassembleIncrement()
|
||||
{
|
||||
return DisassembleIncrementHalf(ImmediateHalf.First) + " | " + DisassembleIncrementHalf(ImmediateHalf.Second);
|
||||
}
|
||||
|
||||
private string DisassembleIncrementHalf(ImmediateHalf half)
|
||||
{
|
||||
string ret = string.Empty;
|
||||
int halfWord = half == ImmediateHalf.First ? (_word & 0xff00) >> 8 : (_word & 0xff);
|
||||
|
||||
// translate the half word to vector movements or escapes
|
||||
// special case for "Enter Immediate mode" halfword (030) in first half.
|
||||
if (half == ImmediateHalf.First && halfWord == 0x30)
|
||||
{
|
||||
ret += "E";
|
||||
}
|
||||
else if ((halfWord & 0x80) == 0)
|
||||
{
|
||||
if ((halfWord & 0x10) != 0)
|
||||
{
|
||||
ret += "IX ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x08) != 0)
|
||||
{
|
||||
ret += "ZX ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x02) != 0)
|
||||
{
|
||||
ret += "IY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x01) != 0)
|
||||
{
|
||||
ret += "ZY ";
|
||||
}
|
||||
|
||||
if ((halfWord & 0x40) != 0)
|
||||
{
|
||||
if ((halfWord & 0x20) != 0)
|
||||
{
|
||||
// escape and return
|
||||
ret += "F RJM";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Escape
|
||||
ret += "F";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int xSign = ((halfWord & 0x20) == 0) ? 1 : -1;
|
||||
int xMag = (int)(((halfWord & 0x18) >> 3));
|
||||
|
||||
int ySign = (int)(((halfWord & 0x04) == 0) ? 1 : -1);
|
||||
int yMag = (int)((halfWord & 0x03));
|
||||
|
||||
ret += String.Format("{0},{1} {2}", xMag * xSign, yMag * ySign, (halfWord & 0x40) == 0 ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void DecodeImmediate()
|
||||
{
|
||||
// TODO: eventually actually precache movement calculations.
|
||||
}
|
||||
|
||||
private string DisassembleProcessor()
|
||||
protected override string DisassembleExtended(Memory mem, out int length)
|
||||
{
|
||||
string ret = String.Empty;
|
||||
if (_opcode == DisplayOpcode.DOPR)
|
||||
{
|
||||
string[] codes = { "INV0 ", "INV1 ", "INV2 ", "INV3 ", "DDSP ", "DRJM ", "DDYM ", "DDXM ", "DIYM ", "DIXM ", "DHVC ", "DHLT " };
|
||||
|
||||
for (int i = 4; i < 12; i++)
|
||||
{
|
||||
if ((_data & (0x01) << i) != 0)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ret))
|
||||
{
|
||||
ret += ",";
|
||||
}
|
||||
|
||||
ret += codes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// F/C ops:
|
||||
int f = (_data & 0xc) >> 2;
|
||||
int c = _data & 0x3;
|
||||
|
||||
switch (f)
|
||||
{
|
||||
case 0x0:
|
||||
// nothing
|
||||
if (c == 1)
|
||||
{
|
||||
ret += String.Format("DADR");
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1:
|
||||
ret += String.Format("DSTS {0}", c);
|
||||
break;
|
||||
|
||||
case 0x2:
|
||||
ret += String.Format("DSTB {0}", c);
|
||||
break;
|
||||
|
||||
case 0x3:
|
||||
ret += String.Format("DLPN {0}", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
switch (_opcode)
|
||||
{
|
||||
// keep things simple -- should add special support for extended instructions at some point...
|
||||
ret = String.Format("{0} {1} ", _opcode, Helpers.ToOctal(_data));
|
||||
case DisplayOpcode.DLVH:
|
||||
length = 2;
|
||||
ret = DecodeLongVector(mem);
|
||||
break;
|
||||
|
||||
default:
|
||||
length = 1;
|
||||
// Handle as yet not-special-cased opcodes
|
||||
ret = String.Format("{0} {1}", _opcode, Helpers.ToOctal(_data));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private string DecodeLongVector(Memory mem)
|
||||
{
|
||||
//
|
||||
// A Long Vector instruction is 3 words long:
|
||||
// Word 0: upper 4 bits indicate the opcode (4), lower 12 specify N-M
|
||||
// Word 1: upper 3 bits specify beam options (dotted, solid, etc) and the lower 12 specify the larger increment "M"
|
||||
// Word 2: upper 3 bits specify signs, lower 12 specify the smaller increment "N"
|
||||
// M is the larger absolute value between dX and dY
|
||||
// N is the smaller.
|
||||
//
|
||||
// TODO: As with the PDS-1 variant, would make sense to precache this during decoding, would require
|
||||
// modifications to cache invalidation logic.
|
||||
ushort word1 = mem.Fetch((ushort)(_address + 1));
|
||||
|
||||
// Not documented, but from empirical evidence from PDS-4 games
|
||||
// (pong, crash) the magnitude is scaled by 2 (i.e. specified LSBN is bit 1 of X and Y AC's)
|
||||
uint M = (uint)(_word & 0x3ff) << 1;
|
||||
uint N = (uint)(word1 & 0x3ff) << 1;
|
||||
|
||||
bool ret = (word1 & 0x8000) != 0;
|
||||
bool dotted = (word1 & 0x4000) != 0;
|
||||
bool dashed = (word1 & 0x2000) != 0;
|
||||
bool beamOn = (word1 & 0x1000) != 0;
|
||||
bool dyGreater = (word1 & 0x0800) != 0;
|
||||
|
||||
int mSign = (_word & 0x0400) != 0 ? -1 : 1;
|
||||
int nSign = (word1 & 0x0400) != 0 ? -1 : 1;
|
||||
|
||||
uint dx = 0;
|
||||
uint dy = 0;
|
||||
|
||||
int dxSign = 0;
|
||||
int dySign = 0;
|
||||
|
||||
if (dyGreater)
|
||||
{
|
||||
dy = M;
|
||||
dx = N;
|
||||
|
||||
dySign = mSign;
|
||||
dxSign = nSign;
|
||||
}
|
||||
else
|
||||
{
|
||||
dx = M;
|
||||
dy = N;
|
||||
dxSign = mSign;
|
||||
dySign = nSign;
|
||||
}
|
||||
|
||||
return String.Format("DLVH ({0},{1}) {2}{3}{4}{5}",
|
||||
dx * dxSign,
|
||||
dy * dySign,
|
||||
beamOn ? "ON " : "OFF ",
|
||||
dotted ? "DOTTED " : String.Empty,
|
||||
dashed ? "DASHED " : String.Empty,
|
||||
ret ? "RET " : String.Empty);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,28 +667,31 @@ namespace imlac
|
||||
}
|
||||
|
||||
ushort endAddress = (ushort)Math.Min(Memory.Size, startAddress + length);
|
||||
|
||||
for (ushort address = startAddress; address < endAddress; address++)
|
||||
ushort address = startAddress;
|
||||
while (address < endAddress)
|
||||
{
|
||||
string disassembly = string.Empty;
|
||||
|
||||
int size = 0;
|
||||
try
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case DisassemblyMode.Processor:
|
||||
size = 1;
|
||||
disassembly = Processor.Disassemble(address);
|
||||
break;
|
||||
|
||||
case DisassemblyMode.DisplayAuto:
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Indeterminate);
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Indeterminate, out size);
|
||||
break;
|
||||
|
||||
case DisassemblyMode.DisplayProcessor:
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Processor);
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Processor, out size);
|
||||
break;
|
||||
|
||||
case DisassemblyMode.DisplayIncrement:
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Increment);
|
||||
disassembly = DisplayProcessor.Disassemble(address, DisplayProcessorMode.Increment, out size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -696,9 +699,12 @@ namespace imlac
|
||||
{
|
||||
// this can happen if the data is not a valid instruction
|
||||
disassembly = "<invalid instruction>";
|
||||
size = 1;
|
||||
}
|
||||
|
||||
Console.WriteLine("{0}\\{1} {2}", Helpers.ToOctal(address), Helpers.ToOctal(Memory.Fetch(address)), disassembly);
|
||||
|
||||
address += (ushort)size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user