1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-26 20:11:53 +00:00

Fixed: Disk address (KADR) and Disk Data (KDATA) registers behave (more) correctly; in particular record commands hare processed properly and KDATA handles reads/writes more sanely. Fixed checksum calculation; due to above changes microcode now correctly validates checksums and boot progresses to read in an entire track's worth of data before dying with a "check failure" error.

This commit is contained in:
Josh Dersch
2015-11-04 16:49:42 -08:00
parent 39f077bf7a
commit a689b7185a
8 changed files with 134 additions and 84 deletions

View File

@@ -46,8 +46,7 @@ namespace Contralto.CPU
return _cpu._system.DiskController.KSTAT;
case DiskBusSource.ReadKDATA:
ushort kdata = _cpu._system.DiskController.KDATA;
return kdata;
return _cpu._system.DiskController.KDATA;
default:
throw new InvalidOperationException(String.Format("Unhandled bus source {0}", bs));
@@ -61,8 +60,7 @@ namespace Contralto.CPU
switch (df1)
{
case DiskF1.LoadKDATA:
// "The KDATA register is loaded from BUS[0-15]."
Log.Write(LogComponent.DiskController, "KDATA loaded with {0}", OctalHelpers.ToOctal(_busData));
// "The KDATA register is loaded from BUS[0-15]."
_cpu._system.DiskController.KDATA = _busData;
break;
@@ -70,8 +68,7 @@ namespace Contralto.CPU
// "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);
Log.Write(LogComponent.DiskController, "KADR bus data is {0}", OctalHelpers.ToOctal(_busData));
_cpu._system.DiskController.KADR = (ushort)((_busData & 0xff));
break;
case DiskF1.LoadKCOMM:
@@ -89,9 +86,15 @@ namespace Contralto.CPU
case DiskF1.LoadKSTAT:
// "KSTAT[12-15] are loaded from BUS[12-15]. (Actually BUS[13] is ORed onto
// KSTAT[13].)"
// From the schematic (and ucode source, based on the values it actually uses for BUS[13]), BUS[13]
// is also inverted. So there's that, too.
// 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));
// build BUS[12-15] with bit 13 flipped.
int modifiedBusData = (_busData & 0xb) | ((~_busData) & 0x4);
// 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)) | modifiedBusData);
break;
case DiskF1.STROBE:

View File

@@ -282,7 +282,7 @@ namespace Contralto.CPU
case 0x400:
case 0x500:
case 0x600:
// NEG, INC, ADC, SUB, ADD, AND - invert the carry bit
// NEG, INC, ADC, SUB, ADD - invert the carry bit
if (_cpu._aluC0 != 0)
{
carry = (~carry) & 0x1;

View File

@@ -79,11 +79,11 @@
this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.ResetButton = new System.Windows.Forms.Button();
this.RunToNextTaskButton = new System.Windows.Forms.Button();
this.B = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.NovaStep = new System.Windows.Forms.Button();
this.Bkpt = 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();
@@ -481,11 +481,13 @@
//
this._memoryData.AllowUserToAddRows = false;
this._memoryData.AllowUserToDeleteRows = false;
this._memoryData.AllowUserToResizeRows = false;
dataGridViewCellStyle12.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle12;
this._memoryData.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
this._memoryData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._memoryData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.B,
this.Bkpt,
this.Address,
this.Data,
this.Disassembly});
@@ -503,6 +505,7 @@
this._memoryData.Name = "_memoryData";
this._memoryData.ReadOnly = true;
this._memoryData.RowHeadersVisible = false;
this._memoryData.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this._memoryData.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this._memoryData.RowTemplate.Height = 18;
this._memoryData.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
@@ -512,7 +515,9 @@
this._memoryData.ShowRowErrors = false;
this._memoryData.Size = new System.Drawing.Size(279, 273);
this._memoryData.TabIndex = 0;
this._memoryData.VirtualMode = true;
this._memoryData.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.MemoryViewCellClick);
this._memoryData.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(this.OnMemoryCellValueNeeded);
//
// label1
//
@@ -613,21 +618,31 @@
this.RunToNextTaskButton.UseVisualStyleBackColor = true;
this.RunToNextTaskButton.Click += new System.EventHandler(this.RunToNextTaskButton_Click);
//
// B
// NovaStep
//
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;
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);
//
// Bkpt
//
this.Bkpt.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
this.Bkpt.FalseValue = "false";
this.Bkpt.HeaderText = "B";
this.Bkpt.Name = "Bkpt";
this.Bkpt.ReadOnly = true;
this.Bkpt.Resizable = System.Windows.Forms.DataGridViewTriState.False;
this.Bkpt.ToolTipText = "Breakpoint";
this.Bkpt.TrueValue = "true";
this.Bkpt.Width = 20;
//
// Address
//
this.Address.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.Address.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
this.Address.HeaderText = "Addr";
this.Address.MinimumWidth = 16;
this.Address.Name = "Address";
@@ -638,7 +653,7 @@
//
// Data
//
this.Data.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.Data.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.DisplayedCells;
this.Data.HeaderText = "Data";
this.Data.MinimumWidth = 16;
this.Data.Name = "Data";
@@ -656,16 +671,6 @@
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);
@@ -745,10 +750,10 @@
private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn2;
private System.Windows.Forms.Button ResetButton;
private System.Windows.Forms.Button RunToNextTaskButton;
private System.Windows.Forms.DataGridViewCheckBoxColumn B;
private System.Windows.Forms.Button NovaStep;
private System.Windows.Forms.DataGridViewCheckBoxColumn Bkpt;
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

@@ -112,13 +112,7 @@ namespace Contralto
_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++)
{
_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));
}
_diskData.Rows[9].Cells[1].Value = _system.DiskController.RECNO.ToString();
// Find the right source line.
HighlightMicrocodeSourceLine(_system.CPU.CurrentTask.MPC);
@@ -170,15 +164,8 @@ namespace Contralto
_taskData.Rows.Add("0", "0", "0");
}
for (ushort i=0;i<1024;i++)
{
_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)));
}
// TODO: handle extended memory
_memoryData.RowCount = 65536;
_otherRegs.Rows.Add("L", "0");
_otherRegs.Rows.Add("T", "0");
@@ -266,11 +253,55 @@ namespace Contralto
}
}
/// <summary>
/// Fill in memory view on demand.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMemoryCellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
// TODO: handle extended memory
if (e.RowIndex > 65535)
{
// Top of memory, nothing to do
return;
}
switch(_memoryData.Columns[e.ColumnIndex].Name)
{
case "Bkpt":
e.Value = GetNovaBreakpoint((UInt16)e.RowIndex);
break;
case "Address":
e.Value = OctalHelpers.ToOctal(e.RowIndex, 6);
break;
case "Data":
e.Value = OctalHelpers.ToOctal(_system.MemoryBus.DebugReadWord((ushort)e.RowIndex), 6);
break;
case "Disassembly":
e.Value = CPU.Nova.NovaDisassembler.DisassembleInstruction(
(ushort)e.RowIndex,
_system.MemoryBus.DebugReadWord((ushort)e.RowIndex));
break;
}
}
private void ModifyMicrocodeBreakpoint(UInt16 address, bool set)
{
_microcodeBreakpointEnabled[address] = set;
}
private bool GetNovaBreakpoint(UInt16 address)
{
return _novaBreakpointEnabled[address];
}
private void ModifyNovaBreakpoint(UInt16 address, bool set)
{
_novaBreakpointEnabled[address] = set;

View File

@@ -153,7 +153,7 @@
<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">
<metadata name="Bkpt.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">

View File

@@ -196,12 +196,12 @@
213:035000 - LDA 3,AC2+0 ; AC3 gets current DCB address
214:025412 - LDA 1,AC3+12 ; AC1 gets label data (previous disk address)
215:022732 - LDA@ 0,.+-46 ;(147) ; Load AC0 with contents KBLK (check controller status)
216:101014 - MOV# 0,0,SZR ; if zero (error or idle) then go to 199
216:101014 - MOV# 0,0,SZR ; if zero (idle) then go to 220
217:000406 - JMP .+6 ;(225) ; not idle, go to 225
220:021401 - LDA 0,AC3+1
221:101014 - MOV# 0,0,SZR
222:000406 - JMP .+6 ;(230)
223:056724 - STA@ 3,.+-54 ;(147)
220:021401 - LDA 0,AC3+1 ; Load AC3 with next DCB address
221:101014 - MOV# 0,0,SZR ; is this zero?
222:000406 - JMP .+6 ;(230) ; no -- goto 230
223:056724 - STA@ 3,.+-54 ;(147) ; yes - write DCB to KBLK (tell disk controller to execute DCB)
224:000767 - JMP .+-11 ;(213)
225:125014 - MOV# 1,1,SZR ; we get here when the disk controller is not idle; see if prev. addr is zero
@@ -238,7 +238,7 @@
257:161000 - MOV 3,0
260:024765 - LDA 1,.+-13 ;(245)
261:034411 - LDA 3,.+11 ;(272)
262:061005 - BLT
262:061005 - BLT`
263:020757 - LDA 0,.+-21 ;(242)
264:024457 - LDA 1,.+57 ;(343)
265:034663 - LDA 3,.+-115 ;(150)

View File

@@ -28,15 +28,20 @@ namespace Contralto.IO
fs.Close();
}
/// <summary>
/// TODO: this is messy; the read and write sides of KDATA are distinct hardware.
/// According to docs, on a Write, eventually it appears on the Read side during an actual write to the disk
/// but not right away. For now, this never happens (since we don't yet support writing).
/// </summary>
public ushort KDATA
{
get
{
return _kData;
return _kDataRead;
}
set
{
_kData = value;
_kDataWrite = value;
}
}
@@ -49,29 +54,28 @@ namespace Contralto.IO
_recNo = 0;
// "In addition, it causes the head address bit to be loaded from KDATA[13]."
_head = (_kData & 0x4) >> 2;
_head = (_kDataWrite & 0x4) >> 2;
// "0 normally, 1 if the command is to terminate immediately after the correct cylinder
// position is reached (before any data is transferred)."
_dataXfer = (_kAdr & 0x2) != 0x2;
Log.Write(LogComponent.DiskController, "KADR set to {0} (Seal {1}, Header {2}, Label {3}, Data {4}, Xfer {5}, Drive {6})",
Log.Write(LogComponent.DiskController, "KADR set to {0} (Header {1}, Label {2}, Data {3}, Xfer {4}, Drive {5})",
OctalHelpers.ToOctal(_kAdr),
OctalHelpers.ToOctal((_kAdr & 0xff00) >> 8),
OctalHelpers.ToOctal((_kAdr & 0xc0) >> 6),
OctalHelpers.ToOctal((_kAdr & 0x30) >> 4),
OctalHelpers.ToOctal((_kAdr & 0xc) >> 2),
_dataXfer,
_kAdr & 0x1);
Log.Write(LogComponent.DiskController, " Disk Address is C/H/S {0}/{1}/{2}, Drive {3} Restore {4}",
(_kData & 0x0ff8) >> 3,
(_kData & 0x4) >> 2,
(_kData & 0xf000) >> 12,
((_kData & 0x2) >> 1),
(_kData & 0x1));
Log.Write(LogComponent.DiskController, " -Disk Address is C/H/S {0}/{1}/{2}, Drive {3} Restore {4}",
(_kDataWrite & 0x0ff8) >> 3,
_head,
(_kDataWrite & 0xf000) >> 12,
(_kDataWrite & 0x2) >> 1,
(_kDataWrite & 0x1));
Log.Write(LogComponent.DiskController, " Selected disk is {0}", ((_kData & 0x2) >> 1) ^ (_kAdr & 0x1));
Log.Write(LogComponent.DiskController, " -Selected disk is {0}", ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1));
}
}
@@ -187,7 +191,8 @@ namespace Contralto.IO
_sector = 0;
_head = 0;
_kStat = 0;
_kData = 0;
_kDataRead = 0;
_kDataWrite = 0;
_sendAdr = false;
_wdInhib = true;
@@ -229,7 +234,7 @@ namespace Contralto.IO
_sectorWordIndex = 0;
_sectorWordTime = 0.0;
_kData = 13;
_kDataRead = 0;
// Load new sector in
LoadSector();
@@ -326,7 +331,7 @@ namespace Contralto.IO
Log.Write(LogComponent.DiskController, "STROBE: Seek initialized.");
_destCylinder = (_kData & 0x0ff8) >> 3;
_destCylinder = (_kDataWrite & 0x0ff8) >> 3;
// set "seek fail" bit based on selected cylinder (if out of bounds) and do not
// commence a seek if so.
@@ -428,8 +433,8 @@ namespace Contralto.IO
{
if (!_xferOff)
{
Log.Write(LogComponent.DiskWordTask, "Word {0} read into KDATA", OctalHelpers.ToOctal(diskWord));
_kData = diskWord;
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, OctalHelpers.ToOctal(diskWord));
_kDataRead = diskWord;
}
if (!_wdInhib)
@@ -451,7 +456,7 @@ namespace Contralto.IO
if (bWakeup)
{
Log.Write(LogComponent.DiskWordTask, "Sector task awoken.");
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Word task awoken.");
_system.CPU.WakeupTask(CPU.TaskType.DiskWord);
}
@@ -477,7 +482,9 @@ namespace Contralto.IO
_sectorData[i] = new DataCell(sector.Header[j], CellType.Data);
}
_sectorData[_headerOffset + 3].Data = CalculateChecksum(_sectorData, _headerOffset + 1, 2);
ushort checksum = CalculateChecksum(_sectorData, _headerOffset + 1, 2);
_sectorData[_headerOffset + 3].Data = checksum;
Log.Write(LogType.Verbose, LogComponent.DiskController, "Header checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, OctalHelpers.ToOctal(checksum));
// Label (8 words data, 1 word cksum)
for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
@@ -486,7 +493,9 @@ namespace Contralto.IO
_sectorData[i] = new DataCell(sector.Label[j], CellType.Data);
}
_sectorData[_labelOffset + 9].Data = CalculateChecksum(_sectorData, _labelOffset + 1, 8);
checksum = CalculateChecksum(_sectorData, _labelOffset + 1, 8);
_sectorData[_labelOffset + 9].Data = checksum;
Log.Write(LogType.Verbose, LogComponent.DiskController, "Label checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, OctalHelpers.ToOctal(checksum));
// sector data (256 words data, 1 word cksum)
for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
@@ -495,7 +504,9 @@ namespace Contralto.IO
_sectorData[i] = new DataCell(sector.Data[j], CellType.Data);
}
_sectorData[_dataOffset + 257].Data = CalculateChecksum(_sectorData, _dataOffset + 1, 256);
checksum = CalculateChecksum(_sectorData, _dataOffset + 1, 256);
_sectorData[_dataOffset + 257].Data = checksum;
Log.Write(LogType.Verbose, LogComponent.DiskController, "Data checksum for C/H/S {0}/{1}/{2} is {3}", _cylinder, _head, _sector, OctalHelpers.ToOctal(checksum));
}
@@ -542,7 +553,7 @@ namespace Contralto.IO
//
ushort checksum = 0x151;
for(int i = offset; i < length;i++)
for(int i = offset; i < offset + length;i++)
{
// Sanity check that we're checksumming actual data
if (sectorData[i].Type != CellType.Data)
@@ -556,7 +567,8 @@ namespace Contralto.IO
return checksum;
}
private ushort _kData;
private ushort _kDataRead;
private ushort _kDataWrite;
private ushort _kAdr;
private ushort _kCom;
private ushort _kStat;

View File

@@ -25,8 +25,7 @@ namespace Contralto.Memory
}
public void Load(int address, ushort data)
{
//Log.Write(LogComponent.DiskWordTask, "Word {0} written to {1}", OctalHelpers.ToOctal(data), OctalHelpers.ToOctal(address));
{
_mem[address] = data;
}