1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-17 00:23:24 +00:00

Improvements to Disk Word Task.

This commit is contained in:
Josh Dersch 2015-10-20 15:32:26 -07:00
parent ee7c7fb035
commit ea5a5f22ec
12 changed files with 581 additions and 204 deletions

View File

@ -146,6 +146,15 @@ namespace Contralto.CPU
}
}
/// <summary>
/// Used by the debugger to determine if a task switch is taking
/// place.
/// </summary>
public Task NextTask
{
get { return _nextTask; }
}
private void ExecuteNext()
{
if (_currentTask.ExecuteNext())

View File

@ -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));
}
}
}
/// <summary>
/// The status of the INIT flag
/// </summary>
/// <returns></returns>
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;
}
}
}
}

View File

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

View File

@ -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; }
}
/// <summary>
/// Indicates whether the current uInstruction asserts BLOCK.
/// Used by hardware for various tasks.
/// </summary>
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);
/// <summary>
/// Used to allow Task-specific F2s that need to modify RSELECT to do so.
/// </summary>
/// <param name="f2"></param>
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;

View File

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

View File

@ -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));
}
}
/// <summary>
@ -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

View File

@ -165,4 +165,10 @@
<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>

View File

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

View File

@ -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;
}
}
}
/// <summary>
/// Used by the DiskTask code to check the WDINIT signal for dispatch.
/// </summary>
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; }
}
/// <summary>
/// This is a hack to see how the microcode expects INIT to work
/// </summary>
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

View File

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

View File

@ -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 <next DCB, not really used here since it will be overwritten by the sector that gets read in -- ALSO a JMP 1 instruction the EMU task is running continuously!>
DCB+1: 1 <status: meaningless, just a placeholder and will be overwritten by the KS/KW tasks>
DCB+2: 44000 <command: read header, label, and data off of drive zero>
DCB+3: 402 <header address: 402>
DCB+4: 402 <label address: 402>
DCB+5: 1 <data address: 1 -- overwrite this very data and the short jump that the CPU is executing at 1 (JMP 1) such that the emulator will start running a real program at 1 when loaded>
.
.
.
.
.
DCB+9: 0
The sector task is noting when sector 0 comes around, and the word task is getting woken up -- at which point it seems to be miscalculating the memory address for disk data (in KNMAR/KNMARW, reg 33).
This ends up being 177777 (-1) and this causes issues. KNMAR is shared between the sector and word tasks (it's KNMARW in the word task) and is set up by the sector task -- this setup code is not running,
leaving R33 at 0; later 1 is subtracted and we hit our problem.
KNMAR is loaded at KS 01153, this appears to be where we're going wrong (other places in the word task repurpose it for a counter, except for KW01746 which just decrements it)
NO, the above is incorrect. See below...
KNMARW is loaded at:
KW 01665 (in prep to use as length register for record 0 (header))
KW 01732 (same, for records 1 and 2)
KW 01742 in prep for loading something...
KW 01746 at the beginning of the transfer loop as an address, just decrementing it
At KW1732 we load in the memory block for the record.
KNMARW is used as a count
at REC12A, we load L with the memory block address and load it into KWDCTW (R31) -- KWDX loads this into L, and then puts it into KNMARW.
We are never reaching KW1732 -- why?
10/19/15:
Current issues are around how the "INIT" mode of RWC works (the mysterious fourth dispatch mode aside from Read/Write or Check).
The logic is

View File

@ -16,6 +16,27 @@ namespace Contralto
AltoSystem system = new AltoSystem();
/*
for(int address=0; address < 1024; address++)
{
MicroInstruction inst = new MicroInstruction(UCodeMemory.UCodeROM[address]);
Console.WriteLine("{0}: {1} - RSEL:{2} ALUF:{3} BS:{4} F1:{5} F2:{6} T:{7} L:{8} NEXT:{9}",
OctalHelpers.ToOctal(address, 4),
OctalHelpers.ToOctal((int)UCodeMemory.UCodeROM[address], 11),
OctalHelpers.ToOctal((int)inst.RSELECT, 2),
OctalHelpers.ToOctal((int)inst.ALUF, 2),
OctalHelpers.ToOctal((int)inst.BS),
OctalHelpers.ToOctal((int)inst.F1, 2),
OctalHelpers.ToOctal((int)inst.F2, 2),
inst.LoadT ? 1 : 0,
inst.LoadL ? 1 : 0,
OctalHelpers.ToOctal((int)inst.NEXT, 4));
} */
// for now everything is driven through the debugger
Debugger d = new Debugger(system);
d.LoadSourceCode("Disassembly\\altoIIcode3.mu");