diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs
index c88aafc..75b6bca 100644
--- a/Contralto/CPU/CPU.cs
+++ b/Contralto/CPU/CPU.cs
@@ -146,6 +146,15 @@ namespace Contralto.CPU
}
}
+ ///
+ /// Used by the debugger to determine if a task switch is taking
+ /// place.
+ ///
+ public Task NextTask
+ {
+ get { return _nextTask; }
+ }
+
private void ExecuteNext()
{
if (_currentTask.ExecuteNext())
diff --git a/Contralto/CPU/Tasks/DiskTask.cs b/Contralto/CPU/Tasks/DiskTask.cs
index 6ac9da2..7f39f8d 100644
--- a/Contralto/CPU/Tasks/DiskTask.cs
+++ b/Contralto/CPU/Tasks/DiskTask.cs
@@ -23,6 +23,18 @@ namespace Contralto.CPU
_wakeup = false;
}
+ public override void WakeupTask()
+ {
+ base.WakeupTask();
+ }
+
+ protected override bool ExecuteInstruction(MicroInstruction instruction)
+ {
+ bool task = base.ExecuteInstruction(instruction);
+
+ return task;
+ }
+
protected override ushort GetBusSource(int bs)
{
DiskBusSource dbs = (DiskBusSource)bs;
@@ -33,6 +45,7 @@ namespace Contralto.CPU
return _cpu._system.DiskController.KSTAT;
case DiskBusSource.ReadKDATA:
+ Console.WriteLine("kdata read");
return _cpu._system.DiskController.KDATA;
default:
@@ -40,9 +53,9 @@ namespace Contralto.CPU
}
}
- protected override void ExecuteSpecialFunction1(int f1)
+ protected override void ExecuteSpecialFunction1(MicroInstruction instruction)
{
- DiskF1 df1 = (DiskF1)f1;
+ DiskF1 df1 = (DiskF1)instruction.F1;
switch (df1)
{
@@ -87,25 +100,15 @@ namespace Contralto.CPU
}
}
- protected override void ExecuteSpecialFunction2(int f2)
+ protected override void ExecuteSpecialFunction2(MicroInstruction instruction)
{
- DiskF2 df2 = (DiskF2)f2;
+ DiskF2 df2 = (DiskF2)instruction.F2;
switch (df2)
{
- case DiskF2.INIT:
- // "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0
- // TODO: figure out how WDTASKACT and WDINIT work.
-
- // From the US Patent (4148098):
- // "..two multiplexers...allow the setting of the next field bits NEXT(05)-NEXT(09)
- // to 1 after an error condition is detected and as soon as the word task active signal
- // WDTASKACT is generated..."
-
- // Is this always an error condition?
- Console.WriteLine("Warning: assuming 0 for Disk F2 INIT (unimplemented stub)");
- break;
-
+ case DiskF2.INIT:
+ _nextModifier |= GetInitModifier(instruction);
+ break;
case DiskF2.RWC:
// "NEXT<-NEXT OR (IF current record to be written THEN 3 ELSE IF
@@ -114,7 +117,9 @@ namespace Contralto.CPU
// by INCREC by the microcode to present the next set of bits.
int command = (_cpu._system.DiskController.KADR & 0x00c0) >> 6;
- switch(command)
+ _nextModifier |= GetInitModifier(instruction);
+
+ switch (command)
{
case 0:
// read, no modification.
@@ -135,8 +140,8 @@ namespace Contralto.CPU
case DiskF2.XFRDAT:
// "NEXT <- NEXT OR (IF current command wants data transfer THEN 1 ELSE 0)
- // TODO: need to get unshifted bit 14 of the command register. Disk controller should
- // save this off somewhere.
+ _nextModifier |= GetInitModifier(instruction);
+
if (_cpu._system.DiskController.DataXfer)
{
_nextModifier |= 0x1;
@@ -144,17 +149,20 @@ namespace Contralto.CPU
break;
case DiskF2.RECNO:
+ _nextModifier |= GetInitModifier(instruction);
_nextModifier |= _cpu._system.DiskController.RECNO;
break;
case DiskF2.NFER:
// "NEXT <- NEXT OR (IF fatal error in latches THEN 0 ELSE 1)"
// We assume success for now...
+ _nextModifier |= GetInitModifier(instruction);
_nextModifier |= 0x1;
break;
case DiskF2.STROBON:
// "NEXT <- NEXT OR (IF seek strobe still on THEN 1 ELSE 0)"
+ _nextModifier |= GetInitModifier(instruction);
if ((_cpu._system.DiskController.KSTAT & 0x0040) == 0x0040)
{
_nextModifier |= 0x1;
@@ -164,13 +172,39 @@ namespace Contralto.CPU
case DiskF2.SWRNRDY:
// "NEXT <- NEXT OR (IF disk not ready to accept command THEN 1 ELSE 0)
// for now, always zero (not sure when this would be 1 yet)
+ _nextModifier |= GetInitModifier(instruction);
break;
default:
throw new InvalidOperationException(String.Format("Unhandled disk special function 2 {0}", df2));
}
}
- }
+ ///
+ /// The status of the INIT flag
+ ///
+ ///
+ private ushort GetInitModifier(MicroInstruction instruction)
+ {
+ //
+ // "NEXT<-NEXT OR (if WDTASKACT AND WDINIT) then 37B else 0."
+ //
+
+ //
+ // A brief discussion of the INIT signal since it isn't really covered in the Alto Hardware docs in any depth
+ // (and in fact is completely skipped over in the description of RWC, a rather important detail!)
+ // This is where the Alto ref's suggestion to have the uCode *and* the schematic on hand is really quite a
+ // valid recommendation.
+ //
+ // WDINIT is initially set whenever the WDINHIB bit (set via KCOM<-) is cleared (this is the WDALLOW signal).
+ // This signals that the microcode is "INITializing" a data transfer (so to speak). During this period,
+ // INIT or RWC instructions in the Disk Word task will OR in 37B to the Next field, causing the uCode to jump
+ // to the requisite initialization paths. WDINIT is cleared whenever a BLOCK instruction occurs during the Disk Word task,
+ // causing INIT to OR in 0 and RWC to or in 0, 2 or 3 (For read, check, or write respectively.)
+ //
+
+ return (_taskType == TaskType.DiskWord && _cpu._system.DiskController.WDINIT) ? (ushort)0x1f : (ushort)0x0;
+ }
+ }
}
}
diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs
index 4139ca7..65b4d09 100644
--- a/Contralto/CPU/Tasks/EmulatorTask.cs
+++ b/Contralto/CPU/Tasks/EmulatorTask.cs
@@ -51,9 +51,9 @@ namespace Contralto.CPU
}
}
- protected override void ExecuteSpecialFunction1(int f1)
+ protected override void ExecuteSpecialFunction1(MicroInstruction instruction)
{
- EmulatorF1 ef1 = (EmulatorF1)f1;
+ EmulatorF1 ef1 = (EmulatorF1)instruction.F1;
switch (ef1)
{
case EmulatorF1.RSNF:
@@ -79,9 +79,9 @@ namespace Contralto.CPU
}
}
- protected override void ExecuteSpecialFunction2Early(int f2)
+ protected override void ExecuteSpecialFunction2Early(MicroInstruction instruction)
{
- EmulatorF2 ef2 = (EmulatorF2)f2;
+ EmulatorF2 ef2 = (EmulatorF2)instruction.F2;
switch (ef2)
{
case EmulatorF2.ACSOURCE:
@@ -102,9 +102,9 @@ namespace Contralto.CPU
}
}
- protected override void ExecuteSpecialFunction2(int f2)
+ protected override void ExecuteSpecialFunction2(MicroInstruction instruction)
{
- EmulatorF2 ef2 = (EmulatorF2)f2;
+ EmulatorF2 ef2 = (EmulatorF2)instruction.F2;
switch (ef2)
{
case EmulatorF2.LoadIR:
diff --git a/Contralto/CPU/Tasks/Task.cs b/Contralto/CPU/Tasks/Task.cs
index d1a9a9f..5911fee 100644
--- a/Contralto/CPU/Tasks/Task.cs
+++ b/Contralto/CPU/Tasks/Task.cs
@@ -22,6 +22,8 @@ namespace Contralto.CPU
_mpc = 0xffff; // invalid, for sanity checking
_taskType = TaskType.Invalid;
_cpu = cpu;
+
+ _block = false;
}
public int Priority
@@ -39,6 +41,15 @@ namespace Contralto.CPU
get { return _mpc; }
}
+ ///
+ /// Indicates whether the current uInstruction asserts BLOCK.
+ /// Used by hardware for various tasks.
+ ///
+ public bool BLOCK
+ {
+ get { return _block; }
+ }
+
public virtual void Reset()
{
// From The Alto Hardware Manual (section 2, "Initialization"):
@@ -61,6 +72,7 @@ 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]);
+ _block = instruction.F1 == SpecialFunction1.Block;
return ExecuteInstruction(instruction);
}
@@ -122,7 +134,7 @@ namespace Contralto.CPU
_rSelect = instruction.RSELECT;
// Give tasks the chance to modify parameters early on (like RSELECT)
- ExecuteSpecialFunction2Early((int)instruction.F2);
+ ExecuteSpecialFunction2Early(instruction);
// Select BUS data.
if (instruction.F1 != SpecialFunction1.Constant &&
@@ -253,7 +265,7 @@ namespace Contralto.CPU
default:
// Let the specific task implementation take a crack at this.
- ExecuteSpecialFunction1((int)instruction.F1);
+ ExecuteSpecialFunction1(instruction);
break;
}
@@ -314,7 +326,7 @@ namespace Contralto.CPU
default:
// Let the specific task implementation take a crack at this.
- ExecuteSpecialFunction2((int)instruction.F2);
+ ExecuteSpecialFunction2(instruction);
break;
}
@@ -372,18 +384,18 @@ namespace Contralto.CPU
}
protected abstract ushort GetBusSource(int bs);
- protected abstract void ExecuteSpecialFunction1(int f1);
+ protected abstract void ExecuteSpecialFunction1(MicroInstruction instruction);
///
/// Used to allow Task-specific F2s that need to modify RSELECT to do so.
///
///
- protected virtual void ExecuteSpecialFunction2Early(int f2)
+ protected virtual void ExecuteSpecialFunction2Early(MicroInstruction instruction)
{
// Nothing by default.
}
- protected abstract void ExecuteSpecialFunction2(int f2);
+ protected abstract void ExecuteSpecialFunction2(MicroInstruction instruction);
//
// Per uInstruction Task Data:
@@ -405,6 +417,8 @@ namespace Contralto.CPU
protected TaskType _taskType;
protected bool _wakeup;
+ protected bool _block;
+
// Emulator Task-specific data. This is placed here because it is used by the ALU and it's easier to reference in the
// base class even if it does break encapsulation. See notes in the EmulatorTask class for meaning.
protected int _skip;
diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs
index 3fb3032..3c21969 100644
--- a/Contralto/Debugger.Designer.cs
+++ b/Contralto/Debugger.Designer.cs
@@ -43,7 +43,11 @@
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();
this._sourceViewer = new System.Windows.Forms.DataGridView();
this.Breakpoint = new System.Windows.Forms.DataGridViewCheckBoxColumn();
this.T = new System.Windows.Forms.DataGridViewTextBoxColumn();
@@ -73,12 +77,16 @@
this.Data = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.label1 = new System.Windows.Forms.Label();
this.ExecutionStateLabel = new System.Windows.Forms.Label();
- this.JumpToAddress = new System.Windows.Forms.TextBox();
- this.label2 = new System.Windows.Forms.Label();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this._diskData = new System.Windows.Forms.DataGridView();
this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.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.Microcode.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this._sourceViewer)).BeginInit();
this.groupBox1.SuspendLayout();
@@ -91,6 +99,8 @@
((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
@@ -105,6 +115,23 @@
this.Microcode.TabStop = false;
this.Microcode.Text = "Microcode Source";
//
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(11, 599);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(47, 13);
+ this.label2.TabIndex = 13;
+ this.label2.Text = "Jump to:";
+ //
+ // JumpToAddress
+ //
+ this.JumpToAddress.Location = new System.Drawing.Point(59, 596);
+ this.JumpToAddress.Name = "JumpToAddress";
+ this.JumpToAddress.Size = new System.Drawing.Size(48, 20);
+ this.JumpToAddress.TabIndex = 12;
+ this.JumpToAddress.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnJumpAddressKeyDown);
+ //
// _sourceViewer
//
this._sourceViewer.AllowUserToAddRows = false;
@@ -294,7 +321,7 @@
//
this.RunButton.Location = new System.Drawing.Point(103, 954);
this.RunButton.Name = "RunButton";
- this.RunButton.Size = new System.Drawing.Size(53, 23);
+ this.RunButton.Size = new System.Drawing.Size(41, 23);
this.RunButton.TabIndex = 5;
this.RunButton.Text = "Run";
this.RunButton.UseVisualStyleBackColor = true;
@@ -302,9 +329,9 @@
//
// StopButton
//
- this.StopButton.Location = new System.Drawing.Point(164, 954);
+ this.StopButton.Location = new System.Drawing.Point(207, 954);
this.StopButton.Name = "StopButton";
- this.StopButton.Size = new System.Drawing.Size(49, 23);
+ this.StopButton.Size = new System.Drawing.Size(43, 23);
this.StopButton.TabIndex = 6;
this.StopButton.Text = "Stop";
this.StopButton.UseVisualStyleBackColor = true;
@@ -524,27 +551,10 @@
this.ExecutionStateLabel.TabIndex = 10;
this.ExecutionStateLabel.Text = "unset";
//
- // JumpToAddress
- //
- this.JumpToAddress.Location = new System.Drawing.Point(59, 596);
- this.JumpToAddress.Name = "JumpToAddress";
- this.JumpToAddress.Size = new System.Drawing.Size(48, 20);
- this.JumpToAddress.TabIndex = 12;
- this.JumpToAddress.KeyDown += new System.Windows.Forms.KeyEventHandler(this.OnJumpAddressKeyDown);
- //
- // label2
- //
- this.label2.AutoSize = true;
- this.label2.Location = new System.Drawing.Point(11, 599);
- this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(47, 13);
- this.label2.TabIndex = 13;
- this.label2.Text = "Jump to:";
- //
// groupBox5
//
this.groupBox5.Controls.Add(this._diskData);
- this.groupBox5.Location = new System.Drawing.Point(3, 634);
+ this.groupBox5.Location = new System.Drawing.Point(150, 634);
this.groupBox5.Name = "groupBox5";
this.groupBox5.Size = new System.Drawing.Size(163, 298);
this.groupBox5.TabIndex = 11;
@@ -602,11 +612,97 @@
this.dataGridViewTextBoxColumn2.Name = "dataGridViewTextBoxColumn2";
this.dataGridViewTextBoxColumn2.ReadOnly = true;
//
+ // ResetButton
+ //
+ this.ResetButton.Location = new System.Drawing.Point(256, 955);
+ this.ResetButton.Name = "ResetButton";
+ this.ResetButton.Size = new System.Drawing.Size(57, 23);
+ this.ResetButton.TabIndex = 12;
+ this.ResetButton.Text = "Reset";
+ 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);
+ this.RunToNextTaskButton.Name = "RunToNextTaskButton";
+ this.RunToNextTaskButton.Size = new System.Drawing.Size(51, 23);
+ this.RunToNextTaskButton.TabIndex = 13;
+ this.RunToNextTaskButton.Text = "Run T";
+ this.RunToNextTaskButton.UseVisualStyleBackColor = true;
+ this.RunToNextTaskButton.Click += new System.EventHandler(this.RunToNextTaskButton_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.RunToNextTaskButton);
+ this.Controls.Add(this.groupBox6);
+ this.Controls.Add(this.ResetButton);
this.Controls.Add(this.groupBox5);
this.Controls.Add(this.ExecutionStateLabel);
this.Controls.Add(this.label1);
@@ -635,6 +731,8 @@
((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();
@@ -678,5 +776,11 @@
private System.Windows.Forms.DataGridView _diskData;
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;
}
}
\ No newline at end of file
diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs
index 31cecc1..5d8ebc4 100644
--- a/Contralto/Debugger.cs
+++ b/Contralto/Debugger.cs
@@ -37,7 +37,7 @@ namespace Contralto
StreamReader sr = new StreamReader(path);
- while(!sr.EndOfStream)
+ while (!sr.EndOfStream)
{
string line = sr.ReadLine();
@@ -45,12 +45,12 @@ namespace Contralto
int i = _sourceViewer.Rows.Add(
false, // breakpoint
- GetTextForTask(src.Task),
- src.Address,
+ GetTextForTask(src.Task),
+ src.Address,
src.Text);
// Give the row a color based on the task
- _sourceViewer.Rows[i].DefaultCellStyle.BackColor = GetColorForTask(src.Task);
+ _sourceViewer.Rows[i].DefaultCellStyle.BackColor = GetColorForTask(src.Task);
// Tag the row based on the PROM address (if any) to make it easy to find.
if (!String.IsNullOrEmpty(src.Address))
@@ -97,7 +97,7 @@ namespace Contralto
_otherRegs.Rows[4].Cells[1].Value = OctalHelpers.ToOctal(_system.CPU.ALUC0, 1);
_otherRegs.Rows[5].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MAR, 6);
_otherRegs.Rows[6].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.MD, 6);
- _otherRegs.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.Cycle, 2);
+ _otherRegs.Rows[7].Cells[1].Value = OctalHelpers.ToOctal(_system.MemoryBus.Cycle & 0x3f, 2);
// Disk info
_diskData.Rows[0].Cells[1].Value = _system.DiskController.ClocksUntilNextSector.ToString("0.00");
@@ -182,6 +182,11 @@ namespace Contralto
_diskData.Rows.Add("KSTAT", "0");
_diskData.Rows.Add("RECNO", "0");
+ for (int i=0;i<16;i++)
+ {
+ _debugTasks.Rows.Add(true, GetTextForTask((TaskType)i));
+ }
+
}
///
@@ -492,6 +497,20 @@ namespace Contralto
}
}
+ private void RunToNextTaskButton_Click(object sender, EventArgs e)
+ {
+ //
+ // Continuously execute until the next task switch but do not update UI
+ // until the "Stop" button is pressed or something bad happens.
+ //
+ //if (_execThread == null)
+ {
+ _execThread = new Thread(new System.Threading.ParameterizedThreadStart(ExecuteProc));
+ _execThread.Start(ExecutionType.NextTask);
+ SetExecutionState(ExecutionState.Running);
+ }
+ }
+
private void OnStopButtonClicked(object sender, EventArgs e)
{
if (_execThread != null &&
@@ -509,6 +528,11 @@ namespace Contralto
SetExecutionState(ExecutionState.Stopped);
}
+ private void ResetButton_Click(object sender, EventArgs e)
+ {
+ _system.Reset();
+ }
+
private void ExecuteStep()
{
_system.SingleStep();
@@ -522,25 +546,34 @@ namespace Contralto
StepDelegate refUI = new StepDelegate(RefreshUI);
StepDelegate inv = new StepDelegate(Invalidate);
while (true)
- {
- if (execType == ExecutionType.Auto)
+ {
+ switch (execType)
{
- // Execute a single step, then update UI and
- // sleep to give messages time to run.
- _system.SingleStep();
-
- this.BeginInvoke(refUI);
- this.BeginInvoke(inv);
- System.Threading.Thread.Sleep(10);
- }
- else
- {
- // Just execute one step, do not update UI.
- _system.SingleStep();
+ 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;
+
+ case ExecutionType.Step:
+ case ExecutionType.Normal:
+ case ExecutionType.NextTask:
+ {
+ // Just execute one step, do not update UI.
+ _system.SingleStep();
+ }
+ break;
}
if (_execAbort ||
- _breakpointEnabled[_system.CPU.CurrentTask.MPC])
+ _breakpointEnabled[_system.CPU.CurrentTask.MPC] ||
+ (execType == ExecutionType.NextTask && _system.CPU.NextTask != null && _system.CPU.NextTask != _system.CPU.CurrentTask))
{
// Stop here as we've hit a breakpoint or have been stopped Update UI
// to indicate where we stopped.
@@ -571,6 +604,7 @@ namespace Contralto
Step,
Auto,
Normal,
+ NextTask,
}
private enum ExecutionState
diff --git a/Contralto/Debugger.resx b/Contralto/Debugger.resx
index 1689f08..5a5826b 100644
--- a/Contralto/Debugger.resx
+++ b/Contralto/Debugger.resx
@@ -165,4 +165,10 @@
True
+
+ True
+
+
+ True
+
\ No newline at end of file
diff --git a/Contralto/Disassembly/altoIIcode3.mu b/Contralto/Disassembly/altoIIcode3.mu
index 372847c..e2f99f7 100644
--- a/Contralto/Disassembly/altoIIcode3.mu
+++ b/Contralto/Disassembly/altoIIcode3.mu
@@ -1947,7 +1947,7 @@ KW01710> MAR<-DCBR+T+1, :REC0RC;
; INIT MAPS REC0RC TO KWD
KW01722> REC0RC: T<-MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY
-KE01723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
+KW01723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
KW01714> REC1: L<-10, INCRECNO; LENGTH OF RECORD 1
KW01715> T<-4, :REC12;
diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs
index ba4a88c..87cf758 100644
--- a/Contralto/IO/DiskController.cs
+++ b/Contralto/IO/DiskController.cs
@@ -21,7 +21,10 @@ namespace Contralto.IO
public ushort KDATA
{
- get { return _kData; }
+ get
+ {
+ return _kData;
+ }
set { _kData = value; }
}
@@ -56,17 +59,43 @@ namespace Contralto.IO
_wffo = (_kCom & 0x02) == 0x02;
_sendAdr = (_kCom & 0x01) == 0x01;
- if (!_wdInhib && !_xferOff)
+ Console.WriteLine(
+ "sst {0}, xferOff {1}, wdInhib {2}, bClkSource {3}, wffo {4}, sendAdr {5}",
+ _elapsedSectorStateTime,
+ _xferOff,
+ _wdInhib,
+ _bClkSource,
+ _wffo,
+ _sendAdr);
+
+ // Update WDINIT state based on _wdInhib.
+ if (_wdInhib)
{
- Console.WriteLine("enabled at sst {0}", _elapsedSectorStateTime);
+ _wdInit = true;
}
}
}
+ ///
+ /// Used by the DiskTask code to check the WDINIT signal for dispatch.
+ ///
+ public bool WDINIT
+ {
+ get { return _wdInit; }
+ }
+
public ushort KSTAT
{
- get { return _kStat; }
- set { _kStat = value; }
+ get
+ {
+ Console.WriteLine("kstat read {0}", _kStat);
+ return _kStat;
+ }
+ set
+ {
+ _kStat = value;
+ Console.WriteLine("kstat write {0}", _kStat);
+ }
}
public ushort RECNO
@@ -79,6 +108,14 @@ namespace Contralto.IO
get { return _dataXfer; }
}
+ ///
+ /// This is a hack to see how the microcode expects INIT to work
+ ///
+ public bool RecordInit
+ {
+ get { return _elapsedSectorStateTime < 10; }
+ }
+
public int Cylinder
{
get { return _cylinder; }
@@ -121,6 +158,8 @@ namespace Contralto.IO
_wdInhib = true;
_xferOff = true;
+
+ _wdInit = false;
}
public void Clock()
@@ -140,11 +179,15 @@ namespace Contralto.IO
_kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12));
+ // TODO: seclate semantics. Looks like if the sector task was BLOCKed when a new sector is signaled
+ // then the seclate flag is set.
+
// Reset internal state machine for sector data
- _sectorState = SectorState.Leadin;
+ _sectorState = SectorState.HeaderReadDelay;
_sectorWordIndex = 0;
_elapsedSectorStateTime = 0.0;
- Console.WriteLine("New sector ({0}), switching to LeadIn state.", _sector);
+ Console.WriteLine("New sector ({0}), switching to HeaderReadDelay state.", _sector);
+ _kData = 13;
_system.CPU.WakeupTask(CPU.TaskType.DiskSector);
@@ -196,127 +239,177 @@ namespace Contralto.IO
// that is, the microcode expects to be woken up on a per-word basis, and it only reads in one word
// per wakeup.
//
- // pseudocode so far:
- // if (elapsed word time > word time)
- // {
- // elapsed word time = 0 (modulo remainder)
- // _kData = next word
- // if (!_wdInhib) DiskSectorTask.Wakeup();
- // }
- _elapsedSectorStateTime++;
- switch(_sectorState)
+
+
+ if (!_wdInhib)
{
- case SectorState.Leadin:
- if (_elapsedSectorStateTime > _leadinDuration)
- {
- _elapsedSectorStateTime -= _leadinDuration;
- _sectorState = SectorState.Header;
- Console.WriteLine("Switching to Header state.");
- }
- break;
+
+ _elapsedSectorStateTime++;
- case SectorState.Header:
- if (_sectorWordIndex > 1) // two words
- {
- _elapsedSectorStateTime -= 2.0 * _wordDuration;
- _sectorState = SectorState.HeaderGap;
- _sectorWordIndex = 0;
- Console.WriteLine("Switching to HeaderGap state.");
- }
- else if (_elapsedSectorStateTime > _wordDuration)
- {
- _elapsedSectorStateTime -= _wordDuration;
-
- // Put next word into KDATA if not inhibited from doing so.
- if (!_xferOff)
- {
- _kData = 0xdead; // placeholder
- Console.WriteLine(" Header word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
- }
- _sectorWordIndex++;
-
- if (!_wdInhib)
+ switch (_sectorState)
+ {
+ case SectorState.HeaderReadDelay:
+ if (_sectorWordIndex > 19)
{
+ _sectorState = SectorState.Header;
+ _sectorWordIndex = 0;
+ Console.WriteLine("Switching to HeaderPreamble state.");
+ _kData = 1;
+ }
+ else if (_elapsedSectorStateTime > _wordDuration)
+ {
+ _elapsedSectorStateTime -= _wordDuration;
+
+ _sectorWordIndex++;
+
+ _kData = 0xfefe; // unused, just for debugging
+
_system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ Console.WriteLine("delay wakeup");
+
}
- }
- break;
+ break;
- case SectorState.HeaderGap:
- if (_elapsedSectorStateTime > _headerGapDuration)
- {
- _elapsedSectorStateTime -= _headerGapDuration;
- _sectorState = SectorState.Label;
- Console.WriteLine("Switching to Label state.");
- }
- break;
-
- case SectorState.Label:
- if (_sectorWordIndex > 7) // eight words
- {
- _elapsedSectorStateTime -= 8.0 * _wordDuration;
- _sectorState = SectorState.LabelGap;
- _sectorWordIndex = 0;
- Console.WriteLine("Switching to LabelGap state.");
- }
- else if(_elapsedSectorStateTime > _wordDuration)
- {
- _elapsedSectorStateTime -= _wordDuration;
- // Put next word into KDATA if not inhibited from doing so.
- if (!_xferOff)
+ case SectorState.HeaderPreamble:
+ if (_sectorWordIndex > 32)
{
- _kData = 0xbeef; // placeholder
- Console.WriteLine(" Label word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
+ _sectorState = SectorState.Header;
+ _sectorWordIndex = 0;
+ Console.WriteLine("Switching to Header state.");
+ _kData = 2;
}
- _sectorWordIndex++;
-
- if (!_wdInhib)
+ else if (_elapsedSectorStateTime > _wordDuration)
{
+ _elapsedSectorStateTime -= _wordDuration;
+
+ _sectorWordIndex++;
+
+ _kData = 0xfeff; // unused, just for debugging
_system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ Console.WriteLine("preamble wakeup");
}
- }
- break;
+ break;
- case SectorState.LabelGap:
- if (_elapsedSectorStateTime > _labelGapDuration)
- {
- _elapsedSectorStateTime -= _labelGapDuration;
- _sectorState = SectorState.Data;
- Console.WriteLine("Switching to Data state.");
- }
- break;
-
- case SectorState.Data:
- if (_sectorWordIndex > 255) // 256 words
- {
- _elapsedSectorStateTime -= 256.0 * _wordDuration;
- _sectorState = SectorState.Leadout;
- _sectorWordIndex = 0;
- Console.WriteLine("Switching to Leadout state.");
- }
- else if (_elapsedSectorStateTime > _wordDuration)
- {
- _elapsedSectorStateTime -= _wordDuration;
- // Put next word into KDATA if not inhibited from doing so.
- if (!_xferOff)
+ case SectorState.Header:
+ if (_sectorWordIndex > 2) // two words + sync
{
- _kData = 0xda1a; // placeholder
- Console.WriteLine(" Sector word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
+ //_elapsedSectorStateTime -= 2.0 * _wordDuration;
+ _sectorState = SectorState.HeaderInterrecord;
+ _sectorWordIndex = 0;
+ Console.WriteLine("Switching to HeaderGap state.");
+ _kData = 3;
}
- _sectorWordIndex++;
-
- if (!_wdInhib)
+ else if (_elapsedSectorStateTime > _wordDuration)
{
- _system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ _elapsedSectorStateTime -= _wordDuration;
+
+ // Put next word into KDATA if not inhibited from doing so.
+ if (!_xferOff)
+ {
+ _kData = 0xdead; // placeholder
+ Console.WriteLine(" Header word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
+ }
+ _sectorWordIndex++;
+
+ if (!_wdInhib)
+ {
+ Console.WriteLine("header wakeup");
+ _system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ }
}
- }
- break;
+ break;
- case SectorState.Leadout:
- // Just stay here forever. We will get reset at the start of the next sector.
- break;
+ case SectorState.HeaderInterrecord:
+ if (_elapsedSectorStateTime > _interRecordDelay)
+ {
+ _elapsedSectorStateTime -= _interRecordDelay;
+ _sectorState = SectorState.Label;
+ Console.WriteLine("Switching to Label state.");
+ _kData = 4;
+ }
+ break;
+ case SectorState.Label:
+ if (_sectorWordIndex > 8) // eight words + sync
+ {
+ //_elapsedSectorStateTime -= 8.0 * _wordDuration;
+ _sectorState = SectorState.LabelInterrecord;
+ _sectorWordIndex = 0;
+ Console.WriteLine("Switching to LabelGap state.");
+ _kData = 5;
+ }
+ else if (_elapsedSectorStateTime > _wordDuration)
+ {
+ _elapsedSectorStateTime -= _wordDuration;
+ // Put next word into KDATA if not inhibited from doing so.
+ if (!_xferOff)
+ {
+ _kData = 0xbeef; // placeholder
+ Console.WriteLine(" Label word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
+ }
+ _sectorWordIndex++;
+
+ if (!_wdInhib)
+ {
+ _system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ }
+ }
+ break;
+
+ case SectorState.LabelInterrecord:
+ if (_elapsedSectorStateTime > _interRecordDelay)
+ {
+ _elapsedSectorStateTime -= _interRecordDelay;
+ _sectorState = SectorState.Data;
+ Console.WriteLine("Switching to Data state.");
+ _kData = 6;
+ }
+ break;
+
+ case SectorState.Data:
+ if (_sectorWordIndex > 256) // 256 words + sync
+ {
+ //_elapsedSectorStateTime -= 256.0 * _wordDuration;
+ _sectorState = SectorState.Postamble;
+ _sectorWordIndex = 0;
+ Console.WriteLine("Switching to Leadout state.");
+ _kData = 7;
+ }
+ else if (_elapsedSectorStateTime > _wordDuration)
+ {
+ _elapsedSectorStateTime -= _wordDuration;
+ // Put next word into KDATA if not inhibited from doing so.
+ if (!_xferOff)
+ {
+ _kData = 0xda1a; // placeholder
+ Console.WriteLine(" Sector word {0} is {1}", _sectorWordIndex, OctalHelpers.ToOctal(_kData));
+ }
+ _sectorWordIndex++;
+
+ if (!_wdInhib)
+ {
+ _system.CPU.WakeupTask(CPU.TaskType.DiskWord);
+ }
+ }
+ break;
+
+ case SectorState.Postamble:
+ // Just stay here forever. We will get reset at the start of the next sector.
+ break;
+
+ }
}
+
+ //
+ // Update the WDINIT signal; this is based on WDALLOW (!_wdInhib) which sets WDINIT (this is done
+ // in KCOM way above).
+ // WDINIT is reset when BLOCK (a BLOCK F1 is being executed) and WDTSKACT (the disk word task is running) are 1.
+ //
+ if (_system.CPU.CurrentTask.Priority == (int)CPU.TaskType.DiskWord &&
+ _system.CPU.CurrentTask.BLOCK)
+ {
+ _wdInit = false;
+ }
}
public void ClearStatus()
@@ -422,6 +515,9 @@ namespace Contralto.IO
private int _head;
private int _sector;
+ // WDINIT signal
+ private bool _wdInit;
+
// Sector timing. Based on table on pg. 43 of the Alto Hardware Manual
private double _elapsedSectorTime; // elapsed time in this sector (in clocks)
private const double _sectorDuration = (40.0 / 12.0); // time in msec for one sector
@@ -430,24 +526,35 @@ namespace Contralto.IO
// Sector data timing and associated state. Timings based on educated guesses at the moment.
private enum SectorState
{
- Leadin = 0, // gap between sector mark and first Header word
- Header, // Header; two words
- HeaderGap, // gap between end of Header and first Label word
- Label, // Label; 8 words
- LabelGap, // gap betweeen the end of Label and first Data word
- Data, // Data; 256 words
- Leadout // gap between the end of Data and the next sector mark
+ HeaderReadDelay = 0, // gap between sector mark and first Header word
+ HeaderPreamble,
+ Header, // Header; two words
+ HeaderInterrecord,// gap between end of Header and first Label word
+ Label, // Label; 8 words
+ LabelInterrecord, // gap betweeen the end of Label and first Data word
+ Data, // Data; 256 words
+ Postamble // gap between the end of Data and the next sector mark
}
private SectorState _sectorState;
private double _elapsedSectorStateTime;
private int _sectorWordIndex;
- private const double _wordDuration = (_sectorClocks / (266.0 + 94.0)); // Based on : 266 words / sector, + 94 "words" for gaps (made up)
- private const double _leadinDuration = (_wordDuration * 70.0);
- private const double _headerGapDuration = (_wordDuration * 8.0);
- private const double _labelGapDuration = (_wordDuration * 8.0);
- private const double _leadoutDuration = (_wordDuration * 8.0);
-
+
+ // From altoconsts23.mu:
+ // $MFRRDL $177757; DISK HEADER READ DELAY IS 21 WORDS
+ // $MFR0BL $177744; DISK HEADER PREAMBLE IS 34 WORDS
+ // $MIRRDL $177774; DISK INTERRECORD READ DELAY IS 4 WORDS
+ // $MIR0BL $177775; DISK INTERRECORD PREAMBLE IS 3 WORDS
+ // $MRPAL $177775; DISK READ POSTAMBLE LENGTH IS 3 WORDS
+ // $MWPAL $177773; DISK WRITE POSTAMBLE LENGTH IS 5 WORDS
+ private const double _wordDuration = (_sectorClocks / (266.0 + 21 + 34 + (4 + 3) * 3)); // Based on : 266 words / sector, + X words for delay / preamble
+ private const double _headerReadDelay = (_wordDuration * 21);
+ private const double _headerPreamble = (_wordDuration * 34);
+ private const double _interRecordDelay = (_wordDuration * 4);
+ private const double _interRecordPreamble = (_wordDuration * 3);
+
+
+
// Cylinder seek timing. Again, see the manual.
// Timing varies based on how many cylinders are being traveled during a seek; see
diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs
index 05207a7..3a11145 100644
--- a/Contralto/Memory/MemoryBus.cs
+++ b/Contralto/Memory/MemoryBus.cs
@@ -242,8 +242,8 @@ namespace Contralto.Memory
}
else
{
- throw new NotImplementedException(String.Format("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address)));
- //Console.WriteLine("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address));
+ //throw new NotImplementedException(String.Format("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address)));
+ Console.WriteLine("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address));
return 0;
}
}
@@ -264,8 +264,8 @@ namespace Contralto.Memory
}
else
{
- throw new NotImplementedException(String.Format("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address)));
- //Console.WriteLine("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address));
+ // throw new NotImplementedException(String.Format("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address)));
+ Console.WriteLine("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address));
}
}
diff --git a/Contralto/Notes.txt b/Contralto/Notes.txt
index 4ca0f46..67ca201 100644
--- a/Contralto/Notes.txt
+++ b/Contralto/Notes.txt
@@ -1,5 +1,53 @@
-Current issue:
+
+9/15/15:
+Current issue:
DCB @ 521 is set to 1 by emulator uCode; then clobbered once sector task runs (set to zero) so the disk controller never picks up a control
block and never does anything.
+9/16:
+"solved" previous issue by issuing a Wake for the KS task on init; this causes the sector task to run first, the Emulator uCode then sets things up correctly.
+Not sure if this is how it's supposed to work.
+
+New issue: Emulator uCode sets up a DCB starting at 1 that looks like:
+
+DCB: 1
+DCB+1: 1
+DCB+2: 44000
+DCB+3: 402
+DCB+4: 402