diff --git a/Contralto/CPU/ConstantMemory.cs b/Contralto/CPU/ConstantMemory.cs index 1f6a6b8..f2a8501 100644 --- a/Contralto/CPU/ConstantMemory.cs +++ b/Contralto/CPU/ConstantMemory.cs @@ -134,8 +134,8 @@ namespace Contralto.CPU } } - // And invert. - return (~mappedData) & 0xff; + // And invert lines 1-7 + return ((~mappedData) & 0x7f) | (mappedData & 0x80); } private static RomFile[] _constantRoms = diff --git a/Contralto/CPU/NovaDisassembler.cs b/Contralto/CPU/NovaDisassembler.cs index f19b466..7e8052d 100644 --- a/Contralto/CPU/NovaDisassembler.cs +++ b/Contralto/CPU/NovaDisassembler.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Contralto.CPU +namespace Contralto.CPU.Nova { /// /// Quick and dirty disassembler for Nova instructions, so we can @@ -12,6 +12,324 @@ namespace Contralto.CPU /// public static class NovaDisassembler { + /// + /// Disassembles the specified instruction + /// + /// + /// + public static string DisassembleInstruction(ushort address, ushort instructionWord) + { + string disassembly = null; + + + switch ((InstructionClass)(instructionWord & 0xe000)) + { + case InstructionClass.MEM: + disassembly = DisassembleMem(address, instructionWord); + break; + + case InstructionClass.LDA: + case InstructionClass.STA: + disassembly = DisassembleLoadStore(address, instructionWord); + break; + + case InstructionClass.IO: + disassembly = DisassembleIO(instructionWord); + break; + + default: + // None of the above, must be ALC + disassembly = DisassembleALC(instructionWord); + break; + } + + return disassembly; + } + + private static string DisassembleMem(ushort address, ushort instructionWord) + { + StringBuilder d = new StringBuilder(); + + // Function + MemFunction func = (MemFunction)(instructionWord & 0x1800); + + // Indirect bit + bool indirect = (instructionWord & 0x400) != 0; + + // Indexing mode + MemIndex index = (MemIndex)(instructionWord & 0x300); + + // Displacement + int disp = (instructionWord & 0xff); + + switch (index) + { + case MemIndex.PageZero: + d.AppendFormat("{0}{1} {2}", + func, + indirect ? "@" : String.Empty, + OctalHelpers.ToOctal(disp)); + break; + + case MemIndex.PCRelative: + d.AppendFormat("{0}{1} .+{2} ;({3})", + func, + indirect ? "@" : String.Empty, + OctalHelpers.ToOctal((sbyte)disp), + OctalHelpers.ToOctal((sbyte)disp + address)); + break; + + case MemIndex.AC2Relative: + d.AppendFormat("{0}{1} AC2+{2}", + func, + indirect ? "@" : String.Empty, + OctalHelpers.ToOctal((sbyte)disp)); + break; + + case MemIndex.AC3Relative: + d.AppendFormat("{0}{1} AC3+{2}", + func, + indirect ? "@" : String.Empty, + OctalHelpers.ToOctal((sbyte)disp)); + break; + + default: + throw new InvalidOperationException("unexpected index type."); + } + + return d.ToString(); + } + + private static string DisassembleLoadStore(ushort address, ushort instructionWord) + { + StringBuilder d = new StringBuilder(); + + // Accumulator + int ac = (instructionWord & 0x1800) >> 11; + + // Indirect bit + bool indirect = (instructionWord & 0x400) != 0; + + // Indexing mode + MemIndex index = (MemIndex)(instructionWord & 0x300); + + // Displacement + int disp = (instructionWord & 0xff); + + // instruction (LDA or STA) + string inst = (InstructionClass)(instructionWord & 0x6000) == InstructionClass.LDA ? "LDA" : "STA"; + + switch(index) + { + case MemIndex.PageZero: + d.AppendFormat("{0}{1} {2},{3}", + inst, + indirect ? "@" : String.Empty, + ac, + OctalHelpers.ToOctal(disp)); + break; + + case MemIndex.PCRelative: + d.AppendFormat("{0}{1} {2},.+{3} ;({4})", + inst, + indirect ? "@" : String.Empty, + ac, + OctalHelpers.ToOctal((sbyte)disp), + OctalHelpers.ToOctal((sbyte)disp + address)); + break; + + case MemIndex.AC2Relative: + d.AppendFormat("{0}{1} {2},AC2+{3}", + inst, + indirect ? "@" : String.Empty, + ac, + OctalHelpers.ToOctal((sbyte)disp)); + break; + + case MemIndex.AC3Relative: + d.AppendFormat("{0}{1} {2},AC3+{3}", + inst, + indirect ? "@" : String.Empty, + ac, + OctalHelpers.ToOctal((sbyte)disp)); + break; + + default: + throw new InvalidOperationException("unexpected index type."); + } + + return d.ToString(); + } + + private static string DisassembleIO(ushort instructionWord) + { + StringBuilder d = new StringBuilder(); + + // Accumulator + int ac = (instructionWord & 0x1800) >> 11; + + // Transfer + IOTransfer trans = (IOTransfer)(instructionWord & 0x700); + + // Control + IOControl cont = (IOControl)(instructionWord & 0xc0); + + // Device code + int deviceCode = (instructionWord & 0x3f); + + if (trans != IOTransfer.SKP) + { + d.AppendFormat("{0}{1} {2},{3}", + trans, + cont == IOControl.None ? String.Empty : cont.ToString(), + ac, + OctalHelpers.ToOctal(deviceCode)); + } + else + { + d.AppendFormat("{0} {1}", + (IOSkip)cont, + OctalHelpers.ToOctal(deviceCode)); + } + + return d.ToString(); + } + + private static string DisassembleALC(ushort instructionWord) + { + StringBuilder d = new StringBuilder(); + + // Grab source/dest accumulators + int srcAC = (instructionWord & 0x6000) >> 13; + int dstAC = (instructionWord & 0x1800) >> 11; + + // Function + ALCFunctions func = (ALCFunctions)(instructionWord & 0x700); + + // Shift + ALCShift shift = (ALCShift)(instructionWord & 0xc0); + + // Carry + ALCCarry carry = (ALCCarry)(instructionWord & 0x30); + + // No load + bool noLoad = ((instructionWord & 0x8) != 0); + + // Skip + ALCSkip skip = (ALCSkip)(instructionWord & 0x7); + + // initial format (minus skip): + // FUNC[shift][carry][noload] src, dest + d.AppendFormat( + "{0}{1}{2}{3} {4},{5}", + func, + shift == ALCShift.None ? String.Empty : shift.ToString(), + carry == ALCCarry.None ? String.Empty : carry.ToString(), + noLoad ? "#" : String.Empty, + srcAC, + dstAC); + + // If a skip is specified, tack it on + if (skip != ALCSkip.None) + { + d.AppendFormat(",{0}", skip); + } + + + return d.ToString(); + } + + private enum InstructionClass + { + MEM = 0x0000, + LDA = 0x2000, + STA = 0x4000, + IO = 0x6000, + } + + private enum ALCFunctions + { + COM = 0x000, + NEG = 0x100, + MOV = 0x200, + INC = 0x300, + ADC = 0x400, + SUB = 0x500, + ADD = 0x600, + AND = 0x700, + } + + private enum ALCShift + { + None = 0x00, + L = 0x40, + R = 0x80, + S = 0xc0, + } + + private enum ALCCarry + { + None = 0x00, + Z = 0x10, + O = 0x20, + C = 0x30, + } + + private enum ALCSkip + { + None = 0x0, + SKP = 0x1, + SZC = 0x2, + SNC = 0x3, + SZR = 0x4, + SNR = 0x5, + SEZ = 0x6, + SBN = 0x7, + } + + private enum IOTransfer + { + NIO = 0x000, + DIA = 0x100, + DOA = 0x200, + DIB = 0x300, + DOB = 0x400, + DIC = 0x500, + DOC = 0x600, + SKP = 0x700, + } + + private enum IOControl + { + None = 0x00, + S = 0x40, + C = 0x80, + P = 0xc0, + } + + private enum IOSkip + { + SKPBN = 0x00, + SKPBZ = 0x40, + SKPDN = 0x80, + SKPDZ = 0xc0, + } + + private enum MemFunction + { + JMP = 0x0000, + JSR = 0x0800, + ISZ = 0x1000, + DSZ = 0x1800, + } + + private enum MemIndex + { + PageZero = 0x000, + PCRelative = 0x100, + AC2Relative = 0x200, + AC3Relative = 0x300, + } } } diff --git a/Contralto/CPU/Shifter.cs b/Contralto/CPU/Shifter.cs index 2f75fa4..743e6fa 100644 --- a/Contralto/CPU/Shifter.cs +++ b/Contralto/CPU/Shifter.cs @@ -47,6 +47,16 @@ namespace Contralto.CPU _magic = magic; } + + /// + /// TODO: this is still kind of clumsy. + /// + /// + public static void SetDNS(bool dns) + { + _dns = dns; + } + /// /// Does the last specified operation to the specified inputs /// @@ -55,6 +65,12 @@ namespace Contralto.CPU /// public static ushort DoOperation(ushort input, ushort t) { + // Sanity check: MAGIC and DNS cannot be set at the same time. + if (_magic && _dns) + { + throw new InvalidOperationException("Both MAGIC and DNS bits are set."); + } + ushort output = 0; switch(_op) { @@ -74,6 +90,10 @@ namespace Contralto.CPU // shifter output on left shifts..." output |= (ushort)((t & 0x8000) >> 15); } + else if (_dns) + { + throw new NotImplementedException("DNS LSH 1"); + } break; case ShifterOp.ShiftRight: @@ -85,6 +105,10 @@ namespace Contralto.CPU // of the shifter output on right shifts." output |= (ushort)((t & 0x1) << 15); } + else if (_dns) + { + throw new NotImplementedException("DNS RSH 1"); + } break; case ShifterOp.RotateLeft: @@ -95,6 +119,11 @@ namespace Contralto.CPU int c = (output & 0x8000) >> 15; output = (ushort)((output << 1) | c); } + + if (_dns) + { + throw new NotImplementedException("DNS LCY"); + } break; case ShifterOp.RotateRight: @@ -117,5 +146,6 @@ namespace Contralto.CPU private static ShifterOp _op; private static int _count; private static bool _magic; + private static bool _dns; } } diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs index e65d6e3..4e98c4a 100644 --- a/Contralto/CPU/Tasks/DiskTask.cs +++ b/Contralto/CPU/Tasks/DiskTask.cs @@ -45,8 +45,7 @@ namespace Contralto.CPU return _cpu._system.DiskController.KSTAT; case DiskBusSource.ReadKDATA: - ushort kdata = _cpu._system.DiskController.KDATA; - Console.WriteLine("kdata read {0}", OctalHelpers.ToOctal(kdata)); + ushort kdata = _cpu._system.DiskController.KDATA; return kdata; default: @@ -89,9 +88,7 @@ namespace Contralto.CPU // 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)); - - Console.WriteLine("KSTAT loaded with {0}, is now {1}", (_busData & 0xf), _cpu._system.DiskController.KSTAT); + _cpu._system.DiskController.KSTAT = (ushort)(((_cpu._system.DiskController.KSTAT & 0xfff4)) | (_busData & 0xf)); break; case DiskF1.STROBE: diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs index 82448a9..4c20df4 100644 --- a/Contralto/CPU/Tasks/EmulatorTask.cs +++ b/Contralto/CPU/Tasks/EmulatorTask.cs @@ -198,12 +198,23 @@ namespace Contralto.CPU // There is considerably more that goes into determining the dispatch, which is controlled by a 256x8 // PROM. We just use the PROM rather than implementing the above logic (because it works.) // - _nextModifier = ControlROM.ACSourceROM[(_cpu._ir & 0xff00) >> 8]; - + + if ((_cpu._ir & 0x8000) != 0) + { + // 3-IR[8-9] (shift field of arithmetic instruction) + _nextModifier = (ushort)(3 - ((_cpu._ir & 0xc0) >> 6)); + } + else + { + // Use the PROM. + // We OR in 0x80 because the top address line is controlled by the value of ACSOURCE(2), which is always + // 1 here (since ACSOURCE is 14 decimal). + _nextModifier = ControlROM.ACSourceROM[((_cpu._ir & 0x7f00) >> 8) | 0x80]; + } break; case EmulatorF2.ACDEST: - // Handled in early handler + // Handled in early handler, nothing to do here. break; case EmulatorF2.BUSODD: @@ -215,10 +226,15 @@ namespace Contralto.CPU case EmulatorF2.MAGIC: Shifter.SetMagic(true); break; - + + case EmulatorF2.LoadDNS: + // DNS<- modifies the normal shift operations. + Shifter.SetDNS(true); + break; default: throw new InvalidOperationException(String.Format("Unhandled emulator F2 {0}.", ef2)); + break; } } diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs index e9451fd..45b3721 100644 --- a/Contralto/CPU/Tasks/Task.cs +++ b/Contralto/CPU/Tasks/Task.cs @@ -72,7 +72,13 @@ namespace Contralto.CPU { // TODO: cache microinstructions (or pre-decode them) to save consing all these up every time. MicroInstruction instruction = new MicroInstruction(UCodeMemory.UCodeROM[_mpc]); + + // Grab BLOCK bit so that other tasks can look at it _block = instruction.F1 == SpecialFunction1.Block; + + //Console.WriteLine("R5:{0},R6:{1},IR:{2} - {3}:{4}", OctalHelpers.ToOctal(_cpu._r[5]), OctalHelpers.ToOctal(_cpu._r[6]), OctalHelpers.ToOctal(_cpu._ir), OctalHelpers.ToOctal(_mpc), UCodeDisassembler.DisassembleInstruction(instruction, _taskType)); + + return ExecuteInstruction(instruction); } @@ -100,9 +106,11 @@ namespace Contralto.CPU // the memory isn't ready yet. // TODO: this needs to be seriously cleaned up. // - if (instruction.BS == BusSource.ReadMD || + if ((instruction.BS == BusSource.ReadMD && + (instruction.F1 != SpecialFunction1.Constant && + instruction.F2 != SpecialFunction2.Constant)) || // ReadMD only occurs if not reading from constant ROM. instruction.F1 == SpecialFunction1.LoadMAR || - instruction.F2 == SpecialFunction2.StoreMD) + instruction.F2 == SpecialFunction2.StoreMD) { MemoryOperation op; @@ -336,12 +344,7 @@ namespace Contralto.CPU // Do writeback to selected R register from shifter output if (loadR) { - _cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t); - - if(_rSelect == 26) - { - Console.WriteLine("cksum is now {0}", OctalHelpers.ToOctal(_cpu._r[_rSelect])); - } + _cpu._r[_rSelect] = Shifter.DoOperation(_cpu._l, _cpu._t); } // Do writeback to selected R register from M diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 85897e0..faacf86 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -65,6 +65,7 @@ + @@ -78,9 +79,15 @@ PreserveNewest + + PreserveNewest + Always + + Always + Always diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs index 3c21969..da2809d 100644 --- a/Contralto/Debugger.Designer.cs +++ b/Contralto/Debugger.Designer.cs @@ -43,8 +43,6 @@ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle(); System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle14 = 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(); this.Microcode = new System.Windows.Forms.GroupBox(); this.label2 = new System.Windows.Forms.Label(); this.JumpToAddress = new System.Windows.Forms.TextBox(); @@ -73,8 +71,6 @@ this.RegValue = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.groupBox4 = new System.Windows.Forms.GroupBox(); 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.groupBox5 = new System.Windows.Forms.GroupBox(); @@ -82,11 +78,12 @@ this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.ResetButton = new System.Windows.Forms.Button(); - this.groupBox6 = new System.Windows.Forms.GroupBox(); - this._debugTasks = new System.Windows.Forms.DataGridView(); - this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewCheckBoxColumn(); - this.dataGridViewTextBoxColumn4 = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.RunToNextTaskButton = new System.Windows.Forms.Button(); + this.B = new System.Windows.Forms.DataGridViewCheckBoxColumn(); + this.Address = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Data = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.Disassembly = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.NovaStep = new System.Windows.Forms.Button(); this.Microcode.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this._sourceViewer)).BeginInit(); this.groupBox1.SuspendLayout(); @@ -99,8 +96,6 @@ ((System.ComponentModel.ISupportInitialize)(this._memoryData)).BeginInit(); this.groupBox5.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this._diskData)).BeginInit(); - this.groupBox6.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this._debugTasks)).BeginInit(); this.SuspendLayout(); // // Microcode @@ -329,7 +324,7 @@ // // StopButton // - this.StopButton.Location = new System.Drawing.Point(207, 954); + this.StopButton.Location = new System.Drawing.Point(351, 955); this.StopButton.Name = "StopButton"; this.StopButton.Size = new System.Drawing.Size(43, 23); this.StopButton.TabIndex = 6; @@ -475,9 +470,9 @@ // groupBox4 // this.groupBox4.Controls.Add(this._memoryData); - this.groupBox4.Location = new System.Drawing.Point(319, 634); + this.groupBox4.Location = new System.Drawing.Point(172, 634); this.groupBox4.Name = "groupBox4"; - this.groupBox4.Size = new System.Drawing.Size(144, 344); + this.groupBox4.Size = new System.Drawing.Size(291, 298); this.groupBox4.TabIndex = 8; this.groupBox4.TabStop = false; this.groupBox4.Text = "Memory"; @@ -490,8 +485,10 @@ this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle12; this._memoryData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this._memoryData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.B, this.Address, - this.Data}); + this.Data, + this.Disassembly}); 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))); @@ -513,25 +510,9 @@ this._memoryData.ShowCellToolTips = false; this._memoryData.ShowEditingIcon = false; this._memoryData.ShowRowErrors = false; - this._memoryData.Size = new System.Drawing.Size(132, 319); + this._memoryData.Size = new System.Drawing.Size(279, 273); this._memoryData.TabIndex = 0; - // - // Address - // - this.Address.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; - this.Address.HeaderText = "Addr"; - this.Address.MinimumWidth = 16; - this.Address.Name = "Address"; - this.Address.ReadOnly = true; - this.Address.Width = 54; - // - // Data - // - this.Data.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - this.Data.HeaderText = "Data"; - this.Data.MinimumWidth = 16; - this.Data.Name = "Data"; - this.Data.ReadOnly = true; + this._memoryData.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.MemoryViewCellClick); // // label1 // @@ -554,7 +535,7 @@ // groupBox5 // this.groupBox5.Controls.Add(this._diskData); - this.groupBox5.Location = new System.Drawing.Point(150, 634); + 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; @@ -614,7 +595,7 @@ // // ResetButton // - this.ResetButton.Location = new System.Drawing.Point(256, 955); + this.ResetButton.Location = new System.Drawing.Point(400, 955); this.ResetButton.Name = "ResetButton"; this.ResetButton.Size = new System.Drawing.Size(57, 23); this.ResetButton.TabIndex = 12; @@ -622,69 +603,6 @@ this.ResetButton.UseVisualStyleBackColor = true; this.ResetButton.Click += new System.EventHandler(this.ResetButton_Click); // - // groupBox6 - // - this.groupBox6.Controls.Add(this._debugTasks); - this.groupBox6.Location = new System.Drawing.Point(3, 634); - this.groupBox6.Name = "groupBox6"; - this.groupBox6.Size = new System.Drawing.Size(141, 298); - this.groupBox6.TabIndex = 12; - this.groupBox6.TabStop = false; - this.groupBox6.Text = "Debug Tasks"; - // - // _debugTasks - // - this._debugTasks.AllowUserToAddRows = false; - this._debugTasks.AllowUserToDeleteRows = false; - dataGridViewCellStyle16.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224))))); - this._debugTasks.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle16; - this._debugTasks.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; - this._debugTasks.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { - this.dataGridViewTextBoxColumn3, - this.dataGridViewTextBoxColumn4}); - dataGridViewCellStyle17.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; - dataGridViewCellStyle17.BackColor = System.Drawing.SystemColors.Window; - dataGridViewCellStyle17.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - dataGridViewCellStyle17.ForeColor = System.Drawing.SystemColors.ControlText; - dataGridViewCellStyle17.SelectionBackColor = System.Drawing.SystemColors.Highlight; - dataGridViewCellStyle17.SelectionForeColor = System.Drawing.SystemColors.HighlightText; - dataGridViewCellStyle17.WrapMode = System.Windows.Forms.DataGridViewTriState.False; - this._debugTasks.DefaultCellStyle = dataGridViewCellStyle17; - this._debugTasks.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically; - this._debugTasks.Location = new System.Drawing.Point(6, 19); - this._debugTasks.MultiSelect = false; - this._debugTasks.Name = "_debugTasks"; - this._debugTasks.ReadOnly = true; - this._debugTasks.RowHeadersVisible = false; - this._debugTasks.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this._debugTasks.RowTemplate.Height = 18; - this._debugTasks.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; - this._debugTasks.ShowCellErrors = false; - this._debugTasks.ShowCellToolTips = false; - this._debugTasks.ShowEditingIcon = false; - this._debugTasks.ShowRowErrors = false; - this._debugTasks.Size = new System.Drawing.Size(129, 273); - this._debugTasks.TabIndex = 1; - // - // dataGridViewTextBoxColumn3 - // - this.dataGridViewTextBoxColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader; - this.dataGridViewTextBoxColumn3.HeaderText = "Debug"; - this.dataGridViewTextBoxColumn3.MinimumWidth = 16; - this.dataGridViewTextBoxColumn3.Name = "dataGridViewTextBoxColumn3"; - this.dataGridViewTextBoxColumn3.ReadOnly = true; - this.dataGridViewTextBoxColumn3.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this.dataGridViewTextBoxColumn3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - this.dataGridViewTextBoxColumn3.Width = 16; - // - // dataGridViewTextBoxColumn4 - // - this.dataGridViewTextBoxColumn4.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; - this.dataGridViewTextBoxColumn4.HeaderText = "Task"; - this.dataGridViewTextBoxColumn4.MinimumWidth = 16; - this.dataGridViewTextBoxColumn4.Name = "dataGridViewTextBoxColumn4"; - this.dataGridViewTextBoxColumn4.ReadOnly = true; - // // RunToNextTaskButton // this.RunToNextTaskButton.Location = new System.Drawing.Point(150, 954); @@ -695,13 +613,66 @@ this.RunToNextTaskButton.UseVisualStyleBackColor = true; this.RunToNextTaskButton.Click += new System.EventHandler(this.RunToNextTaskButton_Click); // + // B + // + this.B.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; + this.B.FalseValue = "false"; + this.B.HeaderText = "B"; + this.B.Name = "B"; + this.B.ReadOnly = true; + this.B.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.B.ToolTipText = "Breakpoint"; + this.B.TrueValue = "true"; + this.B.Width = 20; + // + // Address + // + this.Address.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; + this.Address.HeaderText = "Addr"; + this.Address.MinimumWidth = 16; + this.Address.Name = "Address"; + this.Address.ReadOnly = true; + this.Address.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.Address.ToolTipText = "Address"; + this.Address.Width = 54; + // + // Data + // + this.Data.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; + this.Data.HeaderText = "Data"; + this.Data.MinimumWidth = 16; + this.Data.Name = "Data"; + this.Data.ReadOnly = true; + this.Data.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.Data.ToolTipText = "Data"; + this.Data.Width = 55; + // + // Disassembly + // + this.Disassembly.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.Disassembly.HeaderText = "Disassembly"; + this.Disassembly.Name = "Disassembly"; + this.Disassembly.ReadOnly = true; + this.Disassembly.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.Disassembly.ToolTipText = "Disassembly"; + // + // NovaStep + // + this.NovaStep.Location = new System.Drawing.Point(207, 954); + this.NovaStep.Name = "NovaStep"; + this.NovaStep.Size = new System.Drawing.Size(66, 23); + this.NovaStep.TabIndex = 14; + this.NovaStep.Text = "Nova Step"; + this.NovaStep.UseVisualStyleBackColor = true; + this.NovaStep.Click += new System.EventHandler(this.NovaStep_Click); + // // 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.NovaStep); this.Controls.Add(this.RunToNextTaskButton); - this.Controls.Add(this.groupBox6); this.Controls.Add(this.ResetButton); this.Controls.Add(this.groupBox5); this.Controls.Add(this.ExecutionStateLabel); @@ -731,8 +702,6 @@ ((System.ComponentModel.ISupportInitialize)(this._memoryData)).EndInit(); this.groupBox5.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this._diskData)).EndInit(); - this.groupBox6.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this._debugTasks)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -762,8 +731,6 @@ private System.Windows.Forms.DataGridViewTextBoxColumn RegValue; private System.Windows.Forms.GroupBox groupBox4; 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; @@ -777,10 +744,11 @@ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn1; private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2; private System.Windows.Forms.Button ResetButton; - private System.Windows.Forms.GroupBox groupBox6; - private System.Windows.Forms.DataGridView _debugTasks; - private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewTextBoxColumn3; - private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn4; private System.Windows.Forms.Button RunToNextTaskButton; + private System.Windows.Forms.DataGridViewCheckBoxColumn B; + private System.Windows.Forms.DataGridViewTextBoxColumn Address; + private System.Windows.Forms.DataGridViewTextBoxColumn Data; + private System.Windows.Forms.DataGridViewTextBoxColumn Disassembly; + private System.Windows.Forms.Button NovaStep; } } \ No newline at end of file diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs index 5d8ebc4..2362ccb 100644 --- a/Contralto/Debugger.cs +++ b/Contralto/Debugger.cs @@ -21,7 +21,8 @@ namespace Contralto public Debugger(AltoSystem system) { _system = system; - _breakpointEnabled = new bool[1024]; + _microcodeBreakpointEnabled = new bool[1024]; + _novaBreakpointEnabled = new bool[65536]; InitializeComponent(); InitControls(); @@ -113,11 +114,18 @@ namespace Contralto for (ushort i = 0; i < 1024; i++) { - _memoryData.Rows[i].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6); + _memoryData.Rows[i].Cells[2].Value = OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6); + _memoryData.Rows[i].Cells[3].Value = Contralto.CPU.Nova.NovaDisassembler.DisassembleInstruction(i, _system.MemoryBus.DebugReadWord(i)); } - // Find the right source line - HighlightSourceLine(_system.CPU.CurrentTask.MPC); + // Find the right source line. + HighlightMicrocodeSourceLine(_system.CPU.CurrentTask.MPC); + + // Highlight the nova memory location corresponding to the emulator PC. + // TODO: this should be configurable + ushort pc = _system.CPU.R[6]; + + HighlightNovaSourceLine(pc); // Exec state switch(_execState) @@ -141,6 +149,10 @@ namespace Contralto case ExecutionState.BreakpointStop: ExecutionStateLabel.Text = "Stopped (bkpt)"; break; + + case ExecutionState.InternalError: + ExecutionStateLabel.Text = String.Format("Stopped (error {0})", _lastExceptionText); + break; } } @@ -159,7 +171,11 @@ namespace Contralto for (ushort i=0;i<1024;i++) { - _memoryData.Rows.Add(OctalHelpers.ToOctal(i, 6), OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6)); + _memoryData.Rows.Add( + false, + OctalHelpers.ToOctal(i, 6), + OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord(i), 6), + Contralto.CPU.Nova.NovaDisassembler.DisassembleInstruction(i, _system.MemoryBus.DebugReadWord(i))); } _otherRegs.Rows.Add("L", "0"); @@ -180,12 +196,7 @@ namespace Contralto _diskData.Rows.Add("KADR", "0"); _diskData.Rows.Add("KCOM", "0"); _diskData.Rows.Add("KSTAT", "0"); - _diskData.Rows.Add("RECNO", "0"); - - for (int i=0;i<16;i++) - { - _debugTasks.Rows.Add(true, GetTextForTask((TaskType)i)); - } + _diskData.Rows.Add("RECNO", "0"); } @@ -206,13 +217,27 @@ namespace Contralto 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); + ModifyMicrocodeBreakpoint((UInt16)_sourceViewer.Rows[e.RowIndex].Tag, !value); } } } - private void HighlightSourceLine(UInt16 address) + private void MemoryViewCellClick(object sender, DataGridViewCellEventArgs e) + { + // Check for breakpoint column click. + if (e.ColumnIndex == 0) + { + // Check/uncheck the box and set/unset a breakpoint for the line + bool value = (bool)_memoryData.Rows[e.RowIndex].Cells[0].Value; + _memoryData.Rows[e.RowIndex].Cells[0].Value = !value; + + ModifyNovaBreakpoint((UInt16)e.RowIndex, !value); + } + } + + + private void HighlightMicrocodeSourceLine(UInt16 address) { foreach (DataGridViewRow row in _sourceViewer.Rows) { @@ -227,9 +252,24 @@ namespace Contralto } } - private void ModifyBreakpoint(UInt16 address, bool set) + private void HighlightNovaSourceLine(UInt16 address) { - _breakpointEnabled[address] = set; + if (address < _memoryData.Rows.Count) + { + _memoryData.ClearSelection(); + _memoryData.Rows[address].Selected = true; + _memoryData.CurrentCell = _memoryData.Rows[address].Cells[0]; + } + } + + private void ModifyMicrocodeBreakpoint(UInt16 address, bool set) + { + _microcodeBreakpointEnabled[address] = set; + } + + private void ModifyNovaBreakpoint(UInt16 address, bool set) + { + _novaBreakpointEnabled[address] = set; } private string GetTextForTaskState(AltoCPU.Task task) @@ -429,22 +469,7 @@ namespace Contralto private void Debugger_Load(object sender, EventArgs e) { - } - - 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) { @@ -456,7 +481,7 @@ namespace Contralto UInt16 address = Convert.ToUInt16(JumpToAddress.Text, 8); // find the source address that matches this, if any. - HighlightSourceLine(address); + HighlightMicrocodeSourceLine(address); } catch { @@ -511,6 +536,23 @@ namespace Contralto } } + /// + /// Runs microcode until next Nova instruction is started + /// This is done by simply breaking whenever the uPC for the emulator + /// task returns to 20(octal) -- this is the restart point for the emulator + /// task. + /// + /// + /// + private void NovaStep_Click(object sender, EventArgs e) + { + { + _execThread = new Thread(new System.Threading.ParameterizedThreadStart(ExecuteProc)); + _execThread.Start(ExecutionType.NextNovaInstruction); + SetExecutionState(ExecutionState.Running); + } + } + private void OnStopButtonClicked(object sender, EventArgs e) { if (_execThread != null && @@ -547,36 +589,66 @@ namespace Contralto StepDelegate inv = new StepDelegate(Invalidate); while (true) { - switch (execType) + bool internalError = false; + + try { - case ExecutionType.Auto: - { - // Execute a single step, then update UI and - // sleep to give messages time to run. - _system.SingleStep(); + switch (execType) + { + case 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); - } - break; + this.BeginInvoke(refUI); + this.BeginInvoke(inv); + System.Threading.Thread.Sleep(10); + } + break; - case ExecutionType.Step: - case ExecutionType.Normal: - case ExecutionType.NextTask: - { - // Just execute one step, do not update UI. - _system.SingleStep(); - } - break; + case ExecutionType.Step: + case ExecutionType.Normal: + case ExecutionType.NextTask: + case ExecutionType.NextNovaInstruction: + { + // Just execute one step, do not update UI. + _system.SingleStep(); + } + break; + } + } + catch(Exception e) + { + internalError = true; + _lastExceptionText = e.Message; } - if (_execAbort || - _breakpointEnabled[_system.CPU.CurrentTask.MPC] || - (execType == ExecutionType.NextTask && _system.CPU.NextTask != null && _system.CPU.NextTask != _system.CPU.CurrentTask)) + if (internalError) { - // Stop here as we've hit a breakpoint or have been stopped Update UI - // to indicate where we stopped. + // + // Stop here because of an execution error. + // + this.BeginInvoke(refUI); + this.BeginInvoke(inv); + + + SetExecutionState(ExecutionState.InternalError); + + break; + } + + if (_execAbort || // The Stop button was hit + _microcodeBreakpointEnabled[_system.CPU.CurrentTask.MPC] || // A microcode breakpoint was hit + (execType == ExecutionType.NextTask && + _system.CPU.NextTask != null && + _system.CPU.NextTask != _system.CPU.CurrentTask) || // The next task was switched to + (_system.CPU.CurrentTask.MPC == 0x10 && // MPC is 20(octal) meaning a new Nova instruction and... + (_novaBreakpointEnabled[_system.CPU.R[6]] || // A breakpoint is set here + execType == ExecutionType.NextNovaInstruction))) // or we're running only a single Nova instruction. + { + // 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); @@ -587,7 +659,7 @@ namespace Contralto _execAbort = false; break; - } + } } } @@ -605,6 +677,7 @@ namespace Contralto Auto, Normal, NextTask, + NextNovaInstruction, } private enum ExecutionState @@ -614,6 +687,7 @@ namespace Contralto AutoStep, Running, BreakpointStop, + InternalError, } private delegate void StepDelegate(); @@ -627,12 +701,15 @@ namespace Contralto private Thread _execThread; private bool _execAbort; private ExecutionState _execState; + private string _lastExceptionText; - - // Debugger breakpoints; one entry per address since we only need + // Microcode 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; + private bool[] _microcodeBreakpointEnabled; + + // Nova Debugger breakpoints; same as above + private bool[] _novaBreakpointEnabled; } diff --git a/Contralto/Debugger.resx b/Contralto/Debugger.resx index 5a5826b..f85eb74 100644 --- a/Contralto/Debugger.resx +++ b/Contralto/Debugger.resx @@ -153,22 +153,22 @@ True + + True + True True + + True + True True - - True - - - True - \ No newline at end of file diff --git a/Contralto/Disk/diag.dsk b/Contralto/Disk/diag.dsk new file mode 100644 index 0000000..01373f2 Binary files /dev/null and b/Contralto/Disk/diag.dsk differ diff --git a/Contralto/Disk/tdisk4.dsk b/Contralto/Disk/tdisk4.dsk new file mode 100644 index 0000000..81321bf Binary files /dev/null and b/Contralto/Disk/tdisk4.dsk differ diff --git a/Contralto/IO/DiabloPack.cs b/Contralto/IO/DiabloPack.cs index 2b583af..3fac793 100644 --- a/Contralto/IO/DiabloPack.cs +++ b/Contralto/IO/DiabloPack.cs @@ -105,6 +105,7 @@ namespace Contralto.IO // TODO: should support different formats ("correct" raw, Alto CopyDisk format, etc.) // imageStream.Seek(2, SeekOrigin.Current); + if (imageStream.Read(header, 0, header.Length) != header.Length) { throw new InvalidOperationException("Short read while reading sector header."); diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs index dded8f3..32979f8 100644 --- a/Contralto/IO/DiskController.cs +++ b/Contralto/IO/DiskController.cs @@ -20,12 +20,12 @@ namespace Contralto.IO _pack = new DiabloPack(DiabloDiskType.Diablo31); // TODO: this does not belong here. - FileStream fs = new FileStream("Disk\\games.dsk", FileMode.Open, FileAccess.Read); + FileStream fs = new FileStream("Disk\\tdisk4.dsk", FileMode.Open, FileAccess.Read); _pack.Load(fs); fs.Close(); - + // Wakeup the sector task first thing _system.CPU.WakeupTask(CPU.TaskType.DiskSector); } @@ -70,15 +70,6 @@ namespace Contralto.IO _wffo = (_kCom & 0x02) == 0x02; _sendAdr = (_kCom & 0x01) == 0x01; - Console.WriteLine( - "sst {0}, xferOff {1}, wdInhib {2}, bClkSource {3}, wffo {4}, sendAdr {5}", - _sectorWordTime, - _xferOff, - _wdInhib, - _bClkSource, - _wffo, - _sendAdr); - _diskBitCounterEnable = _wffo; // Update WDINIT state based on _wdInhib. @@ -200,7 +191,7 @@ namespace Contralto.IO // Reset internal state machine for sector data _sectorWordIndex = 0; _sectorWordTime = 0.0; - Console.WriteLine("New sector ({0}), switching to HeaderReadDelay state.", _sector); + _kData = 13; // Load new sector in @@ -371,16 +362,13 @@ namespace Contralto.IO // ushort diskWord = _sectorData[_sectorWordIndex].Data; - Console.WriteLine("Sector Word {0}:{1}", _sectorWordIndex, OctalHelpers.ToOctal(diskWord)); - bool bWakeup = false; // // If the word task is enabled AND the write ("crystal") clock is enabled // then we will wake up the word task now. // if (!_wdInhib && !_bClkSource) - { - Console.WriteLine("Disk Word task wakeup due to word clock."); + { bWakeup = true; } @@ -392,14 +380,12 @@ namespace Contralto.IO if (_wffo || _diskBitCounterEnable) { if (!_xferOff) - { - Console.WriteLine("KDATA loaded."); + { _kData = diskWord; } if (!_wdInhib) { - Console.WriteLine("Disk Word task wakeup due to word read."); bWakeup = true; } } @@ -411,8 +397,7 @@ namespace Contralto.IO // (not the sync word) is actually read. TODO: this should only happen on reads. // if (!_wffo && diskWord == 1) - { - Console.WriteLine("Sync word hit; starting bit clock for next word"); + { _diskBitCounterEnable = true; } diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs index 2ed1ee6..7d097bc 100644 --- a/Contralto/Memory/Memory.cs +++ b/Contralto/Memory/Memory.cs @@ -19,8 +19,7 @@ namespace Contralto.Memory } public void Load(int address, ushort data) - { - Console.WriteLine("wrote {0} to {1}", OctalHelpers.ToOctal(data), OctalHelpers.ToOctal(address)); + { _mem[address] = data; } diff --git a/Contralto/OctalHelpers.cs b/Contralto/OctalHelpers.cs index bafaf12..c7c833e 100644 --- a/Contralto/OctalHelpers.cs +++ b/Contralto/OctalHelpers.cs @@ -13,6 +13,18 @@ namespace Contralto return Convert.ToString(i, 8); } + public static string ToOctal(sbyte s) + { + if (s < 0) + { + return "-" + Convert.ToString(-s, 8); + } + else + { + return Convert.ToString(s, 8); + } + } + public static string ToOctal(int i, int digits) { string octalString = Convert.ToString(i, 8);