diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs
index c116d26..9175c04 100644
--- a/Contralto/CPU/CPU.cs
+++ b/Contralto/CPU/CPU.cs
@@ -22,13 +22,15 @@ namespace Contralto.CPU
DiskWord = 14,
}
- public class AltoCPU
+ public partial class AltoCPU
{
public AltoCPU(AltoSystem system)
{
_system = system;
_tasks[(int)TaskType.Emulator] = new EmulatorTask(this);
+ _tasks[(int)TaskType.DiskSector] = new DiskTask(this, true);
+ _tasks[(int)TaskType.DiskWord] = new DiskTask(this, false);
Reset();
}
@@ -78,7 +80,6 @@ namespace Contralto.CPU
get { return _aluC0; }
}
-
public void Reset()
{
// Reset registers
@@ -169,769 +170,11 @@ namespace Contralto.CPU
if (_tasks[i] != null && _tasks[i].Wakeup)
{
_nextTask = _tasks[i];
+ break;
}
}
}
- // Task:
- // Base task class: provides implementation for non-task-specific microcode execution and
- // state. Task subclasses implement and execute Task-specific behavior and are called into
- // by the base class as necessary.
- public abstract class Task
- {
- public Task(AltoCPU cpu)
- {
- _wakeup = false;
- _mpc = 0xffff; // invalid, for sanity checking
- _taskType = TaskType.Invalid;
- _cpu = cpu;
- }
-
- public int Priority
- {
- get { return (int)_taskType; }
- }
-
- public bool Wakeup
- {
- get { return _wakeup; }
- }
-
- public ushort MPC
- {
- get { return _mpc; }
- }
-
- public virtual void Reset()
- {
- // From The Alto Hardware Manual (section 2, "Initialization"):
- // "...each task start[s] at the location which is its task number"
- //
- _mpc = (ushort)_taskType;
- }
-
- public virtual void BlockTask()
- {
- _wakeup = false;
- }
-
- public virtual void WakeupTask()
- {
- _wakeup = true;
- }
-
- public bool ExecuteNext()
- {
- // TODO: cache microinstructions (or pre-decode them) to save consing all these up every time.
- MicroInstruction instruction = new MicroInstruction(UCodeMemory.UCodeROM[_mpc]);
- return ExecuteInstruction(instruction);
- }
-
- ///
- /// ExecuteInstruction causes the Task to execute the next instruction (the one
- /// _mpc is pointing to). The base implementation covers non-task specific logic; subclasses may
- /// provide their own overrides.
- ///
- /// True if a task switch has been requested by a TASK instruction, false otherwise.
- protected virtual bool ExecuteInstruction(MicroInstruction instruction)
- {
- bool nextTask = false;
- bool loadR = false;
- ushort aluData = 0;
- ushort nextModifier = 0;
- _loadS = false;
- _rSelect = 0;
- _busData = 0;
-
-
- Shifter.SetMagic(false);
-
- //
- // Wait for memory state machine if a memory operation is requested by this instruction and
- // the memory isn't ready yet.
- // TODO: this needs to be seriously cleaned up.
- //
- if (instruction.BS == BusSource.ReadMD ||
- instruction.F1 == SpecialFunction1.LoadMAR ||
- instruction.F2 == SpecialFunction2.StoreMD)
- {
-
- MemoryOperation op;
-
- if (instruction.BS == BusSource.ReadMD)
- {
- op = MemoryOperation.Read;
- }
- else if(instruction.F1 == SpecialFunction1.LoadMAR)
- {
- op = MemoryOperation.LoadAddress;
- }
- else
- {
- op = MemoryOperation.Store;
- }
-
- if (!_cpu._system.MemoryBus.Ready(op))
- {
- // Suspend operation for this cycle.
- return false;
- }
- }
-
- // If we have a modified next field from the last instruction, make sure it gets applied to this one.
- nextModifier = _nextModifier;
- _nextModifier = 0;
-
- _rSelect = instruction.RSELECT;
-
- // Give tasks the chance to modify parameters early on (like RSELECT)
- ExecuteSpecialFunction2Early((int)instruction.F2);
-
- // Select BUS data.
- if (instruction.F1 != SpecialFunction1.Constant &&
- instruction.F2 != SpecialFunction2.Constant)
- {
- // Normal BUS data (not constant ROM access).
- switch (instruction.BS)
- {
- case BusSource.ReadR:
- _busData = _cpu._r[_rSelect];
- break;
-
- case BusSource.LoadR:
- _busData = 0; // "Loading R forces the BUS to 0 so that an ALU function of 0 and T may be executed simultaneously"
- loadR = true;
- break;
-
- case BusSource.None:
- _busData = 0xffff; // "Enables no source to the BUS, leaving it all ones"
- break;
-
- case BusSource.TaskSpecific1:
- case BusSource.TaskSpecific2:
- _busData = GetBusSource((int)instruction.BS); // task specific -- call into specific implementation
- break;
-
- case BusSource.ReadMD:
- _busData = _cpu._system.MemoryBus.ReadMD();
- break;
-
- case BusSource.ReadMouse:
- //throw new NotImplementedException("ReadMouse bus source not implemented.");
- _busData = 0; // TODO: implement;
- break;
-
- case BusSource.ReadDisp:
- // "The high-order bits of IR cannot be read directly, but the displacement field of IR (8 low order bits),
- // may be read with the <-DISP bus source. If the X field of the instruction is zero (i.e. it specifies page 0
- // addressing) then the DISP field of the instruction is put on BUS[8-15] and BUS[0-7] is zeroed. If the X
- // field of the instruction is nonzero (i.e. it specifies PC-relative or base-register addressing) then the DISP
- // field is sign-extended and put on the bus."
- // NB: the "X" field of the NOVA instruction is IR[6-7]
- _busData = (ushort)(_cpu._ir & 0xff);
-
- if ((_cpu._ir & 0x300) != 0)
- {
- // sign extend if necessary
- if ((_cpu._ir & 0x80) == 0x80)
- {
- _busData |= (0xff00);
- }
- }
- break;
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled bus source {0}.", instruction.BS));
- break;
- }
- }
- else
- {
- // See also comments below.
- _busData = ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
- }
-
- // Constant ROM access:
- // The constant memory is gated to the bus by F1=7, F2=7, or BS>4. The constant memory is addressed by the
- // (8 bit) concatenation of RSELECT and BS. The intent in enabling constants with BS>4 is to provide a masking
- // facility, particularly for the <-MOUSE and <-DISP bus sources. This works because the processor bus ANDs if
- // more than one source is gated to it. Up to 32 such mask contans can be provided for each of the four bus sources
- // > 4.
- // NOTE also:
- // "Note that the [emulator task F2] functions which replace the low bits of RSELECT with IR aaffect only the
- // selection of R; they do not affect the address supplied to the constant ROM."
- // Hence we use the unmodified RSELECT value here and above.
- if ((int)instruction.BS > 4 ||
- instruction.F1 == SpecialFunction1.Constant ||
- instruction.F2 == SpecialFunction2.Constant)
- {
- _busData &= ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
- }
-
- // Do ALU operation
- aluData = ALU.Execute(instruction.ALUF, _busData, _cpu._t, _skip);
-
- // Reset shifter op
- Shifter.SetOperation(ShifterOp.None, 0);
-
- //
- // Do Special Functions
- //
- switch(instruction.F1)
- {
- case SpecialFunction1.None:
- // Do nothing. Well, that was easy.
- break;
-
- case SpecialFunction1.LoadMAR:
- _cpu._system.MemoryBus.LoadMAR(aluData); // Start main memory reference
- break;
-
- case SpecialFunction1.Task:
- nextTask = true; // Yield to other more important tasks
- break;
-
- case SpecialFunction1.Block:
- // Technically this is to be invoked by the hardware device associated with a task.
- // That logic would be circituous and unless there's a good reason not to that is discovered
- // later, I'm just going to directly block the current task here.
- _cpu.BlockTask(this._taskType);
- break;
-
- case SpecialFunction1.LLSH1:
- Shifter.SetOperation(ShifterOp.ShiftLeft, 1);
- break;
-
- case SpecialFunction1.LRSH1:
- Shifter.SetOperation(ShifterOp.ShiftRight, 1);
- break;
-
- case SpecialFunction1.LLCY8:
- Shifter.SetOperation(ShifterOp.RotateLeft, 8);
- break;
-
- case SpecialFunction1.Constant:
- // Ignored here; handled by Constant ROM access logic above.
- break;
-
- default:
- // Let the specific task implementation take a crack at this.
- ExecuteSpecialFunction1((int)instruction.F1);
- break;
- }
-
- switch(instruction.F2)
- {
- case SpecialFunction2.None:
- // Nothing!
- break;
-
- case SpecialFunction2.BusEq0:
- if (_busData == 0)
- {
- _nextModifier = 1;
- }
- break;
-
- case SpecialFunction2.ShLt0:
- //
- // Note:
- // "the value of SHIFTER OUTPUT is determined by the value of L as the microinstruction
- // *begins* execution and the shifter function specified during the *current* microinstruction.
- //
- // Since we haven't modifed L yet, and we've selected the shifter function above, we're good to go here.
- //
- if ((short)Shifter.DoOperation(_cpu._l, _cpu._t) < 0)
- {
- _nextModifier = 1;
- }
- break;
-
- case SpecialFunction2.ShEq0:
- // See note above.
- if (Shifter.DoOperation(_cpu._l, _cpu._t) == 0)
- {
- _nextModifier = 1;
- }
- break;
-
- case SpecialFunction2.Bus:
- // Select bits 6-15 (bits 0-9 in modern parlance) of the bus
- _nextModifier = (ushort)(_busData & 0x3ff);
- break;
-
- case SpecialFunction2.ALUCY:
- // ALUC0 is the carry produced by the ALU during the most recent microinstruction
- // that loaded L. It is *not* the carry produced during the execution of the microinstruction
- // that contains the ALUCY function.
- _nextModifier = _cpu._aluC0;
- break;
-
- case SpecialFunction2.StoreMD:
- _cpu._system.MemoryBus.LoadMD(_busData);
- break;
-
- case SpecialFunction2.Constant:
- // Ignored here; handled by Constant ROM access logic above.
- break;
-
- default:
- // Let the specific task implementation take a crack at this.
- ExecuteSpecialFunction2((int)instruction.F2);
- break;
- }
-
- //
- // Write back to registers:
- //
-
- // Load T
- if (instruction.LoadT)
- {
- // Does this operation change the source for T?
- bool loadTFromALU = false;
- switch(instruction.ALUF)
- {
- case AluFunction.Bus:
- case AluFunction.BusOrT:
- case AluFunction.BusPlus1:
- case AluFunction.BusMinus1:
- case AluFunction.BusPlusTPlus1:
- case AluFunction.BusPlusSkip:
- case AluFunction.AluBusAndT:
- loadTFromALU = true;
- break;
- }
-
- _cpu._t = loadTFromALU ? aluData : _busData;
- }
-
- // Do writeback to selected R register from shifter output
- if (loadR)
- {
- _cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t);
- }
-
- // Do writeback to selected R register from M
- if (_loadS)
- {
- _cpu._s[_cpu._rb][_rSelect] = _cpu._m;
- }
-
- // Load L (and M) from ALU
- if (instruction.LoadL)
- {
- _cpu._l = aluData;
- _cpu._m = aluData;
-
- // Save ALUC0 for use in the next ALUCY special function.
- _cpu._aluC0 = (ushort)ALU.Carry;
- }
-
- //
- // Select next address, using the address modifier from the last instruction.
- //
- _mpc = (ushort)(instruction.NEXT | nextModifier);
- return nextTask;
- }
-
- protected abstract ushort GetBusSource(int bs);
- protected abstract void ExecuteSpecialFunction1(int f1);
-
- ///
- /// Used to allow Task-specific F2s that need to modify RSELECT to do so.
- ///
- ///
- protected virtual void ExecuteSpecialFunction2Early(int f2)
- {
- // Nothing by default.
- }
-
- protected abstract void ExecuteSpecialFunction2(int f2);
-
- //
- // Per uInstruction Task Data:
- // Modified by both the base Task implementation and any subclasses
- //
- // TODO: maybe instead of these being shared (which feels kinda bad)
- // these could be encapsulated in an object and passed to subclass implementations?
- protected ushort _busData; // Data placed onto the bus (ANDed from multiple sources)
- protected ushort _nextModifier; // Bits ORed onto the NEXT field of the current instruction
- protected uint _rSelect; // RSELECT field from current instruction, potentially modified by task
- protected bool _loadS; // Whether to load S from M at and of cycle
-
-
- //
- // Global Task Data
- //
- protected AltoCPU _cpu;
- protected ushort _mpc;
- protected TaskType _taskType;
- protected bool _wakeup;
-
- // Emulator Task-specific data. This is placed here because it is used by the ALU and it's easier to reference in the
- // base class even if it does break encapsulation. See notes in the EmulatorTask class for meaning.
- protected int _skip;
- }
-
- ///
- /// EmulatorTask provides emulator (NOVA instruction set) specific operations.
- ///
- private class EmulatorTask : Task
- {
- public EmulatorTask(AltoCPU cpu) : base(cpu)
- {
- _taskType = TaskType.Emulator;
-
- // The Wakeup signal is always true for the Emulator task.
- _wakeup = true;
- }
-
- public override void BlockTask()
- {
- throw new InvalidOperationException("The emulator task cannot be blocked.");
- }
-
- public override void WakeupTask()
- {
- throw new InvalidOperationException("The emulator task is always in wakeup state.");
- }
-
- protected override ushort GetBusSource(int bs)
- {
- EmulatorBusSource ebs = (EmulatorBusSource)bs;
-
- switch(ebs)
- {
- case EmulatorBusSource.ReadSLocation:
- return _cpu._s[_cpu._rb][_rSelect];
-
- case EmulatorBusSource.LoadSLocation:
- _loadS = true;
- return 0; // TODO: technically this is an "undefined value" not zero.
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
- }
- }
-
- protected override void ExecuteSpecialFunction1(int f1)
- {
- EmulatorF1 ef1 = (EmulatorF1)f1;
- switch (ef1)
- {
- case EmulatorF1.RSNF:
- // TODO: make configurable
- // "...decoded by the Ethernet interface, which gates the host address wired on the
- // backplane onto BUS[8-15]. BUS[0-7] is not driven and will therefore be -1. If
- // no Ethernet interface is present, BUS will be -1.
- //
- _busData &= (0xff00 | 0x42);
- break;
-
- case EmulatorF1.STARTF:
- // Dispatch function to I/O based on contents of AC0... (TBD: what are these?)
- throw new NotImplementedException();
- break;
-
- case EmulatorF1.SWMODE:
- // nothing! for now.
- break;
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled emulator F1 {0}.", ef1));
- }
- }
-
- protected override void ExecuteSpecialFunction2Early(int f2)
- {
- EmulatorF2 ef2 = (EmulatorF2)f2;
- switch (ef2)
- {
- case EmulatorF2.ACSOURCE:
- // Early: modify R select field:
- // "...it replaces the two-low order bits of the R select field with
- // the complement of the SrcAC field of IR, (IR[1-2] XOR 3), allowing the emulator
- // to address its accumulators (which are assigned to R0-R3)."
- _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x6000) >> 13) ^ 3);
- break;
-
- case EmulatorF2.ACDEST:
- // "...causes (IR[3-4] XOR 3) to be used as the low-order two bits of the RSELECT field.
- // This address the accumulators from the destination field of the instruction. The selected
- // register may be loaded or read."
- _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
- break;
-
- }
- }
-
- protected override void ExecuteSpecialFunction2(int f2)
- {
- EmulatorF2 ef2 = (EmulatorF2)f2;
- switch (ef2)
- {
- case EmulatorF2.LoadIR:
- // based on block diagram, this always comes from the bus
- _cpu._ir = _busData;
-
- // "IR<- also merges bus bits 0, 5, 6 and 7 into NEXT[6-9] which does a first level
- // instruction dispatch."
- // TODO: is this an AND or an OR operation? (how is the "merge" done?)
- // Assuming for now this is an OR operation like everything else that modifies NEXT.
- _nextModifier = (ushort)(((_busData & 0x8000) >> 12) | ((_busData & 0x0700) >> 8));
-
- // "IR<- clears SKIP"
- _skip = 0;
- break;
-
- case EmulatorF2.IDISP:
- // "The IDISP function (F2=15B) does a 16 way dispatch under control of a PROM and a
- // multiplexer. The values are tabulated below:
- // Conditions ORed onto NEXT Comment
- //
- // if IR[0] = 1 3-IR[8-9] complement of SH field of IR
- // elseif IR[1-2] = 0 IR[3-4] JMP, JSR, ISZ, DSZ
- // elseif IR[1-2] = 1 4 LDA
- // elseif IR[1-2] = 2 5 STA
- // elseif IR[4-7] = 0 1
- // elseif IR[4-7] = 1 0
- // elseif IR[4-7] = 6 16B CONVERT
- // elseif IR[4-7] = 16B 6
- // else IR[4-7]
- // NB: as always, Xerox labels bits in the opposite order from modern convention;
- // (bit 0 is the msb...)
- if ((_cpu._ir & 0x8000) != 0)
- {
- _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6));
- }
- else if((_cpu._ir & 0x6000) == 0)
- {
- _nextModifier = (ushort)((_cpu._ir & 0x1800) >> 11);
- }
- else if((_cpu._ir & 0x6000) == 0x4000)
- {
- _nextModifier = 4;
- }
- else if ((_cpu._ir & 0x6000) == 0x6000)
- {
- _nextModifier = 5;
- }
- else if ((_cpu._ir & 0x0f00) == 0)
- {
- _nextModifier = 1;
- }
- else if ((_cpu._ir & 0x0f00) == 0x0100)
- {
- _nextModifier = 0;
- }
- else if ((_cpu._ir & 0x0f00) == 0x0600)
- {
- _nextModifier = 0xe;
- }
- else if ((_cpu._ir & 0x0f00) == 0x0e00)
- {
- _nextModifier = 0x6;
- }
- else
- {
- _nextModifier = (ushort)((_cpu._ir & 0x0f00) >> 8);
- }
- break;
-
- case EmulatorF2.ACSOURCE:
- // Late:
- // "...a dispatch is performed:
- // Conditions ORed onto NEXT Comment
- //
- // if IR[0] = 1 3-IR[8-9] complement of SH field of IR
- // if IR[1-2] = 3 IR[5] the Indirect bit of R
- // if IR[3-7] = 0 2 CYCLE
- // if IR[3-7] = 1 5 RAMTRAP
- // if IR[3-7] = 2 3 NOPAR -- parameterless opcode group
- // if IR[3-7] = 3 6 RAMTRAP
- // if IR[3-7] = 4 7 RAMTRAP
- // if IR[3-7] = 11B 4 JSRII
- // if IR[3-7] = 12B 4 JSRIS
- // if IR[3-7] = 16B 1 CONVERT
- // if IR[3-7] = 37B 17B ROMTRAP -- used by Swat, the debugger
- // else 16B ROMTRAP
- if ((_cpu._ir & 0x8000) != 0)
- {
- _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6));
- }
- else if ((_cpu._ir & 0xc000) == 0xc000)
- {
- _nextModifier = (ushort)((_cpu._ir & 0x400) >> 10);
- }
- else if ((_cpu._ir & 0x1f00) == 0)
- {
- _nextModifier = 2;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0100)
- {
- _nextModifier = 5;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0200)
- {
- _nextModifier = 3;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0300)
- {
- _nextModifier = 6;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0400)
- {
- _nextModifier = 7;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0900)
- {
- _nextModifier = 4;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0a00)
- {
- _nextModifier = 4;
- }
- else if ((_cpu._ir & 0x1f00) == 0x0e00)
- {
- _nextModifier = 1;
- }
- else if ((_cpu._ir & 0x1f00) == 0x1f00)
- {
- _nextModifier = 0xf;
- }
- else
- {
- _nextModifier = 0xe;
- }
- break;
-
- case EmulatorF2.ACDEST:
- // Handled in early handler
- break;
-
- case EmulatorF2.BUSODD:
- // "...merges BUS[15] into NEXT[9]."
- // TODO: is this an AND or an OR?
- _nextModifier |= (ushort)(_busData & 0x1);
- break;
-
- case EmulatorF2.MAGIC:
- Shifter.SetMagic(true);
- break;
-
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled emulator F2 {0}.", ef2));
- }
- }
-
- // From Section 3, Pg. 31:
- // "The emulator has two additional bits of state, the SKIP and CARRY flip flops. CARRY is distinct from the
- // microprocessor’s ALUC0 bit, tested by the ALUCY function. CARRY is set or cleared as a function of IR and
- // many other things(see section 3.1) when the DNS<-(do novel shifts, F2= 12B) function is executed. In
- // particular, if IR[12] is true, CARRY will not change. DNS also addresses R from (3-IR[3 - 4]), causes a store
- // into R unless IR[12] is set, and sets the SKIP flip flop if appropriate(see section 3.1). The emulator
- // microcode increments PC by 1 at the beginning of the next emulated instruction if SKIP is set, using
- // BUS+SKIP(ALUF= 13B). IR_ clears SKIP."
- //
- // NB: _skip is in the encapsulating AltoCPU class to make it easier to reference since the ALU needs to know about it.
- private int _carry;
- }
-
- ///
- /// DiskSectorTask provides implementation for disk-specific special functions
- ///
- private class DiskSectorTask : Task
- {
- public DiskSectorTask(AltoCPU cpu) : base(cpu)
- {
- _taskType = TaskType.DiskSector;
- _wakeup = false;
- }
-
- protected override ushort GetBusSource(int bs)
- {
- DiskBusSource dbs = (DiskBusSource)bs;
-
- switch (dbs)
- {
- case DiskBusSource.ReadKSTAT:
- return _cpu._system.DiskController.KSTAT;
-
- case DiskBusSource.ReadKDATA:
- return _cpu._system.DiskController.KDATA;
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
- }
- }
-
- protected override void ExecuteSpecialFunction1(int f1)
- {
- DiskF1 df1 = (DiskF1)f1;
-
- switch(df1)
- {
- case DiskF1.LoadKDATA:
- // "The KDATA register is loaded from BUS[0-15]."
- _cpu._system.DiskController.KDATA = _busData;
- break;
-
- case DiskF1.LoadKADR:
- // "This causes the KADR register to be loaded from BUS[8-14].
- // in addition, it causes the head address bit to be loaded from KDATA[13]."
- // TODO: do the latter (likely inside the controller)
- _cpu._system.DiskController.KADR = (ushort)((_busData & 0xfe) >> 1);
- break;
-
- case DiskF1.LoadKCOMM:
- _cpu._system.DiskController.KCOM = (ushort)((_busData & 0x7c00) >> 10);
- break;
-
- case DiskF1.CLRSTAT:
- _cpu._system.DiskController.ClearStatus();
- break;
-
- case DiskF1.INCRECNO:
- _cpu._system.DiskController.IncrementRecord();
- break;
-
- case DiskF1.LoadKSTAT:
- // "KSTAT[12-15] are loaded from BUS[12-15]. (Actually BUS[13] is ORed onto
- // KSTAT[13].)"
-
- // OR in BUS[12-15] after masking in KSTAT[13] so it is ORed in properly.
- _cpu._system.DiskController.KSTAT = (ushort)(((_cpu._system.DiskController.KSTAT & 0xfff4)) | (_busData & 0xf));
- break;
-
- case DiskF1.STROBE:
- _cpu._system.DiskController.Strobe();
- break;
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled disk special function 1 {0}", df1));
- }
- }
-
- protected override void ExecuteSpecialFunction2(int f2)
- {
- DiskF2 df2 = (DiskF2)f2;
-
- switch(df2)
- {
- case DiskF2.INIT:
- // "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0
- // TODO: figure out how WDTASKACT and WDINIT work.
- throw new NotImplementedException("INIT not implemented.");
-
- default:
- throw new InvalidOperationException(String.Format("Unhandled disk special function 2 {0}", df2));
- }
- }
- }
-
-
// AltoCPU registers
ushort _t;
ushort _l;
diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs
new file mode 100644
index 0000000..6ae6374
--- /dev/null
+++ b/Contralto/CPU/Tasks/DiskTask.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Contralto.Memory;
+
+namespace Contralto.CPU
+{
+ public partial class AltoCPU
+ {
+ ///
+ /// DiskTask provides implementation for disk-specific special functions
+ /// (for both Disk Sector and Disk Word tasks, since the special functions are
+ /// identical between the two)
+ ///
+ private class DiskTask : Task
+ {
+ public DiskTask(AltoCPU cpu, bool diskSectorTask) : base(cpu)
+ {
+ _taskType = diskSectorTask ? TaskType.DiskSector : TaskType.DiskWord;
+ _wakeup = false;
+ }
+
+ protected override ushort GetBusSource(int bs)
+ {
+ DiskBusSource dbs = (DiskBusSource)bs;
+
+ switch (dbs)
+ {
+ case DiskBusSource.ReadKSTAT:
+ return _cpu._system.DiskController.KSTAT;
+
+ case DiskBusSource.ReadKDATA:
+ return _cpu._system.DiskController.KDATA;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
+ }
+ }
+
+ protected override void ExecuteSpecialFunction1(int f1)
+ {
+ DiskF1 df1 = (DiskF1)f1;
+
+ switch (df1)
+ {
+ case DiskF1.LoadKDATA:
+ // "The KDATA register is loaded from BUS[0-15]."
+ _cpu._system.DiskController.KDATA = _busData;
+ break;
+
+ case DiskF1.LoadKADR:
+ // "This causes the KADR register to be loaded from BUS[8-14].
+ // in addition, it causes the head address bit to be loaded from KDATA[13]."
+ // (the latter is done by DiskController)
+ _cpu._system.DiskController.KADR = (ushort)((_busData & 0xfe) >> 1);
+ break;
+
+ case DiskF1.LoadKCOMM:
+ _cpu._system.DiskController.KCOM = (ushort)((_busData & 0x7c00) >> 10);
+ break;
+
+ case DiskF1.CLRSTAT:
+ _cpu._system.DiskController.ClearStatus();
+ break;
+
+ case DiskF1.INCRECNO:
+ _cpu._system.DiskController.IncrementRecord();
+ break;
+
+ case DiskF1.LoadKSTAT:
+ // "KSTAT[12-15] are loaded from BUS[12-15]. (Actually BUS[13] is ORed onto
+ // KSTAT[13].)"
+
+ // OR in BUS[12-15] after masking in KSTAT[13] so it is ORed in properly.
+ _cpu._system.DiskController.KSTAT = (ushort)(((_cpu._system.DiskController.KSTAT & 0xfff4)) | (_busData & 0xf));
+ break;
+
+ case DiskF1.STROBE:
+ _cpu._system.DiskController.Strobe();
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled disk special function 1 {0}", df1));
+ }
+ }
+
+ protected override void ExecuteSpecialFunction2(int f2)
+ {
+ DiskF2 df2 = (DiskF2)f2;
+
+ switch (df2)
+ {
+ case DiskF2.INIT:
+ // "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0
+ // TODO: figure out how WDTASKACT and WDINIT work.
+ throw new NotImplementedException("INIT not implemented.");
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled disk special function 2 {0}", df2));
+ }
+ }
+ }
+
+ }
+}
diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs
new file mode 100644
index 0000000..a05377c
--- /dev/null
+++ b/Contralto/CPU/Tasks/EmulatorTask.cs
@@ -0,0 +1,278 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Contralto.Memory;
+
+namespace Contralto.CPU
+{
+ public partial class AltoCPU
+ {
+ ///
+ /// EmulatorTask provides emulator (NOVA instruction set) specific operations.
+ ///
+ private class EmulatorTask : Task
+ {
+ public EmulatorTask(AltoCPU cpu) : base(cpu)
+ {
+ _taskType = TaskType.Emulator;
+
+ // The Wakeup signal is always true for the Emulator task.
+ _wakeup = true;
+ }
+
+ public override void BlockTask()
+ {
+ throw new InvalidOperationException("The emulator task cannot be blocked.");
+ }
+
+ public override void WakeupTask()
+ {
+ throw new InvalidOperationException("The emulator task is always in wakeup state.");
+ }
+
+ protected override ushort GetBusSource(int bs)
+ {
+ EmulatorBusSource ebs = (EmulatorBusSource)bs;
+
+ switch (ebs)
+ {
+ case EmulatorBusSource.ReadSLocation:
+ return _cpu._s[_cpu._rb][_rSelect];
+
+ case EmulatorBusSource.LoadSLocation:
+ _loadS = true;
+ return 0; // TODO: technically this is an "undefined value," not zero.
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
+ }
+ }
+
+ protected override void ExecuteSpecialFunction1(int f1)
+ {
+ EmulatorF1 ef1 = (EmulatorF1)f1;
+ switch (ef1)
+ {
+ case EmulatorF1.RSNF:
+ // TODO: make configurable
+ // "...decoded by the Ethernet interface, which gates the host address wired on the
+ // backplane onto BUS[8-15]. BUS[0-7] is not driven and will therefore be -1. If
+ // no Ethernet interface is present, BUS will be -1.
+ //
+ _busData &= (0xff00 | 0x42);
+ break;
+
+ case EmulatorF1.STARTF:
+ // Dispatch function to I/O based on contents of AC0... (TBD: what are these?)
+ throw new NotImplementedException();
+ break;
+
+ case EmulatorF1.SWMODE:
+ // nothing! for now.
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled emulator F1 {0}.", ef1));
+ }
+ }
+
+ protected override void ExecuteSpecialFunction2Early(int f2)
+ {
+ EmulatorF2 ef2 = (EmulatorF2)f2;
+ switch (ef2)
+ {
+ case EmulatorF2.ACSOURCE:
+ // Early: modify R select field:
+ // "...it replaces the two-low order bits of the R select field with
+ // the complement of the SrcAC field of IR, (IR[1-2] XOR 3), allowing the emulator
+ // to address its accumulators (which are assigned to R0-R3)."
+ _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x6000) >> 13) ^ 3);
+ break;
+
+ case EmulatorF2.ACDEST:
+ // "...causes (IR[3-4] XOR 3) to be used as the low-order two bits of the RSELECT field.
+ // This address the accumulators from the destination field of the instruction. The selected
+ // register may be loaded or read."
+ _rSelect = (_rSelect & 0xfffc) | ((((uint)_cpu._ir & 0x1800) >> 11) ^ 3);
+ break;
+
+ }
+ }
+
+ protected override void ExecuteSpecialFunction2(int f2)
+ {
+ EmulatorF2 ef2 = (EmulatorF2)f2;
+ switch (ef2)
+ {
+ case EmulatorF2.LoadIR:
+ // based on block diagram, this always comes from the bus
+ _cpu._ir = _busData;
+
+ // "IR<- also merges bus bits 0, 5, 6 and 7 into NEXT[6-9] which does a first level
+ // instruction dispatch."
+ // TODO: is this an AND or an OR operation? (how is the "merge" done?)
+ // Assuming for now this is an OR operation like everything else that modifies NEXT.
+ _nextModifier = (ushort)(((_busData & 0x8000) >> 12) | ((_busData & 0x0700) >> 8));
+
+ // "IR<- clears SKIP"
+ _skip = 0;
+ break;
+
+ case EmulatorF2.IDISP:
+ // "The IDISP function (F2=15B) does a 16 way dispatch under control of a PROM and a
+ // multiplexer. The values are tabulated below:
+ // Conditions ORed onto NEXT Comment
+ //
+ // if IR[0] = 1 3-IR[8-9] complement of SH field of IR
+ // elseif IR[1-2] = 0 IR[3-4] JMP, JSR, ISZ, DSZ
+ // elseif IR[1-2] = 1 4 LDA
+ // elseif IR[1-2] = 2 5 STA
+ // elseif IR[4-7] = 0 1
+ // elseif IR[4-7] = 1 0
+ // elseif IR[4-7] = 6 16B CONVERT
+ // elseif IR[4-7] = 16B 6
+ // else IR[4-7]
+ // NB: as always, Xerox labels bits in the opposite order from modern convention;
+ // (bit 0 is the msb...)
+ if ((_cpu._ir & 0x8000) != 0)
+ {
+ _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6));
+ }
+ else if ((_cpu._ir & 0x6000) == 0)
+ {
+ _nextModifier = (ushort)((_cpu._ir & 0x1800) >> 11);
+ }
+ else if ((_cpu._ir & 0x6000) == 0x4000)
+ {
+ _nextModifier = 4;
+ }
+ else if ((_cpu._ir & 0x6000) == 0x6000)
+ {
+ _nextModifier = 5;
+ }
+ else if ((_cpu._ir & 0x0f00) == 0)
+ {
+ _nextModifier = 1;
+ }
+ else if ((_cpu._ir & 0x0f00) == 0x0100)
+ {
+ _nextModifier = 0;
+ }
+ else if ((_cpu._ir & 0x0f00) == 0x0600)
+ {
+ _nextModifier = 0xe;
+ }
+ else if ((_cpu._ir & 0x0f00) == 0x0e00)
+ {
+ _nextModifier = 0x6;
+ }
+ else
+ {
+ _nextModifier = (ushort)((_cpu._ir & 0x0f00) >> 8);
+ }
+ break;
+
+ case EmulatorF2.ACSOURCE:
+ // Late:
+ // "...a dispatch is performed:
+ // Conditions ORed onto NEXT Comment
+ //
+ // if IR[0] = 1 3-IR[8-9] complement of SH field of IR
+ // if IR[1-2] = 3 IR[5] the Indirect bit of R
+ // if IR[3-7] = 0 2 CYCLE
+ // if IR[3-7] = 1 5 RAMTRAP
+ // if IR[3-7] = 2 3 NOPAR -- parameterless opcode group
+ // if IR[3-7] = 3 6 RAMTRAP
+ // if IR[3-7] = 4 7 RAMTRAP
+ // if IR[3-7] = 11B 4 JSRII
+ // if IR[3-7] = 12B 4 JSRIS
+ // if IR[3-7] = 16B 1 CONVERT
+ // if IR[3-7] = 37B 17B ROMTRAP -- used by Swat, the debugger
+ // else 16B ROMTRAP
+ if ((_cpu._ir & 0x8000) != 0)
+ {
+ _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6));
+ }
+ else if ((_cpu._ir & 0xc000) == 0xc000)
+ {
+ _nextModifier = (ushort)((_cpu._ir & 0x400) >> 10);
+ }
+ else if ((_cpu._ir & 0x1f00) == 0)
+ {
+ _nextModifier = 2;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0100)
+ {
+ _nextModifier = 5;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0200)
+ {
+ _nextModifier = 3;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0300)
+ {
+ _nextModifier = 6;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0400)
+ {
+ _nextModifier = 7;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0900)
+ {
+ _nextModifier = 4;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0a00)
+ {
+ _nextModifier = 4;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x0e00)
+ {
+ _nextModifier = 1;
+ }
+ else if ((_cpu._ir & 0x1f00) == 0x1f00)
+ {
+ _nextModifier = 0xf;
+ }
+ else
+ {
+ _nextModifier = 0xe;
+ }
+ break;
+
+ case EmulatorF2.ACDEST:
+ // Handled in early handler
+ break;
+
+ case EmulatorF2.BUSODD:
+ // "...merges BUS[15] into NEXT[9]."
+ // TODO: is this an AND or an OR?
+ _nextModifier |= (ushort)(_busData & 0x1);
+ break;
+
+ case EmulatorF2.MAGIC:
+ Shifter.SetMagic(true);
+ break;
+
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled emulator F2 {0}.", ef2));
+ }
+ }
+
+ // From Section 3, Pg. 31:
+ // "The emulator has two additional bits of state, the SKIP and CARRY flip flops. CARRY is distinct from the
+ // microprocessor’s ALUC0 bit, tested by the ALUCY function. CARRY is set or cleared as a function of IR and
+ // many other things(see section 3.1) when the DNS<-(do novel shifts, F2= 12B) function is executed. In
+ // particular, if IR[12] is true, CARRY will not change. DNS also addresses R from (3-IR[3 - 4]), causes a store
+ // into R unless IR[12] is set, and sets the SKIP flip flop if appropriate(see section 3.1). The emulator
+ // microcode increments PC by 1 at the beginning of the next emulated instruction if SKIP is set, using
+ // BUS+SKIP(ALUF= 13B). IR_ clears SKIP."
+ //
+ // NB: _skip is in the encapsulating AltoCPU class to make it easier to reference since the ALU needs to know about it.
+ private int _carry;
+ }
+ }
+}
diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs
new file mode 100644
index 0000000..1518d18
--- /dev/null
+++ b/Contralto/CPU/Tasks/Task.cs
@@ -0,0 +1,413 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Contralto.Memory;
+
+namespace Contralto.CPU
+{
+ public partial class AltoCPU
+ {
+ // Task:
+ // Base task class: provides implementation for non-task-specific microcode execution and
+ // state. Task subclasses implement and execute Task-specific behavior and are called into
+ // by the base class as necessary.
+ public abstract class Task
+ {
+ public Task(AltoCPU cpu)
+ {
+ _wakeup = false;
+ _mpc = 0xffff; // invalid, for sanity checking
+ _taskType = TaskType.Invalid;
+ _cpu = cpu;
+ }
+
+ public int Priority
+ {
+ get { return (int)_taskType; }
+ }
+
+ public bool Wakeup
+ {
+ get { return _wakeup; }
+ }
+
+ public ushort MPC
+ {
+ get { return _mpc; }
+ }
+
+ public virtual void Reset()
+ {
+ // From The Alto Hardware Manual (section 2, "Initialization"):
+ // "...each task start[s] at the location which is its task number"
+ //
+ _mpc = (ushort)_taskType;
+ }
+
+ public virtual void BlockTask()
+ {
+ _wakeup = false;
+ }
+
+ public virtual void WakeupTask()
+ {
+ _wakeup = true;
+ }
+
+ public bool ExecuteNext()
+ {
+ // TODO: cache microinstructions (or pre-decode them) to save consing all these up every time.
+ MicroInstruction instruction = new MicroInstruction(UCodeMemory.UCodeROM[_mpc]);
+ return ExecuteInstruction(instruction);
+ }
+
+ ///
+ /// ExecuteInstruction causes the Task to execute the next instruction (the one
+ /// _mpc is pointing to). The base implementation covers non-task specific logic; subclasses may
+ /// provide their own overrides.
+ ///
+ /// True if a task switch has been requested by a TASK instruction, false otherwise.
+ protected virtual bool ExecuteInstruction(MicroInstruction instruction)
+ {
+ bool nextTask = false;
+ bool loadR = false;
+ ushort aluData = 0;
+ ushort nextModifier = 0;
+ _loadS = false;
+ _rSelect = 0;
+ _busData = 0;
+
+
+ Shifter.SetMagic(false);
+
+ //
+ // Wait for memory state machine if a memory operation is requested by this instruction and
+ // the memory isn't ready yet.
+ // TODO: this needs to be seriously cleaned up.
+ //
+ if (instruction.BS == BusSource.ReadMD ||
+ instruction.F1 == SpecialFunction1.LoadMAR ||
+ instruction.F2 == SpecialFunction2.StoreMD)
+ {
+
+ MemoryOperation op;
+
+ if (instruction.BS == BusSource.ReadMD)
+ {
+ op = MemoryOperation.Read;
+ }
+ else if (instruction.F1 == SpecialFunction1.LoadMAR)
+ {
+ op = MemoryOperation.LoadAddress;
+ }
+ else
+ {
+ op = MemoryOperation.Store;
+ }
+
+ if (!_cpu._system.MemoryBus.Ready(op))
+ {
+ // Suspend operation for this cycle.
+ return false;
+ }
+ }
+
+ // If we have a modified next field from the last instruction, make sure it gets applied to this one.
+ nextModifier = _nextModifier;
+ _nextModifier = 0;
+
+ _rSelect = instruction.RSELECT;
+
+ // Give tasks the chance to modify parameters early on (like RSELECT)
+ ExecuteSpecialFunction2Early((int)instruction.F2);
+
+ // Select BUS data.
+ if (instruction.F1 != SpecialFunction1.Constant &&
+ instruction.F2 != SpecialFunction2.Constant)
+ {
+ // Normal BUS data (not constant ROM access).
+ switch (instruction.BS)
+ {
+ case BusSource.ReadR:
+ _busData = _cpu._r[_rSelect];
+ break;
+
+ case BusSource.LoadR:
+ _busData = 0; // "Loading R forces the BUS to 0 so that an ALU function of 0 and T may be executed simultaneously"
+ loadR = true;
+ break;
+
+ case BusSource.None:
+ _busData = 0xffff; // "Enables no source to the BUS, leaving it all ones"
+ break;
+
+ case BusSource.TaskSpecific1:
+ case BusSource.TaskSpecific2:
+ _busData = GetBusSource((int)instruction.BS); // task specific -- call into specific implementation
+ break;
+
+ case BusSource.ReadMD:
+ _busData = _cpu._system.MemoryBus.ReadMD();
+ break;
+
+ case BusSource.ReadMouse:
+ //throw new NotImplementedException("ReadMouse bus source not implemented.");
+ _busData = 0; // TODO: implement;
+ break;
+
+ case BusSource.ReadDisp:
+ // "The high-order bits of IR cannot be read directly, but the displacement field of IR (8 low order bits),
+ // may be read with the <-DISP bus source. If the X field of the instruction is zero (i.e. it specifies page 0
+ // addressing) then the DISP field of the instruction is put on BUS[8-15] and BUS[0-7] is zeroed. If the X
+ // field of the instruction is nonzero (i.e. it specifies PC-relative or base-register addressing) then the DISP
+ // field is sign-extended and put on the bus."
+ // NB: the "X" field of the NOVA instruction is IR[6-7]
+ _busData = (ushort)(_cpu._ir & 0xff);
+
+ if ((_cpu._ir & 0x300) != 0)
+ {
+ // sign extend if necessary
+ if ((_cpu._ir & 0x80) == 0x80)
+ {
+ _busData |= (0xff00);
+ }
+ }
+ break;
+
+ default:
+ throw new InvalidOperationException(String.Format("Unhandled bus source {0}.", instruction.BS));
+ break;
+ }
+ }
+ else
+ {
+ // See also comments below.
+ _busData = ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
+ }
+
+ // Constant ROM access:
+ // The constant memory is gated to the bus by F1=7, F2=7, or BS>4. The constant memory is addressed by the
+ // (8 bit) concatenation of RSELECT and BS. The intent in enabling constants with BS>4 is to provide a masking
+ // facility, particularly for the <-MOUSE and <-DISP bus sources. This works because the processor bus ANDs if
+ // more than one source is gated to it. Up to 32 such mask contans can be provided for each of the four bus sources
+ // > 4.
+ // NOTE also:
+ // "Note that the [emulator task F2] functions which replace the low bits of RSELECT with IR aaffect only the
+ // selection of R; they do not affect the address supplied to the constant ROM."
+ // Hence we use the unmodified RSELECT value here and above.
+ if ((int)instruction.BS > 4 ||
+ instruction.F1 == SpecialFunction1.Constant ||
+ instruction.F2 == SpecialFunction2.Constant)
+ {
+ _busData &= ConstantMemory.ConstantROM[(instruction.RSELECT << 3) | ((uint)instruction.BS)];
+ }
+
+ // Do ALU operation
+ aluData = ALU.Execute(instruction.ALUF, _busData, _cpu._t, _skip);
+
+ // Reset shifter op
+ Shifter.SetOperation(ShifterOp.None, 0);
+
+ //
+ // Do Special Functions
+ //
+ switch (instruction.F1)
+ {
+ case SpecialFunction1.None:
+ // Do nothing. Well, that was easy.
+ break;
+
+ case SpecialFunction1.LoadMAR:
+ _cpu._system.MemoryBus.LoadMAR(aluData); // Start main memory reference
+ break;
+
+ case SpecialFunction1.Task:
+ nextTask = true; // Yield to other more important tasks
+ break;
+
+ case SpecialFunction1.Block:
+ // Technically this is to be invoked by the hardware device associated with a task.
+ // That logic would be circituous and unless there's a good reason not to that is discovered
+ // later, I'm just going to directly block the current task here.
+ _cpu.BlockTask(this._taskType);
+ break;
+
+ case SpecialFunction1.LLSH1:
+ Shifter.SetOperation(ShifterOp.ShiftLeft, 1);
+ break;
+
+ case SpecialFunction1.LRSH1:
+ Shifter.SetOperation(ShifterOp.ShiftRight, 1);
+ break;
+
+ case SpecialFunction1.LLCY8:
+ Shifter.SetOperation(ShifterOp.RotateLeft, 8);
+ break;
+
+ case SpecialFunction1.Constant:
+ // Ignored here; handled by Constant ROM access logic above.
+ break;
+
+ default:
+ // Let the specific task implementation take a crack at this.
+ ExecuteSpecialFunction1((int)instruction.F1);
+ break;
+ }
+
+ switch (instruction.F2)
+ {
+ case SpecialFunction2.None:
+ // Nothing!
+ break;
+
+ case SpecialFunction2.BusEq0:
+ if (_busData == 0)
+ {
+ _nextModifier = 1;
+ }
+ break;
+
+ case SpecialFunction2.ShLt0:
+ //
+ // Note:
+ // "the value of SHIFTER OUTPUT is determined by the value of L as the microinstruction
+ // *begins* execution and the shifter function specified during the *current* microinstruction.
+ //
+ // Since we haven't modifed L yet, and we've selected the shifter function above, we're good to go here.
+ //
+ if ((short)Shifter.DoOperation(_cpu._l, _cpu._t) < 0)
+ {
+ _nextModifier = 1;
+ }
+ break;
+
+ case SpecialFunction2.ShEq0:
+ // See note above.
+ if (Shifter.DoOperation(_cpu._l, _cpu._t) == 0)
+ {
+ _nextModifier = 1;
+ }
+ break;
+
+ case SpecialFunction2.Bus:
+ // Select bits 6-15 (bits 0-9 in modern parlance) of the bus
+ _nextModifier = (ushort)(_busData & 0x3ff);
+ break;
+
+ case SpecialFunction2.ALUCY:
+ // ALUC0 is the carry produced by the ALU during the most recent microinstruction
+ // that loaded L. It is *not* the carry produced during the execution of the microinstruction
+ // that contains the ALUCY function.
+ _nextModifier = _cpu._aluC0;
+ break;
+
+ case SpecialFunction2.StoreMD:
+ _cpu._system.MemoryBus.LoadMD(_busData);
+ break;
+
+ case SpecialFunction2.Constant:
+ // Ignored here; handled by Constant ROM access logic above.
+ break;
+
+ default:
+ // Let the specific task implementation take a crack at this.
+ ExecuteSpecialFunction2((int)instruction.F2);
+ break;
+ }
+
+ //
+ // Write back to registers:
+ //
+ // Do writeback to selected R register from shifter output
+ if (loadR)
+ {
+ _cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t);
+ }
+
+ // Do writeback to selected R register from M
+ if (_loadS)
+ {
+ _cpu._s[_cpu._rb][_rSelect] = _cpu._m;
+ }
+
+ // Load T
+ if (instruction.LoadT)
+ {
+ // Does this operation change the source for T?
+ bool loadTFromALU = false;
+ switch (instruction.ALUF)
+ {
+ case AluFunction.Bus:
+ case AluFunction.BusOrT:
+ case AluFunction.BusPlus1:
+ case AluFunction.BusMinus1:
+ case AluFunction.BusPlusTPlus1:
+ case AluFunction.BusPlusSkip:
+ case AluFunction.AluBusAndT:
+ loadTFromALU = true;
+ break;
+ }
+
+ _cpu._t = loadTFromALU ? aluData : _busData;
+ }
+
+ // Load L (and M) from ALU outputs.
+ if (instruction.LoadL)
+ {
+ _cpu._l = aluData;
+ _cpu._m = aluData;
+
+ // Save ALUC0 for use in the next ALUCY special function.
+ _cpu._aluC0 = (ushort)ALU.Carry;
+ }
+
+ //
+ // Select next address, using the address modifier from the last instruction.
+ //
+ _mpc = (ushort)(instruction.NEXT | nextModifier);
+ return nextTask;
+ }
+
+ protected abstract ushort GetBusSource(int bs);
+ protected abstract void ExecuteSpecialFunction1(int f1);
+
+ ///
+ /// Used to allow Task-specific F2s that need to modify RSELECT to do so.
+ ///
+ ///
+ protected virtual void ExecuteSpecialFunction2Early(int f2)
+ {
+ // Nothing by default.
+ }
+
+ protected abstract void ExecuteSpecialFunction2(int f2);
+
+ //
+ // Per uInstruction Task Data:
+ // Modified by both the base Task implementation and any subclasses
+ //
+ // TODO: maybe instead of these being shared (which feels kinda bad)
+ // these could be encapsulated in an object and passed to subclass implementations?
+ protected ushort _busData; // Data placed onto the bus (ANDed from multiple sources)
+ protected ushort _nextModifier; // Bits ORed onto the NEXT field of the current instruction
+ protected uint _rSelect; // RSELECT field from current instruction, potentially modified by task
+ protected bool _loadS; // Whether to load S from M at and of cycle
+
+
+ //
+ // Global Task Data
+ //
+ protected AltoCPU _cpu;
+ protected ushort _mpc;
+ protected TaskType _taskType;
+ protected bool _wakeup;
+
+ // Emulator Task-specific data. This is placed here because it is used by the ALU and it's easier to reference in the
+ // base class even if it does break encapsulation. See notes in the EmulatorTask class for meaning.
+ protected int _skip;
+ }
+ }
+}
diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj
index 229cecc..21ce8e3 100644
--- a/Contralto/Contralto.csproj
+++ b/Contralto/Contralto.csproj
@@ -48,8 +48,11 @@
+
+
+
Form
diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs
index ecc876f..3fb3032 100644
--- a/Contralto/Debugger.Designer.cs
+++ b/Contralto/Debugger.Designer.cs
@@ -28,38 +28,41 @@
///
private void InitializeComponent()
{
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle8 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle9 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle10 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle11 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle12 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle14 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle18 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle19 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle20 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle21 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle22 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle15 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle16 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle17 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle23 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle24 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle25 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle26 = new System.Windows.Forms.DataGridViewCellStyle();
this.Microcode = new System.Windows.Forms.GroupBox();
this._sourceViewer = new System.Windows.Forms.DataGridView();
+ this.Breakpoint = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.T = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.Addr = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.Source = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.groupBox1 = new System.Windows.Forms.GroupBox();
- this.StepButton = new System.Windows.Forms.Button();
- this.button2 = new System.Windows.Forms.Button();
- this.button3 = new System.Windows.Forms.Button();
- this.button4 = new System.Windows.Forms.Button();
this._registerData = new System.Windows.Forms.DataGridView();
this.RegNum = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.R = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.S = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.StepButton = new System.Windows.Forms.Button();
+ this.AutoStep = new System.Windows.Forms.Button();
+ this.RunButton = new System.Windows.Forms.Button();
+ this.StopButton = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this._taskData = new System.Windows.Forms.DataGridView();
this.TaskName = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.TaskState = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.TaskPC = new System.Windows.Forms.DataGridViewTextBoxColumn();
- this.T = new System.Windows.Forms.DataGridViewTextBoxColumn();
- this.Addr = new System.Windows.Forms.DataGridViewTextBoxColumn();
- this.Source = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this._otherRegs = new System.Windows.Forms.DataGridView();
this.Reg = new System.Windows.Forms.DataGridViewTextBoxColumn();
@@ -68,6 +71,14 @@
this._memoryData = new System.Windows.Forms.DataGridView();
this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Data = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.label1 = new System.Windows.Forms.Label();
+ this.ExecutionStateLabel = new System.Windows.Forms.Label();
+ this.JumpToAddress = new System.Windows.Forms.TextBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.groupBox5 = new System.Windows.Forms.GroupBox();
+ this._diskData = new System.Windows.Forms.DataGridView();
+ this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Microcode.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this._sourceViewer)).BeginInit();
this.groupBox1.SuspendLayout();
@@ -78,10 +89,14 @@
((System.ComponentModel.ISupportInitialize)(this._otherRegs)).BeginInit();
this.groupBox4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this._memoryData)).BeginInit();
+ this.groupBox5.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this._diskData)).BeginInit();
this.SuspendLayout();
//
// Microcode
//
+ this.Microcode.Controls.Add(this.label2);
+ this.Microcode.Controls.Add(this.JumpToAddress);
this.Microcode.Controls.Add(this._sourceViewer);
this.Microcode.Location = new System.Drawing.Point(3, 3);
this.Microcode.Name = "Microcode";
@@ -96,11 +111,12 @@
this._sourceViewer.AllowUserToDeleteRows = false;
this._sourceViewer.AllowUserToResizeColumns = false;
this._sourceViewer.AllowUserToResizeRows = false;
- dataGridViewCellStyle14.BackColor = System.Drawing.Color.Silver;
- this._sourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle14;
+ dataGridViewCellStyle1.BackColor = System.Drawing.Color.Silver;
+ this._sourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1;
this._sourceViewer.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleVertical;
this._sourceViewer.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._sourceViewer.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+ this.Breakpoint,
this.T,
this.Addr,
this.Source});
@@ -109,14 +125,14 @@
this._sourceViewer.Name = "_sourceViewer";
this._sourceViewer.ReadOnly = true;
this._sourceViewer.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
- dataGridViewCellStyle18.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle18.BackColor = System.Drawing.SystemColors.Control;
- dataGridViewCellStyle18.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle18.ForeColor = System.Drawing.SystemColors.WindowText;
- dataGridViewCellStyle18.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle18.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle18.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
- this._sourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle18;
+ dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle5.BackColor = System.Drawing.SystemColors.Control;
+ dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle5.ForeColor = System.Drawing.SystemColors.WindowText;
+ dataGridViewCellStyle5.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle5.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+ this._sourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle5;
this._sourceViewer.RowHeadersVisible = false;
this._sourceViewer.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this._sourceViewer.RowTemplate.Height = 18;
@@ -124,9 +140,58 @@
this._sourceViewer.ShowCellErrors = false;
this._sourceViewer.ShowEditingIcon = false;
this._sourceViewer.ShowRowErrors = false;
- this._sourceViewer.Size = new System.Drawing.Size(584, 600);
+ this._sourceViewer.Size = new System.Drawing.Size(584, 571);
this._sourceViewer.TabIndex = 1;
- this._sourceViewer.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellContentClick);
+ this._sourceViewer.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.SourceViewCellClick);
+ //
+ // Breakpoint
+ //
+ this.Breakpoint.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
+ this.Breakpoint.FalseValue = "false";
+ this.Breakpoint.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.Breakpoint.HeaderText = "B";
+ this.Breakpoint.IndeterminateValue = "null";
+ this.Breakpoint.Name = "Breakpoint";
+ this.Breakpoint.ReadOnly = true;
+ this.Breakpoint.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.Breakpoint.TrueValue = "true";
+ this.Breakpoint.Width = 20;
+ //
+ // T
+ //
+ this.T.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
+ dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.T.DefaultCellStyle = dataGridViewCellStyle2;
+ this.T.HeaderText = "T";
+ this.T.Name = "T";
+ this.T.ReadOnly = true;
+ this.T.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.T.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ this.T.Width = 5;
+ //
+ // Addr
+ //
+ this.Addr.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
+ dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Addr.DefaultCellStyle = dataGridViewCellStyle3;
+ this.Addr.HeaderText = "Addr";
+ this.Addr.Name = "Addr";
+ this.Addr.ReadOnly = true;
+ this.Addr.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.Addr.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ this.Addr.Width = 5;
+ //
+ // Source
+ //
+ this.Source.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Source.DefaultCellStyle = dataGridViewCellStyle4;
+ this.Source.HeaderText = "Source Code";
+ this.Source.Name = "Source";
+ this.Source.ReadOnly = true;
+ this.Source.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.Source.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
//
// groupBox1
//
@@ -138,64 +203,27 @@
this.groupBox1.TabStop = false;
this.groupBox1.Text = "General Registers";
//
- // StepButton
- //
- this.StepButton.Location = new System.Drawing.Point(3, 634);
- this.StepButton.Name = "StepButton";
- this.StepButton.Size = new System.Drawing.Size(44, 23);
- this.StepButton.TabIndex = 3;
- this.StepButton.Text = "Step";
- this.StepButton.UseVisualStyleBackColor = true;
- this.StepButton.Click += new System.EventHandler(this.OnStepButtonClicked);
- //
- // button2
- //
- this.button2.Location = new System.Drawing.Point(54, 634);
- this.button2.Name = "button2";
- this.button2.Size = new System.Drawing.Size(47, 23);
- this.button2.TabIndex = 4;
- this.button2.Text = "Auto";
- this.button2.UseVisualStyleBackColor = true;
- //
- // button3
- //
- this.button3.Location = new System.Drawing.Point(108, 634);
- this.button3.Name = "button3";
- this.button3.Size = new System.Drawing.Size(53, 23);
- this.button3.TabIndex = 5;
- this.button3.Text = "Run";
- this.button3.UseVisualStyleBackColor = true;
- //
- // button4
- //
- this.button4.Location = new System.Drawing.Point(168, 634);
- this.button4.Name = "button4";
- this.button4.Size = new System.Drawing.Size(49, 23);
- this.button4.TabIndex = 6;
- this.button4.Text = "Stop";
- this.button4.UseVisualStyleBackColor = true;
- //
// _registerData
//
this._registerData.AllowUserToAddRows = false;
this._registerData.AllowUserToDeleteRows = false;
this._registerData.AllowUserToResizeColumns = false;
this._registerData.AllowUserToResizeRows = false;
- dataGridViewCellStyle19.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._registerData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle19;
+ dataGridViewCellStyle6.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._registerData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle6;
this._registerData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._registerData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.RegNum,
this.R,
this.S});
- dataGridViewCellStyle20.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle20.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle20.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle20.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle20.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle20.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle20.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._registerData.DefaultCellStyle = dataGridViewCellStyle20;
+ dataGridViewCellStyle7.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle7.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle7.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle7.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle7.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle7.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._registerData.DefaultCellStyle = dataGridViewCellStyle7;
this._registerData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._registerData.Location = new System.Drawing.Point(7, 19);
this._registerData.MultiSelect = false;
@@ -242,6 +270,46 @@
this.S.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
this.S.Width = 50;
//
+ // StepButton
+ //
+ this.StepButton.Location = new System.Drawing.Point(0, 954);
+ this.StepButton.Name = "StepButton";
+ this.StepButton.Size = new System.Drawing.Size(44, 23);
+ this.StepButton.TabIndex = 3;
+ this.StepButton.Text = "Step";
+ this.StepButton.UseVisualStyleBackColor = true;
+ this.StepButton.Click += new System.EventHandler(this.OnStepButtonClicked);
+ //
+ // AutoStep
+ //
+ this.AutoStep.Location = new System.Drawing.Point(50, 954);
+ this.AutoStep.Name = "AutoStep";
+ this.AutoStep.Size = new System.Drawing.Size(47, 23);
+ this.AutoStep.TabIndex = 4;
+ this.AutoStep.Text = "Auto";
+ this.AutoStep.UseVisualStyleBackColor = true;
+ this.AutoStep.Click += new System.EventHandler(this.OnAutoStepButtonClicked);
+ //
+ // RunButton
+ //
+ this.RunButton.Location = new System.Drawing.Point(103, 954);
+ this.RunButton.Name = "RunButton";
+ this.RunButton.Size = new System.Drawing.Size(53, 23);
+ this.RunButton.TabIndex = 5;
+ this.RunButton.Text = "Run";
+ this.RunButton.UseVisualStyleBackColor = true;
+ this.RunButton.Click += new System.EventHandler(this.RunButton_Click);
+ //
+ // StopButton
+ //
+ this.StopButton.Location = new System.Drawing.Point(164, 954);
+ this.StopButton.Name = "StopButton";
+ this.StopButton.Size = new System.Drawing.Size(49, 23);
+ this.StopButton.TabIndex = 6;
+ this.StopButton.Text = "Stop";
+ this.StopButton.UseVisualStyleBackColor = true;
+ this.StopButton.Click += new System.EventHandler(this.OnStopButtonClicked);
+ //
// groupBox2
//
this.groupBox2.Controls.Add(this._taskData);
@@ -256,21 +324,21 @@
//
this._taskData.AllowUserToAddRows = false;
this._taskData.AllowUserToDeleteRows = false;
- dataGridViewCellStyle21.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._taskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle21;
+ dataGridViewCellStyle8.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._taskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle8;
this._taskData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._taskData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.TaskName,
this.TaskState,
this.TaskPC});
- dataGridViewCellStyle22.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle22.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle22.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle22.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle22.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle22.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle22.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._taskData.DefaultCellStyle = dataGridViewCellStyle22;
+ dataGridViewCellStyle9.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle9.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle9.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle9.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle9.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle9.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._taskData.DefaultCellStyle = dataGridViewCellStyle9;
this._taskData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._taskData.Location = new System.Drawing.Point(7, 19);
this._taskData.MultiSelect = false;
@@ -312,42 +380,6 @@
this.TaskPC.Name = "TaskPC";
this.TaskPC.ReadOnly = true;
//
- // T
- //
- this.T.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle15.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle15.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this.T.DefaultCellStyle = dataGridViewCellStyle15;
- this.T.HeaderText = "T";
- this.T.Name = "T";
- this.T.ReadOnly = true;
- this.T.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.T.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- this.T.Width = 5;
- //
- // Addr
- //
- this.Addr.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle16.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.Addr.DefaultCellStyle = dataGridViewCellStyle16;
- this.Addr.HeaderText = "Addr";
- this.Addr.Name = "Addr";
- this.Addr.ReadOnly = true;
- this.Addr.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.Addr.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- this.Addr.Width = 5;
- //
- // Source
- //
- this.Source.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
- dataGridViewCellStyle17.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.Source.DefaultCellStyle = dataGridViewCellStyle17;
- this.Source.HeaderText = "Source Code";
- this.Source.Name = "Source";
- this.Source.ReadOnly = true;
- this.Source.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.Source.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- //
// groupBox3
//
this.groupBox3.Controls.Add(this._otherRegs);
@@ -362,20 +394,20 @@
//
this._otherRegs.AllowUserToAddRows = false;
this._otherRegs.AllowUserToDeleteRows = false;
- dataGridViewCellStyle23.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._otherRegs.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle23;
+ dataGridViewCellStyle10.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._otherRegs.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle10;
this._otherRegs.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._otherRegs.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Reg,
this.RegValue});
- dataGridViewCellStyle24.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle24.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle24.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle24.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle24.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle24.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle24.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._otherRegs.DefaultCellStyle = dataGridViewCellStyle24;
+ dataGridViewCellStyle11.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle11.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle11.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle11.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle11.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle11.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle11.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._otherRegs.DefaultCellStyle = dataGridViewCellStyle11;
this._otherRegs.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._otherRegs.Location = new System.Drawing.Point(7, 19);
this._otherRegs.MultiSelect = false;
@@ -416,9 +448,9 @@
// groupBox4
//
this.groupBox4.Controls.Add(this._memoryData);
- this.groupBox4.Location = new System.Drawing.Point(223, 634);
+ this.groupBox4.Location = new System.Drawing.Point(319, 634);
this.groupBox4.Name = "groupBox4";
- this.groupBox4.Size = new System.Drawing.Size(240, 344);
+ this.groupBox4.Size = new System.Drawing.Size(144, 344);
this.groupBox4.TabIndex = 8;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Memory";
@@ -427,22 +459,22 @@
//
this._memoryData.AllowUserToAddRows = false;
this._memoryData.AllowUserToDeleteRows = false;
- dataGridViewCellStyle25.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle25;
+ dataGridViewCellStyle12.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle12;
this._memoryData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._memoryData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Address,
this.Data});
- dataGridViewCellStyle26.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle26.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle26.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle26.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle26.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle26.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle26.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._memoryData.DefaultCellStyle = dataGridViewCellStyle26;
+ dataGridViewCellStyle13.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle13.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle13.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle13.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle13.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle13.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle13.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._memoryData.DefaultCellStyle = dataGridViewCellStyle13;
this._memoryData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
- this._memoryData.Location = new System.Drawing.Point(7, 19);
+ this._memoryData.Location = new System.Drawing.Point(6, 19);
this._memoryData.MultiSelect = false;
this._memoryData.Name = "_memoryData";
this._memoryData.ReadOnly = true;
@@ -454,7 +486,7 @@
this._memoryData.ShowCellToolTips = false;
this._memoryData.ShowEditingIcon = false;
this._memoryData.ShowRowErrors = false;
- this._memoryData.Size = new System.Drawing.Size(227, 319);
+ this._memoryData.Size = new System.Drawing.Size(132, 319);
this._memoryData.TabIndex = 0;
//
// Address
@@ -474,17 +506,116 @@
this.Data.Name = "Data";
this.Data.ReadOnly = true;
//
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(0, 935);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(85, 13);
+ this.label1.TabIndex = 9;
+ this.label1.Text = "Execution State:";
+ //
+ // ExecutionStateLabel
+ //
+ this.ExecutionStateLabel.AutoSize = true;
+ this.ExecutionStateLabel.Location = new System.Drawing.Point(92, 935);
+ this.ExecutionStateLabel.Name = "ExecutionStateLabel";
+ this.ExecutionStateLabel.Size = new System.Drawing.Size(33, 13);
+ this.ExecutionStateLabel.TabIndex = 10;
+ this.ExecutionStateLabel.Text = "unset";
+ //
+ // JumpToAddress
+ //
+ this.JumpToAddress.Location = new System.Drawing.Point(59, 596);
+ this.JumpToAddress.Name = "JumpToAddress";
+ this.JumpToAddress.Size = new System.Drawing.Size(48, 20);
+ this.JumpToAddress.TabIndex = 12;
+ this.JumpToAddress.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnJumpAddressKeyDown);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(11, 599);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(47, 13);
+ this.label2.TabIndex = 13;
+ this.label2.Text = "Jump to:";
+ //
+ // groupBox5
+ //
+ this.groupBox5.Controls.Add(this._diskData);
+ this.groupBox5.Location = new System.Drawing.Point(3, 634);
+ this.groupBox5.Name = "groupBox5";
+ this.groupBox5.Size = new System.Drawing.Size(163, 298);
+ this.groupBox5.TabIndex = 11;
+ this.groupBox5.TabStop = false;
+ this.groupBox5.Text = "Disk";
+ //
+ // _diskData
+ //
+ this._diskData.AllowUserToAddRows = false;
+ this._diskData.AllowUserToDeleteRows = false;
+ dataGridViewCellStyle14.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._diskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle14;
+ this._diskData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ this._diskData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+ this.dataGridViewTextBoxColumn1,
+ this.dataGridViewTextBoxColumn2});
+ dataGridViewCellStyle15.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle15.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle15.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle15.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle15.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle15.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle15.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._diskData.DefaultCellStyle = dataGridViewCellStyle15;
+ this._diskData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
+ this._diskData.Location = new System.Drawing.Point(6, 19);
+ this._diskData.MultiSelect = false;
+ this._diskData.Name = "_diskData";
+ this._diskData.ReadOnly = true;
+ this._diskData.RowHeadersVisible = false;
+ this._diskData.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this._diskData.RowTemplate.Height = 18;
+ this._diskData.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
+ this._diskData.ShowCellErrors = false;
+ this._diskData.ShowCellToolTips = false;
+ this._diskData.ShowEditingIcon = false;
+ this._diskData.ShowRowErrors = false;
+ this._diskData.Size = new System.Drawing.Size(147, 273);
+ this._diskData.TabIndex = 1;
+ //
+ // dataGridViewTextBoxColumn1
+ //
+ this.dataGridViewTextBoxColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
+ this.dataGridViewTextBoxColumn1.HeaderText = "Data";
+ this.dataGridViewTextBoxColumn1.MinimumWidth = 16;
+ this.dataGridViewTextBoxColumn1.Name = "dataGridViewTextBoxColumn1";
+ this.dataGridViewTextBoxColumn1.ReadOnly = true;
+ this.dataGridViewTextBoxColumn1.Width = 55;
+ //
+ // dataGridViewTextBoxColumn2
+ //
+ this.dataGridViewTextBoxColumn2.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ this.dataGridViewTextBoxColumn2.HeaderText = "Value";
+ this.dataGridViewTextBoxColumn2.MinimumWidth = 16;
+ this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2";
+ this.dataGridViewTextBoxColumn2.ReadOnly = true;
+ //
// Debugger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(753, 997);
+ this.Controls.Add(this.groupBox5);
+ this.Controls.Add(this.ExecutionStateLabel);
+ this.Controls.Add(this.label1);
this.Controls.Add(this.groupBox4);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
- this.Controls.Add(this.button4);
- this.Controls.Add(this.button3);
- this.Controls.Add(this.button2);
+ this.Controls.Add(this.StopButton);
+ this.Controls.Add(this.RunButton);
+ this.Controls.Add(this.AutoStep);
this.Controls.Add(this.StepButton);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.Microcode);
@@ -492,6 +623,7 @@
this.Text = "Debugger";
this.Load += new System.EventHandler(this.Debugger_Load);
this.Microcode.ResumeLayout(false);
+ this.Microcode.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this._sourceViewer)).EndInit();
this.groupBox1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this._registerData)).EndInit();
@@ -501,7 +633,10 @@
((System.ComponentModel.ISupportInitialize)(this._otherRegs)).EndInit();
this.groupBox4.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this._memoryData)).EndInit();
+ this.groupBox5.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this._diskData)).EndInit();
this.ResumeLayout(false);
+ this.PerformLayout();
}
@@ -511,9 +646,9 @@
private System.Windows.Forms.DataGridView _sourceViewer;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button StepButton;
- private System.Windows.Forms.Button button2;
- private System.Windows.Forms.Button button3;
- private System.Windows.Forms.Button button4;
+ private System.Windows.Forms.Button AutoStep;
+ private System.Windows.Forms.Button RunButton;
+ private System.Windows.Forms.Button StopButton;
private System.Windows.Forms.DataGridView _registerData;
private System.Windows.Forms.DataGridViewTextBoxColumn RegNum;
private System.Windows.Forms.DataGridViewTextBoxColumn R;
@@ -523,9 +658,6 @@
private System.Windows.Forms.DataGridViewTextBoxColumn TaskName;
private System.Windows.Forms.DataGridViewTextBoxColumn TaskState;
private System.Windows.Forms.DataGridViewTextBoxColumn TaskPC;
- private System.Windows.Forms.DataGridViewTextBoxColumn T;
- private System.Windows.Forms.DataGridViewTextBoxColumn Addr;
- private System.Windows.Forms.DataGridViewTextBoxColumn Source;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.DataGridView _otherRegs;
private System.Windows.Forms.DataGridViewTextBoxColumn Reg;
@@ -534,5 +666,17 @@
private System.Windows.Forms.DataGridView _memoryData;
private System.Windows.Forms.DataGridViewTextBoxColumn Address;
private System.Windows.Forms.DataGridViewTextBoxColumn Data;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn Breakpoint;
+ private System.Windows.Forms.DataGridViewTextBoxColumn T;
+ private System.Windows.Forms.DataGridViewTextBoxColumn Addr;
+ private System.Windows.Forms.DataGridViewTextBoxColumn Source;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label ExecutionStateLabel;
+ private System.Windows.Forms.TextBox JumpToAddress;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.GroupBox groupBox5;
+ private System.Windows.Forms.DataGridView _diskData;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2;
}
}
\ No newline at end of file
diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs
index 3a38860..aebbfcc 100644
--- a/Contralto/Debugger.cs
+++ b/Contralto/Debugger.cs
@@ -9,6 +9,7 @@ using System.Text;
using System.Windows.Forms;
using Contralto.CPU;
+using System.Threading;
namespace Contralto
{
@@ -17,6 +18,7 @@ namespace Contralto
public Debugger(AltoSystem system)
{
_system = system;
+ _breakpointEnabled = new bool[1024];
InitializeComponent();
InitControls();
@@ -39,6 +41,7 @@ namespace Contralto
SourceLine src = new SourceLine(line);
int i = _sourceViewer.Rows.Add(
+ false, // breakpoint
GetTextForTask(src.Task),
src.Address,
src.Text);
@@ -80,7 +83,7 @@ namespace Contralto
_taskData.Rows[i].Cells[0].Value = GetTextForTask((TaskType)i);
_taskData.Rows[i].Cells[1].Value = GetTextForTaskState(_system.CPU.Tasks[i]);
_taskData.Rows[i].Cells[2].Value =
- _system.CPU.Tasks[i] != null ? OctalHelpers.ToOctal(_system.CPU.Tasks[i].MPC, 4) : String.Empty;
+ _system.CPU.Tasks[i] != null ? OctalHelpers.ToOctal(_system.CPU.Tasks[i].MPC, 4) : String.Empty;
}
// Other registers
@@ -93,17 +96,48 @@ namespace Contralto
_otherRegs.Rows[6].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MD, 6);
_otherRegs.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.Cycle, 2);
- // Find the right source line
- foreach(DataGridViewRow row in _sourceViewer.Rows)
+ // Disk info
+ _diskData.Rows[0].Cells[1].Value = _system.DiskController.ClocksUntilNextSector.ToString("0.00");
+ _diskData.Rows[1].Cells[1].Value = _system.DiskController.Cylinder.ToString();
+ _diskData.Rows[2].Cells[1].Value = _system.DiskController.SeekCylinder.ToString();
+ _diskData.Rows[3].Cells[1].Value = _system.DiskController.Head.ToString();
+ _diskData.Rows[4].Cells[1].Value = _system.DiskController.Sector.ToString();
+ _diskData.Rows[5].Cells[1].Value = OctalHelpers.ToOctal(_system.DiskController.KDATA, 6);
+ _diskData.Rows[6].Cells[1].Value = OctalHelpers.ToOctal(_system.DiskController.KADR, 6);
+ _diskData.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.DiskController.KCOM, 6);
+ _diskData.Rows[8].Cells[1].Value = OctalHelpers.ToOctal(_system.DiskController.KSTAT, 6);
+ _diskData.Rows[9].Cells[1].Value = _system.DiskController.RECNO.ToString();
+
+ for (ushort i = 0; i < 1024; i++)
{
- if (row.Tag != null &&
- (ushort)(row.Tag) == _system.CPU.CurrentTask.MPC)
- {
- _sourceViewer.ClearSelection();
- row.Selected = true;
- _sourceViewer.CurrentCell = row.Cells[0];
+ _memoryData.Rows[i].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6);
+ }
+
+ // Find the right source line
+ HighlightSourceLine(_system.CPU.CurrentTask.MPC);
+
+ // Exec state
+ switch(_execState)
+ {
+ case ExecutionState.Stopped:
+ ExecutionStateLabel.Text = "Stopped";
+ break;
+
+ case ExecutionState.SingleStep:
+ ExecutionStateLabel.Text = "Stepping";
+ break;
+
+ case ExecutionState.AutoStep:
+ ExecutionStateLabel.Text = "Stepping (auto)";
+ break;
+
+ case ExecutionState.Running:
+ ExecutionStateLabel.Text = "Running";
+ break;
+
+ case ExecutionState.BreakpointStop:
+ ExecutionStateLabel.Text = "Stopped (bkpt)";
break;
- }
}
}
@@ -119,11 +153,11 @@ namespace Contralto
_taskData.Rows.Add("0", "0", "0");
}
- /*
- for (int i=0;i<65536;i++)
+
+ for (ushort i=0;i<1024;i++)
{
- _memoryData.Rows.Add();
- } */
+ _memoryData.Rows.Add(OctalHelpers.ToOctal(i, 6), OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6));
+ }
_otherRegs.Rows.Add("L", "0");
_otherRegs.Rows.Add("T", "0");
@@ -133,11 +167,61 @@ namespace Contralto
_otherRegs.Rows.Add("MAR", "0");
_otherRegs.Rows.Add("MD", "0");
_otherRegs.Rows.Add("MCycle", "0");
+
+ _diskData.Rows.Add("Cycles", "0");
+ _diskData.Rows.Add("Cylinder", "0");
+ _diskData.Rows.Add("D.Cylinder", "0");
+ _diskData.Rows.Add("Head", "0");
+ _diskData.Rows.Add("Sector", "0");
+ _diskData.Rows.Add("KDATA", "0");
+ _diskData.Rows.Add("KADR", "0");
+ _diskData.Rows.Add("KCOM", "0");
+ _diskData.Rows.Add("KSTAT", "0");
+ _diskData.Rows.Add("RECNO", "0");
+
}
- private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
+ ///
+ /// Handle breakpoint placement on column 0.
+ ///
+ ///
+ ///
+ private void SourceViewCellClick(object sender, DataGridViewCellEventArgs e)
{
+ // Check for breakpoint column click.
+ if (e.ColumnIndex == 0)
+ {
+ // See if this is a source line, if so check/uncheck the box
+ // and set/unset a breakpoint for the line
+ if (_sourceViewer.Rows[e.RowIndex].Tag != null)
+ {
+ bool value = (bool)_sourceViewer.Rows[e.RowIndex].Cells[0].Value;
+ _sourceViewer.Rows[e.RowIndex].Cells[0].Value = !value;
+ ModifyBreakpoint((UInt16)_sourceViewer.Rows[e.RowIndex].Tag, !value);
+ }
+
+ }
+ }
+
+ private void HighlightSourceLine(UInt16 address)
+ {
+ foreach (DataGridViewRow row in _sourceViewer.Rows)
+ {
+ if (row.Tag != null &&
+ (ushort)(row.Tag) == address)
+ {
+ _sourceViewer.ClearSelection();
+ row.Selected = true;
+ _sourceViewer.CurrentCell = row.Cells[0];
+ break;
+ }
+ }
+ }
+
+ private void ModifyBreakpoint(UInt16 address, bool set)
+ {
+ _breakpointEnabled[address] = set;
}
private string GetTextForTaskState(AltoCPU.Task task)
@@ -148,8 +232,16 @@ namespace Contralto
}
else
{
- // TODO: block status
- return task.Wakeup ? "W" : String.Empty;
+ // Wakeup bit
+ string status = task.Wakeup ? "W" : String.Empty;
+
+ // Run bit
+ if (task == _system.CPU.CurrentTask)
+ {
+ status += "R";
+ }
+
+ return status;
}
}
@@ -331,17 +423,177 @@ namespace Contralto
}
+ private void JumpToButton_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ UInt16 address = Convert.ToUInt16(JumpToAddress.Text, 8);
+
+ // find the source address that matches this, if any.
+ HighlightSourceLine(address);
+ }
+ catch
+ {
+ // eh, just do nothing for now
+ }
+ }
+
+ private void OnJumpAddressKeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Return ||
+ e.KeyCode == Keys.Enter)
+ {
+ try
+ {
+ UInt16 address = Convert.ToUInt16(JumpToAddress.Text, 8);
+
+ // find the source address that matches this, if any.
+ HighlightSourceLine(address);
+ }
+ catch
+ {
+ // eh, just do nothing for now
+ }
+ }
+ }
+
private void OnStepButtonClicked(object sender, EventArgs e)
+ {
+ SetExecutionState(ExecutionState.SingleStep);
+ ExecuteStep();
+ SetExecutionState(ExecutionState.Stopped);
+ }
+
+ private void OnAutoStepButtonClicked(object sender, EventArgs e)
+ {
+ //
+ // Continuously step (and update the UI)
+ // until the "Stop" button is pressed or something bad happens.
+ //
+ _execThread = new Thread(new System.Threading.ParameterizedThreadStart(ExecuteProc));
+ _execThread.Start(ExecutionType.Auto);
+ SetExecutionState(ExecutionState.AutoStep);
+ }
+
+ private void RunButton_Click(object sender, EventArgs e)
+ {
+ //
+ // Continuously execute, but do not update UI
+ // until the "Stop" button is pressed or something bad happens.
+ //
+ _execThread = new Thread(new System.Threading.ParameterizedThreadStart(ExecuteProc));
+ _execThread.Start(ExecutionType.Normal);
+ SetExecutionState(ExecutionState.Running);
+ }
+
+ private void OnStopButtonClicked(object sender, EventArgs e)
+ {
+ if (_execThread != null &&
+ _execThread.IsAlive)
+ {
+ // Signal for the exec thread to end
+ _execAbort = true;
+
+ // Wait for the thread to exit.
+ _execThread.Join();
+
+ _execThread = null;
+ }
+
+ SetExecutionState(ExecutionState.Stopped);
+ }
+
+ private void ExecuteStep()
{
_system.SingleStep();
Refresh();
}
+ private void ExecuteProc(object param)
+ {
+ ExecutionType execType = (ExecutionType)param;
+
+ StepDelegate refUI = new StepDelegate(RefreshUI);
+ StepDelegate inv = new StepDelegate(Invalidate);
+ while (true)
+ {
+ if (execType == ExecutionType.Auto)
+ {
+ // Execute a single step, then update UI and
+ // sleep to give messages time to run.
+ _system.SingleStep();
+
+ this.BeginInvoke(refUI);
+ this.BeginInvoke(inv);
+ System.Threading.Thread.Sleep(10);
+ }
+ else
+ {
+ // Just execute one step, do not update UI.
+ _system.SingleStep();
+ }
+
+ if (_execAbort ||
+ _breakpointEnabled[_system.CPU.CurrentTask.MPC])
+ {
+ // Stop here as we've hit a breakpoint or have been stopped Update UI
+ // to indicate where we stopped.
+ this.BeginInvoke(refUI);
+ this.BeginInvoke(inv);
+
+ if (!_execAbort)
+ {
+ SetExecutionState(ExecutionState.BreakpointStop);
+ }
+
+ _execAbort = false;
+ break;
+ }
+ }
+ }
+
+ private void SetExecutionState(ExecutionState state)
+ {
+ _execState = state;
+ this.BeginInvoke(new StepDelegate(RefreshUI));
+ }
+
+
+ private enum ExecutionType
+ {
+ None = 0,
+ Step,
+ Auto,
+ Normal,
+ }
+
+ private enum ExecutionState
+ {
+ Stopped = 0,
+ SingleStep,
+ AutoStep,
+ Running,
+ BreakpointStop,
+ }
+
+ private delegate void StepDelegate();
+
private AltoSystem _system;
// Unicode character for the Arrow used by Alto microcode
private const char _arrowChar = (char)0x2190;
-
+ // Thread used for execution other than single-step
+ private Thread _execThread;
+ private bool _execAbort;
+ private ExecutionState _execState;
+
+
+
+ // Debugger breakpoints; one entry per address since we only need
+ // to worry about a 10 bit address space, this is fast and uses little memory.
+ private bool[] _breakpointEnabled;
+
+
}
}
diff --git a/Contralto/Debugger.resx b/Contralto/Debugger.resx
index e7c4f7d..1689f08 100644
--- a/Contralto/Debugger.resx
+++ b/Contralto/Debugger.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ True
+
True
@@ -156,4 +159,10 @@
True
+
+ True
+
+
+ True
+
\ No newline at end of file
diff --git a/Contralto/Disassembly/altoIIcode3.mu b/Contralto/Disassembly/altoIIcode3.mu
index 3b189ac..372847c 100644
--- a/Contralto/Disassembly/altoIIcode3.mu
+++ b/Contralto/Disassembly/altoIIcode3.mu
@@ -659,7 +659,7 @@ EM00517> INXE: T<-EIOffset, :INXCom; ***X21 addition.
EM00520> INXCom: MAR<-T<-IR<- SAD+T; *** X21 addition.
EM00521> PC<- L, L<- 0+T+1; *** X21 change.
-EM00522> INXB: SAD<- L;
+EM00522> INXB: SAD<- L; **NB (JDersch 9/14 -- this is actually MD<-PC !)
EM00523> SINK<- DISP, BUS,TASK;
EM00524> SAD<- L, :Q0;
diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs
index a6c048c..35641ed 100644
--- a/Contralto/IO/DiskController.cs
+++ b/Contralto/IO/DiskController.cs
@@ -41,7 +41,12 @@ namespace Contralto.IO
{
_kCom = value;
- //
+ // Read control bits (pg. 47 of hw manual)
+ _xferOff = (_kCom & 0x10) == 0x10;
+ _wdInhib = (_kCom & 0x08) == 0x08;
+ _bClkSource = (_kCom & 0x04) == 0x04;
+ _wffo = (_kCom & 0x02) == 0x02;
+ _sendAdr = (_kCom & 0x01) == 0x01;
}
}
@@ -56,6 +61,36 @@ namespace Contralto.IO
get { return _recMap[_recNo]; }
}
+ public int Cylinder
+ {
+ get { return _cylinder; }
+ }
+
+ public int SeekCylinder
+ {
+ get { return _destCylinder; }
+ }
+
+ public int Head
+ {
+ get { return _head; }
+ }
+
+ public int Sector
+ {
+ get { return _sector; }
+ }
+
+ public int Drive
+ {
+ get { return 0; }
+ }
+
+ public double ClocksUntilNextSector
+ {
+ get { return _sectorClocks - _elapsedSectorTime; }
+ }
+
public void Reset()
{
ClearStatus();
@@ -100,7 +135,7 @@ namespace Contralto.IO
{
_cylinder++;
}
- else
+ else if (_cylinder > _destCylinder)
{
_cylinder--;
}
@@ -113,6 +148,33 @@ namespace Contralto.IO
}
}
}
+
+ //
+ // Select data word based on elapsed time in this sector, if data transfer is not inhibited.
+ // On a new word, wake up the disk word task if not inhibited
+ // TODO: the exact mechanics of this are still kind of mysterious.
+ // Things to examine the schematics / uCode for:
+ // - Use of WFFO bit -- is this related to the "sync word" that the docs mention?
+ // - how does WFFO work -- I assume the "1 bit" mentioned in the docs indicates the MFM bit
+ // and indicates the start of the next data word (or is at least used to wait for the next
+ // data word)
+ // - How does the delaying work
+ // The microcode word-copying code works basically as:
+ // On wakeup:
+ // - read word, store into memory.
+ // - block task (remove wakeup)
+ // - task switch (let something else run)
+ // - repeat until all words read
+ // that is, the microcode expects to be woken up on a per-word basis, and it only reads in one word
+ // per wakeup.
+ //
+ // pseudocode so far:
+ // if (elapsed word time > word time)
+ // {
+ // elapsed word time = 0 (modulo remainder)
+ // _kData = next word
+ // if (!_wdInhib) DiskSectorTask.Wakeup();
+ // }
}
public void ClearStatus()
@@ -148,16 +210,16 @@ namespace Contralto.IO
// sanity check: see if SENDADR bit is set, if not we'll signal an error (since I'm trusting that
// the official Xerox uCode is doing the right thing, this will help ferret out emulation issues.
// eventually this can be removed.)
- if ((_kCom & 0x1) != 1)
+ if (!_sendAdr)
{
- throw new InvalidOperationException("STROBE while SENDADR bit of KCOMM not 1. Unexpected.");
+ throw new InvalidOperationException("STROBE while SENDADR bit of KCOM not 1. Unexpected.");
}
_destCylinder = (_kData & 0x0ff8) >> 3;
// set "seek fail" bit based on selected cylinder (if out of bounds) and do not
// commence a seek if so.
- if (_destCylinder < 203)
+ if (_destCylinder > 202)
{
_kStat |= 0x0080;
}
@@ -202,6 +264,13 @@ namespace Contralto.IO
0, 2, 3, 1
};
+ // KCOM bits
+ private bool _xferOff;
+ private bool _wdInhib;
+ private bool _bClkSource;
+ private bool _wffo;
+ private bool _sendAdr;
+
// Current disk position
private int _cylinder;
private int _destCylinder;
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
index 7c905c8..0215b27 100644
--- a/Contralto/Memory/MemoryBus.cs
+++ b/Contralto/Memory/MemoryBus.cs
@@ -73,6 +73,15 @@ namespace Contralto.Memory
get { return _memoryOperationActive; }
}
+ ///
+ /// Used for debugging only -- returns the (correctly mapped)
+ /// word at the specified address
+ ///
+ public ushort DebugReadWord(ushort address)
+ {
+ return ReadFromBus(address);
+ }
+
public void Clock()
{
_memoryCycle++;