1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-18 00:52:47 +00:00

Some fixes to emulator task dispatch functions, added Nova disassembler, nova instruction single-step and nova instruction breakpoint support. Penciled in DNS (Nova Shift) support in emulator task. Added skeleton for Logging.

This commit is contained in:
Josh Dersch 2015-10-28 14:11:04 -07:00
parent 1dfd1e0be9
commit 2918ede7ce
16 changed files with 628 additions and 215 deletions

View File

@ -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 =

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Contralto.CPU
namespace Contralto.CPU.Nova
{
/// <summary>
/// Quick and dirty disassembler for Nova instructions, so we can
@ -12,6 +12,324 @@ namespace Contralto.CPU
/// </summary>
public static class NovaDisassembler
{
/// <summary>
/// Disassembles the specified instruction
/// </summary>
/// <param name="instructionWord"></param>
/// <returns></returns>
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,
}
}
}

View File

@ -47,6 +47,16 @@ namespace Contralto.CPU
_magic = magic;
}
/// <summary>
/// TODO: this is still kind of clumsy.
/// </summary>
/// <param name="dns"></param>
public static void SetDNS(bool dns)
{
_dns = dns;
}
/// <summary>
/// Does the last specified operation to the specified inputs
/// </summary>
@ -55,6 +65,12 @@ namespace Contralto.CPU
/// <returns></returns>
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;
}
}

View File

@ -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:

View File

@ -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;
}
}

View File

@ -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

View File

@ -65,6 +65,7 @@
<Compile Include="IO\DiskController.cs" />
<Compile Include="IO\DiabloPack.cs" />
<Compile Include="IO\Keyboard.cs" />
<Compile Include="Logging\Log.cs" />
<Compile Include="Memory\IMemoryMappedDevice.cs" />
<Compile Include="Memory\Memory.cs" />
<Compile Include="Memory\MemoryBus.cs" />
@ -78,9 +79,15 @@
<None Include="Disassembly\altoIIcode3.mu">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\diag.dsk">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Disk\games.dsk">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Disk\tdisk4.dsk">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="ROM\2kctl.u3">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@ -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;
}
}

View File

@ -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
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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;
}

View File

@ -153,22 +153,22 @@
<metadata name="RegValue.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="B.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Address.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Data.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Disassembly.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dataGridViewTextBoxColumn1.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dataGridViewTextBoxColumn2.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dataGridViewTextBoxColumn3.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="dataGridViewTextBoxColumn4.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

BIN
Contralto/Disk/diag.dsk Normal file

Binary file not shown.

BIN
Contralto/Disk/tdisk4.dsk Normal file

Binary file not shown.

View File

@ -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.");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);