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:
parent
ee7c7fb035
commit
ea5a5f22ec
@ -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())
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
|
||||
150
Contralto/Debugger.Designer.cs
generated
150
Contralto/Debugger.Designer.cs
generated
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user