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++;