diff --git a/Contralto/CPU/Tasks/EmulatorTask.cs b/Contralto/CPU/Tasks/EmulatorTask.cs
index eb1fca9..a2c4263 100644
--- a/Contralto/CPU/Tasks/EmulatorTask.cs
+++ b/Contralto/CPU/Tasks/EmulatorTask.cs
@@ -73,6 +73,14 @@ namespace Contralto.CPU
// Dispatch function to Ethernet I/O based on contents of AC0... (TBD: what are these?)
// For now do nothing, since we have no Ethernet implemented
//throw new NotImplementedException();
+ if ((_busData & 0x8000) != 0)
+ {
+ Console.WriteLine("Emulator STARTF -- boot");
+ }
+ else if(_busData != 0)
+ {
+ Console.WriteLine("Emulator STARTF -- {0}", Conversion.ToOctal(_busData));
+ }
break;
case EmulatorF1.SWMODE:
diff --git a/Contralto/CPU/UCodeMemory.cs b/Contralto/CPU/UCodeMemory.cs
index ffdb5d4..7da167a 100644
--- a/Contralto/CPU/UCodeMemory.cs
+++ b/Contralto/CPU/UCodeMemory.cs
@@ -102,8 +102,7 @@ namespace Contralto.CPU
{
Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: Current Bank {0}", _microcodeBank);
- // 2K ROM
- /*
+ // 2K ROM
switch(_microcodeBank)
{
case MicrocodeBank.ROM0:
@@ -117,10 +116,10 @@ namespace Contralto.CPU
case MicrocodeBank.RAM0:
_microcodeBank = (nextAddress & 0x100) == 0 ? MicrocodeBank.ROM0 : MicrocodeBank.ROM1;
break;
- } */
+ }
// for 1K ROM
- _microcodeBank = _microcodeBank == MicrocodeBank.ROM0 ? MicrocodeBank.RAM0 : MicrocodeBank.ROM0;
+ //_microcodeBank = _microcodeBank == MicrocodeBank.ROM0 ? MicrocodeBank.RAM0 : MicrocodeBank.ROM0;
Logging.Log.Write(Logging.LogComponent.Microcode, "SWMODE: New Bank {0}", _microcodeBank);
}
diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj
index 7de6d41..0a43734 100644
--- a/Contralto/Contralto.csproj
+++ b/Contralto/Contralto.csproj
@@ -108,7 +108,9 @@
PreserveNewest
-
+
+ PreserveNewest
+
PreserveNewest
diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs
index 1e82650..7e519ca 100644
--- a/Contralto/Debugger.Designer.cs
+++ b/Contralto/Debugger.Designer.cs
@@ -28,31 +28,31 @@
///
private void InitializeComponent()
{
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle76 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle80 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle77 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle78 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle79 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle81 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle85 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle82 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle83 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle84 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle86 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle90 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle87 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle88 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle89 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle91 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle92 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle93 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle94 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle95 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle96 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle97 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle98 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle99 = new System.Windows.Forms.DataGridViewCellStyle();
- System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle100 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle5 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle4 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle6 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle10 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle11 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle15 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle12 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle13 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle14 = 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();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle18 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle19 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle20 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle21 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle22 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle23 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle24 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle25 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle7 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle8 = new System.Windows.Forms.DataGridViewCellStyle();
+ System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle9 = new System.Windows.Forms.DataGridViewCellStyle();
this.Microcode = new System.Windows.Forms.GroupBox();
this.SourceTabs = new System.Windows.Forms.TabControl();
this.Rom0Page = new System.Windows.Forms.TabPage();
@@ -63,10 +63,6 @@
this.Source = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Rom1Page = new System.Windows.Forms.TabPage();
this._rom1SourceViewer = new System.Windows.Forms.DataGridView();
- this.dataGridViewCheckBoxColumn1 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
- this.dataGridViewTextBoxColumn4 = new System.Windows.Forms.DataGridViewTextBoxColumn();
- this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
- this.dataGridViewTextBoxColumn5 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Rom2Page = new System.Windows.Forms.TabPage();
this._ram0SourceViewer = new System.Windows.Forms.DataGridView();
this.dataGridViewCheckBoxColumn2 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
@@ -110,6 +106,10 @@
this.NovaStep = new System.Windows.Forms.Button();
this.groupBox6 = new System.Windows.Forms.GroupBox();
this.DisplayBox = new System.Windows.Forms.PictureBox();
+ this.dataGridViewCheckBoxColumn1 = new System.Windows.Forms.DataGridViewCheckBoxColumn();
+ this.dataGridViewTextBoxColumn4 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
+ this.dataGridViewTextBoxColumn5 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Microcode.SuspendLayout();
this.SourceTabs.SuspendLayout();
this.Rom0Page.SuspendLayout();
@@ -173,8 +173,8 @@
this._rom0SourceViewer.AllowUserToDeleteRows = false;
this._rom0SourceViewer.AllowUserToResizeColumns = false;
this._rom0SourceViewer.AllowUserToResizeRows = false;
- dataGridViewCellStyle76.BackColor = System.Drawing.Color.Silver;
- this._rom0SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle76;
+ dataGridViewCellStyle1.BackColor = System.Drawing.Color.Silver;
+ this._rom0SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle1;
this._rom0SourceViewer.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleVertical;
this._rom0SourceViewer.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._rom0SourceViewer.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
@@ -187,14 +187,14 @@
this._rom0SourceViewer.Name = "_rom0SourceViewer";
this._rom0SourceViewer.ReadOnly = true;
this._rom0SourceViewer.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
- dataGridViewCellStyle80.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle80.BackColor = System.Drawing.SystemColors.Control;
- dataGridViewCellStyle80.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle80.ForeColor = System.Drawing.SystemColors.WindowText;
- dataGridViewCellStyle80.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle80.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle80.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
- this._rom0SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle80;
+ dataGridViewCellStyle5.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle5.BackColor = System.Drawing.SystemColors.Control;
+ dataGridViewCellStyle5.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle5.ForeColor = System.Drawing.SystemColors.WindowText;
+ dataGridViewCellStyle5.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle5.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle5.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+ this._rom0SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle5;
this._rom0SourceViewer.RowHeadersVisible = false;
this._rom0SourceViewer.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this._rom0SourceViewer.RowTemplate.Height = 18;
@@ -223,9 +223,9 @@
// T
//
this.T.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle77.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle77.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this.T.DefaultCellStyle = dataGridViewCellStyle77;
+ dataGridViewCellStyle2.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle2.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.T.DefaultCellStyle = dataGridViewCellStyle2;
this.T.HeaderText = "T";
this.T.Name = "T";
this.T.ReadOnly = true;
@@ -236,8 +236,8 @@
// Addr
//
this.Addr.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle78.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.Addr.DefaultCellStyle = dataGridViewCellStyle78;
+ dataGridViewCellStyle3.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Addr.DefaultCellStyle = dataGridViewCellStyle3;
this.Addr.HeaderText = "Addr";
this.Addr.Name = "Addr";
this.Addr.ReadOnly = true;
@@ -248,8 +248,8 @@
// Source
//
this.Source.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
- dataGridViewCellStyle79.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.Source.DefaultCellStyle = dataGridViewCellStyle79;
+ dataGridViewCellStyle4.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.Source.DefaultCellStyle = dataGridViewCellStyle4;
this.Source.HeaderText = "Source Code";
this.Source.Name = "Source";
this.Source.ReadOnly = true;
@@ -273,8 +273,8 @@
this._rom1SourceViewer.AllowUserToDeleteRows = false;
this._rom1SourceViewer.AllowUserToResizeColumns = false;
this._rom1SourceViewer.AllowUserToResizeRows = false;
- dataGridViewCellStyle81.BackColor = System.Drawing.Color.Silver;
- this._rom1SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle81;
+ dataGridViewCellStyle6.BackColor = System.Drawing.Color.Silver;
+ this._rom1SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle6;
this._rom1SourceViewer.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleVertical;
this._rom1SourceViewer.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._rom1SourceViewer.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
@@ -287,14 +287,14 @@
this._rom1SourceViewer.Name = "_rom1SourceViewer";
this._rom1SourceViewer.ReadOnly = true;
this._rom1SourceViewer.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
- dataGridViewCellStyle85.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle85.BackColor = System.Drawing.SystemColors.Control;
- dataGridViewCellStyle85.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle85.ForeColor = System.Drawing.SystemColors.WindowText;
- dataGridViewCellStyle85.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle85.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle85.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
- this._rom1SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle85;
+ dataGridViewCellStyle10.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle10.BackColor = System.Drawing.SystemColors.Control;
+ dataGridViewCellStyle10.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle10.ForeColor = System.Drawing.SystemColors.WindowText;
+ dataGridViewCellStyle10.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle10.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle10.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+ this._rom1SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle10;
this._rom1SourceViewer.RowHeadersVisible = false;
this._rom1SourceViewer.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this._rom1SourceViewer.RowTemplate.Height = 18;
@@ -306,55 +306,6 @@
this._rom1SourceViewer.TabIndex = 2;
this._rom1SourceViewer.TabStop = false;
//
- // dataGridViewCheckBoxColumn1
- //
- this.dataGridViewCheckBoxColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
- this.dataGridViewCheckBoxColumn1.FalseValue = "false";
- this.dataGridViewCheckBoxColumn1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.dataGridViewCheckBoxColumn1.HeaderText = "B";
- this.dataGridViewCheckBoxColumn1.IndeterminateValue = "null";
- this.dataGridViewCheckBoxColumn1.Name = "dataGridViewCheckBoxColumn1";
- this.dataGridViewCheckBoxColumn1.ReadOnly = true;
- this.dataGridViewCheckBoxColumn1.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewCheckBoxColumn1.TrueValue = "true";
- this.dataGridViewCheckBoxColumn1.Width = 20;
- //
- // dataGridViewTextBoxColumn4
- //
- this.dataGridViewTextBoxColumn4.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle82.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.dataGridViewTextBoxColumn4.DefaultCellStyle = dataGridViewCellStyle82;
- this.dataGridViewTextBoxColumn4.HeaderText = "Addr";
- this.dataGridViewTextBoxColumn4.Name = "dataGridViewTextBoxColumn4";
- this.dataGridViewTextBoxColumn4.ReadOnly = true;
- this.dataGridViewTextBoxColumn4.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewTextBoxColumn4.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- this.dataGridViewTextBoxColumn4.Width = 5;
- //
- // dataGridViewTextBoxColumn3
- //
- this.dataGridViewTextBoxColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle83.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle83.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewTextBoxColumn3.DefaultCellStyle = dataGridViewCellStyle83;
- this.dataGridViewTextBoxColumn3.HeaderText = "Word";
- this.dataGridViewTextBoxColumn3.Name = "dataGridViewTextBoxColumn3";
- this.dataGridViewTextBoxColumn3.ReadOnly = true;
- this.dataGridViewTextBoxColumn3.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewTextBoxColumn3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- this.dataGridViewTextBoxColumn3.Width = 5;
- //
- // dataGridViewTextBoxColumn5
- //
- this.dataGridViewTextBoxColumn5.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
- dataGridViewCellStyle84.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.dataGridViewTextBoxColumn5.DefaultCellStyle = dataGridViewCellStyle84;
- this.dataGridViewTextBoxColumn5.HeaderText = "Disassembly";
- this.dataGridViewTextBoxColumn5.Name = "dataGridViewTextBoxColumn5";
- this.dataGridViewTextBoxColumn5.ReadOnly = true;
- this.dataGridViewTextBoxColumn5.Resizable = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewTextBoxColumn5.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
- //
// Rom2Page
//
this.Rom2Page.Controls.Add(this._ram0SourceViewer);
@@ -372,8 +323,8 @@
this._ram0SourceViewer.AllowUserToDeleteRows = false;
this._ram0SourceViewer.AllowUserToResizeColumns = false;
this._ram0SourceViewer.AllowUserToResizeRows = false;
- dataGridViewCellStyle86.BackColor = System.Drawing.Color.Silver;
- this._ram0SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle86;
+ dataGridViewCellStyle11.BackColor = System.Drawing.Color.Silver;
+ this._ram0SourceViewer.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle11;
this._ram0SourceViewer.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.SingleVertical;
this._ram0SourceViewer.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._ram0SourceViewer.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
@@ -386,14 +337,14 @@
this._ram0SourceViewer.Name = "_ram0SourceViewer";
this._ram0SourceViewer.ReadOnly = true;
this._ram0SourceViewer.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
- dataGridViewCellStyle90.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle90.BackColor = System.Drawing.SystemColors.Control;
- dataGridViewCellStyle90.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle90.ForeColor = System.Drawing.SystemColors.WindowText;
- dataGridViewCellStyle90.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle90.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle90.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
- this._ram0SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle90;
+ dataGridViewCellStyle15.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle15.BackColor = System.Drawing.SystemColors.Control;
+ dataGridViewCellStyle15.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle15.ForeColor = System.Drawing.SystemColors.WindowText;
+ dataGridViewCellStyle15.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle15.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle15.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
+ this._ram0SourceViewer.RowHeadersDefaultCellStyle = dataGridViewCellStyle15;
this._ram0SourceViewer.RowHeadersVisible = false;
this._ram0SourceViewer.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this._ram0SourceViewer.RowTemplate.Height = 18;
@@ -421,8 +372,8 @@
// dataGridViewTextBoxColumn7
//
this.dataGridViewTextBoxColumn7.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle87.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.dataGridViewTextBoxColumn7.DefaultCellStyle = dataGridViewCellStyle87;
+ dataGridViewCellStyle12.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.dataGridViewTextBoxColumn7.DefaultCellStyle = dataGridViewCellStyle12;
this.dataGridViewTextBoxColumn7.HeaderText = "Addr";
this.dataGridViewTextBoxColumn7.Name = "dataGridViewTextBoxColumn7";
this.dataGridViewTextBoxColumn7.ReadOnly = true;
@@ -433,9 +384,9 @@
// dataGridViewTextBoxColumn6
//
this.dataGridViewTextBoxColumn6.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
- dataGridViewCellStyle88.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle88.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this.dataGridViewTextBoxColumn6.DefaultCellStyle = dataGridViewCellStyle88;
+ dataGridViewCellStyle13.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle13.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn6.DefaultCellStyle = dataGridViewCellStyle13;
this.dataGridViewTextBoxColumn6.HeaderText = "Word";
this.dataGridViewTextBoxColumn6.Name = "dataGridViewTextBoxColumn6";
this.dataGridViewTextBoxColumn6.ReadOnly = true;
@@ -446,8 +397,8 @@
// dataGridViewTextBoxColumn8
//
this.dataGridViewTextBoxColumn8.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
- dataGridViewCellStyle89.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.dataGridViewTextBoxColumn8.DefaultCellStyle = dataGridViewCellStyle89;
+ dataGridViewCellStyle14.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.dataGridViewTextBoxColumn8.DefaultCellStyle = dataGridViewCellStyle14;
this.dataGridViewTextBoxColumn8.HeaderText = "Disassembly";
this.dataGridViewTextBoxColumn8.Name = "dataGridViewTextBoxColumn8";
this.dataGridViewTextBoxColumn8.ReadOnly = true;
@@ -488,21 +439,21 @@
this._registerData.AllowUserToDeleteRows = false;
this._registerData.AllowUserToResizeColumns = false;
this._registerData.AllowUserToResizeRows = false;
- dataGridViewCellStyle91.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._registerData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle91;
+ dataGridViewCellStyle16.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._registerData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle16;
this._registerData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._registerData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.RegNum,
this.R,
this.S});
- dataGridViewCellStyle92.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle92.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle92.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle92.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle92.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle92.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle92.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._registerData.DefaultCellStyle = dataGridViewCellStyle92;
+ 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._registerData.DefaultCellStyle = dataGridViewCellStyle17;
this._registerData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._registerData.Location = new System.Drawing.Point(7, 19);
this._registerData.MultiSelect = false;
@@ -608,21 +559,21 @@
//
this._taskData.AllowUserToAddRows = false;
this._taskData.AllowUserToDeleteRows = false;
- dataGridViewCellStyle93.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._taskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle93;
+ dataGridViewCellStyle18.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._taskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle18;
this._taskData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._taskData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.TaskName,
this.TaskState,
this.TaskPC});
- dataGridViewCellStyle94.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle94.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle94.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle94.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle94.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle94.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle94.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._taskData.DefaultCellStyle = dataGridViewCellStyle94;
+ dataGridViewCellStyle19.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle19.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle19.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle19.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle19.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle19.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle19.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._taskData.DefaultCellStyle = dataGridViewCellStyle19;
this._taskData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._taskData.Location = new System.Drawing.Point(7, 19);
this._taskData.MultiSelect = false;
@@ -679,20 +630,20 @@
//
this._otherRegs.AllowUserToAddRows = false;
this._otherRegs.AllowUserToDeleteRows = false;
- dataGridViewCellStyle95.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._otherRegs.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle95;
+ dataGridViewCellStyle20.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._otherRegs.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle20;
this._otherRegs.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._otherRegs.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Reg,
this.RegValue});
- dataGridViewCellStyle96.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle96.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle96.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle96.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle96.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle96.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle96.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._otherRegs.DefaultCellStyle = dataGridViewCellStyle96;
+ dataGridViewCellStyle21.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle21.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle21.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle21.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle21.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle21.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle21.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._otherRegs.DefaultCellStyle = dataGridViewCellStyle21;
this._otherRegs.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._otherRegs.Location = new System.Drawing.Point(7, 19);
this._otherRegs.MultiSelect = false;
@@ -745,8 +696,8 @@
this._memoryData.AllowUserToAddRows = false;
this._memoryData.AllowUserToDeleteRows = false;
this._memoryData.AllowUserToResizeRows = false;
- dataGridViewCellStyle97.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle97;
+ dataGridViewCellStyle22.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._memoryData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle22;
this._memoryData.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
this._memoryData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._memoryData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
@@ -754,14 +705,14 @@
this.Address,
this.Data,
this.Disassembly});
- dataGridViewCellStyle98.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle98.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle98.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle98.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle98.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle98.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle98.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._memoryData.DefaultCellStyle = dataGridViewCellStyle98;
+ dataGridViewCellStyle23.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle23.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle23.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle23.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle23.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle23.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle23.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._memoryData.DefaultCellStyle = dataGridViewCellStyle23;
this._memoryData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._memoryData.Location = new System.Drawing.Point(6, 19);
this._memoryData.MultiSelect = false;
@@ -858,20 +809,20 @@
//
this._diskData.AllowUserToAddRows = false;
this._diskData.AllowUserToDeleteRows = false;
- dataGridViewCellStyle99.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
- this._diskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle99;
+ dataGridViewCellStyle24.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this._diskData.AlternatingRowsDefaultCellStyle = dataGridViewCellStyle24;
this._diskData.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this._diskData.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.dataGridViewTextBoxColumn1,
this.dataGridViewTextBoxColumn2});
- dataGridViewCellStyle100.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
- dataGridViewCellStyle100.BackColor = System.Drawing.SystemColors.Window;
- dataGridViewCellStyle100.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- dataGridViewCellStyle100.ForeColor = System.Drawing.SystemColors.ControlText;
- dataGridViewCellStyle100.SelectionBackColor = System.Drawing.SystemColors.Highlight;
- dataGridViewCellStyle100.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
- dataGridViewCellStyle100.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
- this._diskData.DefaultCellStyle = dataGridViewCellStyle100;
+ dataGridViewCellStyle25.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
+ dataGridViewCellStyle25.BackColor = System.Drawing.SystemColors.Window;
+ dataGridViewCellStyle25.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle25.ForeColor = System.Drawing.SystemColors.ControlText;
+ dataGridViewCellStyle25.SelectionBackColor = System.Drawing.SystemColors.Highlight;
+ dataGridViewCellStyle25.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
+ dataGridViewCellStyle25.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this._diskData.DefaultCellStyle = dataGridViewCellStyle25;
this._diskData.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this._diskData.Location = new System.Drawing.Point(6, 19);
this._diskData.MultiSelect = false;
@@ -962,6 +913,55 @@
this.DisplayBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.OnDisplayMouseUp);
this.DisplayBox.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.DisplayBox_PreviewKeyDown);
//
+ // dataGridViewCheckBoxColumn1
+ //
+ this.dataGridViewCheckBoxColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
+ this.dataGridViewCheckBoxColumn1.FalseValue = "false";
+ this.dataGridViewCheckBoxColumn1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.dataGridViewCheckBoxColumn1.HeaderText = "B";
+ this.dataGridViewCheckBoxColumn1.IndeterminateValue = "null";
+ this.dataGridViewCheckBoxColumn1.Name = "dataGridViewCheckBoxColumn1";
+ this.dataGridViewCheckBoxColumn1.ReadOnly = true;
+ this.dataGridViewCheckBoxColumn1.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewCheckBoxColumn1.TrueValue = "true";
+ this.dataGridViewCheckBoxColumn1.Width = 20;
+ //
+ // dataGridViewTextBoxColumn4
+ //
+ this.dataGridViewTextBoxColumn4.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
+ dataGridViewCellStyle7.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.dataGridViewTextBoxColumn4.DefaultCellStyle = dataGridViewCellStyle7;
+ this.dataGridViewTextBoxColumn4.HeaderText = "Addr";
+ this.dataGridViewTextBoxColumn4.Name = "dataGridViewTextBoxColumn4";
+ this.dataGridViewTextBoxColumn4.ReadOnly = true;
+ this.dataGridViewTextBoxColumn4.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn4.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ this.dataGridViewTextBoxColumn4.Width = 5;
+ //
+ // dataGridViewTextBoxColumn3
+ //
+ this.dataGridViewTextBoxColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
+ dataGridViewCellStyle8.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ dataGridViewCellStyle8.WrapMode = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn3.DefaultCellStyle = dataGridViewCellStyle8;
+ this.dataGridViewTextBoxColumn3.HeaderText = "Word";
+ this.dataGridViewTextBoxColumn3.Name = "dataGridViewTextBoxColumn3";
+ this.dataGridViewTextBoxColumn3.ReadOnly = true;
+ this.dataGridViewTextBoxColumn3.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ this.dataGridViewTextBoxColumn3.Width = 5;
+ //
+ // dataGridViewTextBoxColumn5
+ //
+ this.dataGridViewTextBoxColumn5.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+ dataGridViewCellStyle9.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.dataGridViewTextBoxColumn5.DefaultCellStyle = dataGridViewCellStyle9;
+ this.dataGridViewTextBoxColumn5.HeaderText = "Source Code";
+ this.dataGridViewTextBoxColumn5.Name = "dataGridViewTextBoxColumn5";
+ this.dataGridViewTextBoxColumn5.ReadOnly = true;
+ this.dataGridViewTextBoxColumn5.Resizable = System.Windows.Forms.DataGridViewTriState.False;
+ this.dataGridViewTextBoxColumn5.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+ //
// Debugger
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -1067,13 +1067,13 @@
private System.Windows.Forms.DataGridView _rom1SourceViewer;
private System.Windows.Forms.TabPage Rom2Page;
private System.Windows.Forms.DataGridView _ram0SourceViewer;
- private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn1;
- private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn4;
- private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn3;
- private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn5;
private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn2;
private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn7;
private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn6;
private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn8;
+ private System.Windows.Forms.DataGridViewCheckBoxColumn dataGridViewCheckBoxColumn1;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn4;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn3;
+ private System.Windows.Forms.DataGridViewTextBoxColumn dataGridViewTextBoxColumn5;
}
}
\ No newline at end of file
diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs
index 3af7cb7..7dc2021 100644
--- a/Contralto/Debugger.cs
+++ b/Contralto/Debugger.cs
@@ -32,13 +32,15 @@ namespace Contralto
RefreshUI();
}
- public void LoadSourceCode(string path)
+ public void LoadSourceCode(MicrocodeBank bank, string path)
{
if (path == null)
{
throw new ArgumentNullException(path, "Microcode path must be specified.");
}
+ DataGridView view = bank == MicrocodeBank.ROM0 ? _rom0SourceViewer : _rom1SourceViewer;
+
StreamReader sr = new StreamReader(path);
while (!sr.EndOfStream)
@@ -47,19 +49,19 @@ namespace Contralto
SourceLine src = new SourceLine(line);
- int i = _rom0SourceViewer.Rows.Add(
+ int i = view.Rows.Add(
false, // breakpoint
GetTextForTask(src.Task),
src.Address,
src.Text);
// Give the row a color based on the task
- _rom0SourceViewer.Rows[i].DefaultCellStyle.BackColor = GetColorForTask(src.Task);
+ view.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))
{
- _rom0SourceViewer.Rows[i].Tag = Convert.ToUInt16(src.Address, 8);
+ view.Rows[i].Tag = Convert.ToUInt16(src.Address, 8);
}
}
@@ -272,8 +274,7 @@ namespace Contralto
break;
case 1:
- SourceTabs.TabIndex = 1;
- RefreshMicrocodeDisassembly(MicrocodeBank.ROM1);
+ SourceTabs.TabIndex = 1;
HighlightMicrocodeSourceLine(_rom1SourceViewer, _system.CPU.CurrentTask.MPC);
break;
@@ -596,7 +597,7 @@ namespace Contralto
Task = TaskType.Invalid;
if (tokens.Length > 0 &&
- tokens[0].Length == 8 &&
+ tokens[0].Length == 7 &&
tokens[0].EndsWith(">"))
{
// Close enough. Look for the task tag and parse out the (octal) address
@@ -642,6 +643,10 @@ namespace Contralto
Task = TaskType.DiskWord;
break;
+ case "XM": //XMesa code, which runs in the Emulator task
+ Task = TaskType.Emulator;
+ break;
+
default:
Task = TaskType.Invalid;
break;
@@ -652,7 +657,7 @@ namespace Contralto
try
{
// Belongs to a task, so we can grab the address out as well
- Address = sourceText.Substring(2, 5);
+ Address = sourceText.Substring(2, 4);
}
catch
{
diff --git a/Contralto/Disassembly/MesaROM-full-annotated.mu b/Contralto/Disassembly/MesaROM-full-annotated.mu
deleted file mode 100644
index 8ab1c80..0000000
--- a/Contralto/Disassembly/MesaROM-full-annotated.mu
+++ /dev/null
@@ -1 +0,0 @@
-;-----------------------------------------------------------------;
; X M E S A M I C R O C O D E ;
; Version 39-3 ;
;-----------------------------------------------------------------;
; MesaROM.Mu - Instruction fetch and general subroutines
; Last modified by Levin - March 6, 1979 10:40 AM
; 'uCodeVersion' is used by RunMesa to determine what version of the Mesa microcode is
; in ROM1. This version number should be incremented by 1 for every official release of
; the microcode. 'uCodeVersion' is mapped by RunMesa to the actual version number (which
; appears as a comment above). The reason for this mapping is the limited number of
; constants in the Alto constants ROM, otherwise, we would obviously have assigned
; 'uCodeVersion' the true microcode version number.
;
; The current table in RunMesa should have the following correspondences:
; uCodeVersion Microcode version Mesa release
; 0 34 4.1
; 1 39 5.0
$uCodeVersion $1;
;Completely rewritten by Roy Levin, Sept-Oct. 1977
;Modified by Johnsson; July 25, 1977 10:20 AM
;First version assembled 5 June 1975.
;Developed from Lampson's MESA.U of 21 March 1975.
;-----------------------------------------------------------------
; GLOBAL CONVENTIONS AND ASSUMPTIONS
;-----------------------------------------------------------------
; 1) Stack representation:
; stkp=0 => stack is empty
; sktp=10 => stack is full
; The validity checking that determines if the stack pointer is
; within this range is somewhat perfunctory. The approach taken is
; to include specific checks only where there absence would not lead
; to some catastrophic error. Hence, the stack is not checked for
; underflow, since allowing it to become negative will cause a disaster
; on the next stack dispatch.
; 2) Notation:
; Instruction labels correspond to opcodes in the obvious way. Suffixes
; of A and B (capitalized) refer to alignment in memory. 'A' is intended
; to suggest the right-hand byte of a memory word; 'B' is intended to
; suggest the left-hand byte. Labels terminating in a lower-case letter
; generally name local branch points within a particular group of
; opcodes. (Exception: subroutine names.) Labels terminating in 'x' generally
; exist only to satisfy alignment requirements imposed by various dispatches
; (most commonly IR<- and B/A in instruction fetch).
; 3) Tasking:
; Every effort has been made to ensure that a 'TASK' appears approximately
; every 12 instructions. Occasionally, this has not been possible,
; but (it is hoped that) violations occur only in infrequently executed
; code segments.
; 4) New symbols:
; In a few cases, the definitions of the standard Alto package
; (AltoConsts23.MU) have not been quite suitable to the needs of this
; microcode. Rather than change the standard package, we have defined
; new symbols (with names beginning with 'm') that are to be used instead
; of their standard counterparts. All such definitions appear together in
; Mesab.Mu.
; 5) Subroutine returns:
; Normally, subroutine returns using IDISP require one to deal with
; (the nuisance of) the dispatch caused by loading IR. Happily, however,
; no such dispatch occurs for 'msr0' and 'sr1' (the relevant bits
; are 0). To cut down on alignment restrictions, some subroutines
; assume they are called with only one of two returns and can
; therefore ignore the possibility of a pending IR<- dispatch.
; Such subroutines are clearly noted in the comments.
; 6) Frame pointer registers (lp and gp):
; These registers normally (i.e. except during Xfer) contain the
; addresses of local 2 and global 1, respectively. This optimizes accesses
; in such bytecodes as LL3 and SG2, which would otherwise require another cycle.
;-----------------------------------------------------------------
; Get definitions for ALTO and MESA
;-----------------------------------------------------------------
#AltoConsts23.mu;
#MesabROM.mu;
; *** 11/23/15 - START OF MESABROM.MU ***
;-----------------------------------------------------------------
; MesabROM.Mu - Registers, miscellaneous symbols and constants
; Last modified by Levin - February 27, 1979 4:49 PM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; R memories used by code in ROM0, correct to AltoCode23.Mu
;-----------------------------------------------------------------
; Nova Emulator Registers (some used by Mesa as well)
$AC3 $R0;
$MASK1 $R0;
$AC2 $R1;
$AC1 $R2;
$YMUL $R2;
$RETN $R2;
$AC0 $R3;
$SKEW $R3;
$NWW $R4;
$SAD $R5;
$CYRET $R5;
$TEMP $R5;
$PC $R6;
$XREG $R7;
$CYCOUT $R7;
$WIDTH $R7;
$PLIER $R7;
$XH $R10;
$DESTY $R10;
$WORD2 $R10;
$DWAX $R35;
$STARTBITSM1 $R35;
$MASK $R36;
$SWA $R36;
$DESTX $R36;
$LREG $R40;
$NLINES $R41;
$RAST1 $R42;
$SRCX $R43;
$SKMSK $R43;
$SRCY $R44;
$RAST2 $R44;
$CONST $R45;
$TWICE $R45;
$HCNT $R46;
$VINC $R46;
$HINC $R47;
$NWORDS $R50;
$MASK2 $R51;
;-----------------------------------------------------------------
; Registers used by standard Nova I/O controllers
;
; All names have been prefixed with 'x' to prevent conflicts when MesabROM is
; used by XMesa clients to assemble MesaXRAM with other microcode.
;-----------------------------------------------------------------
; Model 31 Disk
$xKWDCT $R31;
$xKWDCTW $R31;
$xCKSUMR $R32;
$xCKSUMRW $R32;
$xKNMAR $R33;
$xKNMARW $R33;
$xDCBR $R34;
; Display
$CURX $R20;
$CURDATA $R21;
$xCBA $R22;
$xAECL $R23;
$xSLC $R24;
$xMTEMP $R25;
$xHTAB $R26;
$xYPOS $R27;
$xDWA $R30;
; Ethernet
$xECNTR $R12;
$xEPNTR $R13;
; Memory Refresh
$xCLOCKTEMP $R11;
$xR37 $R37;
; Audio (obsolete)
$xAudioWdCt $R71;
$xAudioData $R72;
;-----------------------------------------------------------------
; Registers used by Mesa Emulator
;-----------------------------------------------------------------
; R registers
$temp $R35; Temporary (smashed by BITBLT)
$temp2 $R36; Temporary (smashed by BITBLT)
$mpc $R15; R register holds Mesa PC (points at word last read)
$stkp $R16; stack pointer [0-10] 0 empty, 10 full
$XTSreg $R17; xfer trap state
; Registers shared by Nova and Mesa emulators
; Nova ACs are set explicitly by Mesa process opcodes and for ROM0 calls
; Other R-registers smashed by BITBLT and other ROM0 subroutines
$brkbyte $R0; (AC3) bytecode to execute after a breakpoint
; Warning! brkbyte must be reset to 0 after ROM calls!
; (see BITBLT)
$mx $R1; (AC2) x register for XFER
; Warning! smashed by BITBLT and MUL/DIV/LDIV
$saveret $R2; (AC1) R-temporary for return indices and values
$newfield $R3; (AC0) new field bits for WF and friends
; Warning! must be R-register; assumed safe across CYCLE
$count $R5; scratch R register used for counting
$taskhole $R7; pigeonhole for saving things across TASKs
; Warning! smashed by all ROM calls!
$ib $R10; instruction byte, 0 if none (0,,byte)
; Warning! smashed by BITBLT
$clockreg $R37; low-order bits of real-time clock
; S registers, can't shift into them, BUS not zero while storing.
$my $R51; y register for XFER
$lp $R52; local pointer
$gp $R53; global pointer
$cp $R54; code pointer
$ATPreg $R55; allocation trap parameter
$OTPreg $R56; other trap parameter
$XTPreg $R57; xfer trap parameter
$wdc $R70; wakeup disable counter
; Mesa evaluation stack
$stk0 $R60; stack (bottom)
$stk1 $R61; stack
$stk2 $R62; stack
$stk3 $R63; stack
$stk4 $R64; stack
$stk5 $R65; stack
$stk6 $R66; stack
$stk7 $R67; stack (top)
; Miscellaneous S registers
$mask $R41; used by string instructions, among others
$unused1 $R42; not safe across call to BITBLT
$unused2 $R43; not safe across call to BITBLT
$alpha $R44; alpha byte (among other things)
$index $R45; frame size index (among other things)
$entry $R46; allocation table entry address (among other things)
$frame $R47; allocated frame pointer (among other things)
$righthalf $R41; right 4 bits of alpha or beta
$lefthalf $R45; left 4 bits of alpha or beta
$unused3 $R50; not safe across call to BITBLT
;-----------------------------------------------------------------
; Mnemonic constants for subroutine return indices used by BUS dispatch.
;-----------------------------------------------------------------
$ret0 $L0,12000,100; zero is always special
$ret1 $1;
$ret2 $2;
$ret3 $3;
$ret4 $4;
$ret5 $5;
$ret6 $6;
$ret7 $7;
$ret10 $10;
$ret11 $11;
$ret12 $12;
$ret13 $13;
$ret14 $14;
$ret15 $15;
$ret16 $16;
$ret17 $17;
$ret20 $20;
$ret21 $21;
$ret22 $22;
$ret23 $23;
$ret24 $24;
$ret25 $25;
$ret26 $26;
$ret27 $27;
$ret30 $30;
$ret31 $31;
$ret37 $37;
;-----------------------------------------------------------------
; Mesa Trap codes - index into sd vector
;-----------------------------------------------------------------
$sBRK $L0,12000,100; Breakpoint
$sStackError $2;
$sStackUnderflow $2; (trap handler distinguishes underflow from
$sStackOverflow $2; overflow by stkp value)
$sXferTrap $4;
$sAllocTrap $6;
$sControlFault $7;
$sSwapTrap $10;
$sUnbound $13;
$sBoundsFault $20;
$sPointerFault $21; must equal sBoundsFault+1
$sBoundsFaultm1 $17; must equal sBoundsFault-1
;-----------------------------------------------------------------
; Low- and high-core address definitions
;-----------------------------------------------------------------
$HardMRE $20; location which forces MRE to drop to Nova code
$CurrentState $23; location holding address of current state
$NovaDVloc $25; dispatch vector for Nova code
$avm1 $777; base of allocation vector for frames (-1)
$sdoffset $100; offset to base of sd from av
$gftm1 $1377; base of global frame table (-1)
$BankReg $177740; address of emulator's bank register
;-----------------------------------------------------------------
; Constants in ROM, but with unpleasant names
;-----------------------------------------------------------------
$12 $12; for function calls
$-12 $177766; for Savestate
$400 $400; for JB
;-----------------------------------------------------------------
; Frame offsets and other software/microcode agreements
;-----------------------------------------------------------------
$lpoffset $6; local frame overhead + 2
$nlpoffset $177771; = -(lpoffset + 1)
$nlpoffset1 $177770; = -(lpoffset + 2)
$pcoffset $1; offset from local frame base to saved pc
$npcoffset $5; = -(lpoffset+1+pcoffset) [see Savpcinframe]
$retlinkoffset $2; offset from local frame base to return link
$nretlinkoffset $177774; = -(lpoffset-retlinkoffset)
$gpoffset $4; global frame overhead + 1
$ngpoffset $177773; = -(gpoffset + 1)
$gfioffset $L0,12000,100; offset from global frame base to gfi word (=0)
$ngfioffset $4; = gpoffset-gfioffset [see XferGfz]
$cpoffset $1; offset from global frame base to code pointer
$gpcpoffset $2; offset from high code pointer to global 1
$gfimask $177600; mask to isolate gfi in global frame word 0
$enmask $37; mask to isolate entry number/4
;-----------------------------------------------------------------
; Symbols to be used instead of ones in the standard definitions
;-----------------------------------------------------------------
$mACSOURCE $L024016,000000,000000; sets only F2. ACSOURCE also sets BS and RSEL
$msr0 $L000000,012000,000100; IDISP => 0, no IR<- dispatch, a 'special' zero
$BUSAND~T $L000000,054015,000040; sets ALUF = 15B, doesn't require defined bus
;-----------------------------------------------------------------
; Linkages between ROM1 and RAM for overflow microcode
;-----------------------------------------------------------------
; Fixed locations in ROM1
$romnext $L004400,0,0; must correspond to next
$romnextA $L004401,0,0; must correspond to nextA
$romIntstop $L004406,0,0; must correspond to Intstop
$romUntail $L004407,0,0; must correspond to Untail
$romXfer $L004431,0,0; must correspond to Xfer
; Fixed locations in RAM
$ramBLTloop $L004403,0,0; must correspond to BLTloop
$ramBLTint $L004405,0,0; must correspond to BLTint
$ramOverflow $L004410,0,0; RR, BLTL, WR
; DADD, DSUB, DCOMP, DUCOMP
; *** 11/23/15 - END OF MESABROM.MU ***
;-----------------------------------------------------------------
; Location-specific Definitions
;-----------------------------------------------------------------
; There is a fundamental difficulty in the selection of addresses that are known and
; used outside the Mesa emulator. The problem arises in trying to select a single set of
; addresses that can be used regardless of the Alto's control memory configuration. In
; effect, this cannot be done. If an Alto has only a RAM (in addition, of course, to its
; basic ROM, ROM0), then the problem does not arise. However, suppose the Alto has both a
; RAM and a second ROM, ROM1. Then, when it is necessary to move from a control memory to
; one of the other two, the choice is conditioned on (1) the memory from which the transfer
; is occurring, and (2) bit 1 of the target address. Since we expect that, in most cases, an
; Alto running Mesa will have the Mesa emulator in ROM1, the externally-known addresses have
; been chosen to work in that case. They will also work, without alteration, on an Alto that
; has no ROM1. However, if it is necessary to run Mesa on an Alto with ROM1 and it is desired
; to use a Mesa emulator residing in the RAM (say, for debugging purposes), then the address
; values in the RAM version must be altered. This implies changes in both the RAM code itself
; and the Nova code that invokes the RAM (via the Nova JMPRAM instruction). Details
; concerning the necessary changes for re-assembly appear with the definitions below.
; Note concerning Alto IVs and Alto IIs with retrofitted 3K control RAMs:
;
; The above comments apply uniformly to these machines if "RAM" is systematically replaced
; by "RAM1" and "ROM1" is systematically replaced by "RAM2".
%1,1777,0,nextBa; forced to location 0 to save a word in JRAM
;-----------------------------------------------------------------
; Emulator Entry Point Definitions
; These addresses are known by the Nova code that interfaces to the emulator and by
; RAM code executing with the Mesa emulator in ROM1. They have been chosen so that
; both such "users" can use the same value. Precisely, this means that bit 1 (the
; 400 bit) must be set in the address. In a RAM version of the Mesa emulator intended
; to execute on an Alto with a second ROM, bit 1 must be zero.
;-----------------------------------------------------------------
%1,1777,420,Mgo; Normal entry to Mesa Emulator - load state
; of process specified by AC0.
%1,1777,400,next,nextA; Return to 'next' to continue in current Mesa
; process after Nova or RAM execution.
$Minterpret $L004400,0,0; Documentation refers to 'next' this way.
%1,1777,776,DSTr1,Mstopc; Return addresses for 'Savestate'. By
; standard convention, 'Mstopc' must be at 777.
;-----------------------------------------------------------------
; Linkage from RAM to ROM1
; The following predefs must correspond to the label definitions in MesabROM.mu
;-----------------------------------------------------------------
%1,1777,406,Intstop; must correspond to romIntstop
%1,1777,407,Untail; must correspond to romUntail
%7,1777,430,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr; Xfer must agree with romXfer
;-----------------------------------------------------------------
; Linkage from Mesa emulator to ROM0
; The Mesa emulator uses a number of subroutines that reside in ROM0. In posting a
; return address, the emulator must be aware of the control memory in which it resides,
; RAM or ROM1. These return addresses must satisfy the following constraint:
; no ROM1 extant or emulator in ROM1 => bit 1 of address must be 1
; ROM1 extant and emulator in RAM => bit 1 of address must be 0
; In addition, since these addresses must be passed as data to ROM0, it is desirable
; that they be available in the Alto's constants ROM. Finally, it is desirable that
; they be chosen not to mess up too many pre-defs. It should be noted that these
; issues do not affect the destination location in ROM0, since its address remains
; fixed (even with respect to bit 1 mapping) whether the Mesa emulator is in RAM or
; ROM1. [Note pertaining to Alto IVs and retrofitted Alto IIs with 3K RAMs: to avoid
; confusion, the comments above and below have not been revised to discuss 3K control
; RAMs. In all cases, there is an additional constraint that bit 2 of the return
; addresses must be 1. The suggested values observe this constraint, even though the
; comments do not explicitly mention it.]
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; MUL/DIV linkage:
; An additional constraint peculiar to the MUL/DIV microcode is that the high-order
; bits of the return address be 1's. Hence, the recommended values are:
; no ROM1 extant or emulator in ROM1 => MULDIVretloc = 177675B (OK to be odd)
; ROM1 extant and emulator in RAM => MULDIVretloc = 177162B (OK to be odd)
;-----------------------------------------------------------------
$ROMMUL $L004120,0,0; MUL routine address (120B) in ROM0
$ROMDIV $L004121,0,0; DIV routine address (121B) in ROM0
$MULDIVretloc $177675; (may be even or odd)
; The third value in the following pre-def must be: (MULDIVretloc AND 777B)
%1,1777,675,MULDIVret,MULDIVret1; return addresses from MUL/DIV in ROM0
;-----------------------------------------------------------------
; BITBLT linkage:
; An additional constraint peculiar to the BITBLT microcode is that the high-order
; bits of the return address be 1's. Hence, the recommended values are:
; no ROM1 extant or emulator in ROM1 => BITBLTret = 177714B
; ROM1 extant and emulator in RAM => BITBLTret = 177175B
;-----------------------------------------------------------------
$ROMBITBLT $L004124,0,0; BITBLT routine address (124B) in ROM0
$BITBLTret $177714; (may be even or odd)
; The third value in the following pre-def must be: (BITBLTret AND 777B)-1
%1,1777,713,BITBLTintr,BITBLTdone; return addresses from BITBLT in ROM0
;-----------------------------------------------------------------
; CYCLE linkage:
; A special constraint here is that WFretloc be odd. Recommended values are:
; no ROM1 extant or emulator in ROM1 => Fieldretloc = 612B, WFretloc = 605B
; ROM1 extant and emulator in RAM => Fieldretloc = 34104B, WFretloc = 14023B
;-----------------------------------------------------------------
$RAMCYCX $L004022,0,0; CYCLE routine address (22B) in ROM0
$Fieldretloc $612; RAMCYCX return to Fieldsub (even or odd)
$WFretloc $605; RAMCYCX return to WF (must be odd)
; The third value in the following pre-def must be: (Fieldretloc AND 1777B)
%1,1777,612,Fieldrc; return address from RAMCYCX to Fieldsub
; The third value in the following pre-def must be: (WFretloc AND 1777B)-1
%1,1777,604,WFnzct,WFret; return address from RAMCYCX to WF
;-----------------------------------------------------------------
; I n s t r u c t i o n f e t c h
;
; State at entry:
; 1) ib holds either the next instruction byte to interpret
; (right-justified) or 0 if a new word must be fetched.
; 2) control enters at one of the following points:
; a) next: ib must be interpreted
; b) nextA: ib is assumed to be uninteresting and a
; new instruction word is to be fetched.
; c) nextXB: a new word is to be fetched, and interpretation
; is to begin with the odd byte.
; d) nextAdeaf: similar to 'nextA', but does not check for
; pending interrupts.
; e) nextXBdeaf: similar to 'nextXB', but does not check for
; pending interrupts.
;
; State at exit:
; 1) ib is in an acceptable state for subsequent entry.
; 2) T contains the value 1.
; 3) A branch (1) is pending if ib = 0, meaning the next
; instruction may return to 'nextA'. (This is subsequently
; referred to as "ball 1", and code that nullifies its
; effect is labelled as "dropping ball 1".)
; 4) If a branch (1) is pending, L = 0. If no branch is
; pending, L = 1.
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Address pre-definitions for bytecode dispatch table.
;-----------------------------------------------------------------
; Table must have 2 high-order bits on for BUS branch at 'nextAni'.
;
; Warning! Many address inter-dependencies exist - think (at least) twice
; before re-ordering. Inserting new opcodes in previously unused slots,
; however, is safe.
; XMESA Note: RBL, WBL, and BLTL exist for XMESA only.
%7,1777,1400,NOOP,ME,MRE,MXW,MXD,NOTIFY,BCAST,REQUEUE; 000-007
%7,1777,1410,LL0,LL1,LL2,LL3,LL4,LL5,LL6,LL7; 010-017
%7,1777,1420,LLB,LLDB,SL0,SL1,SL2,SL3,SL4,SL5; 020-027
%7,1777,1430,SL6,SL7,SLB,PL0,PL1,PL2,PL3,LG0; 030-037
%7,1777,1440,LG1,LG2,LG3,LG4,LG5,LG6,LG7,LGB; 040-047
%7,1777,1450,LGDB,SG0,SG1,SG2,SG3,SGB,LI0,LI1; 050-057
%7,1777,1460,LI2,LI3,LI4,LI5,LI6,LIN1,LINI,LIB; 060-067
%7,1777,1470,LIW,LINB,LADRB,GADRB,,,,; 070-077
%7,1777,1500,R0,R1,R2,R3,R4,RB,W0,W1; 100-107
%7,1777,1510,W2,WB,RF,WF,RDB,RD0,WDB,WD0; 110-117
%7,1777,1520,RSTR,WSTR,RXLP,WXLP,RILP,RIGP,WILP,RIL0; 120-127
%7,1777,1530,WS0,WSB,WSF,WSDB,RFC,RFS,WFS,RBL; 130-137
%7,1777,1540,WBL,,,,,,,; 140-147
%7,1777,1550,,,,,,,,; 150-157
%7,1777,1560,,,SLDB,SGDB,PUSH,POP,EXCH,LINKB; 160-167
%7,1777,1570,DUP,NILCK,,BNDCK,,,,; 170-177
%7,1777,1600,J2,J3,J4,J5,J6,J7,J8,J9; 200-207
%7,1777,1610,JB,JW,JEQ2,JEQ3,JEQ4,JEQ5,JEQ6,JEQ7; 210-217
%7,1777,1620,JEQ8,JEQ9,JEQB,JNE2,JNE3,JNE4,JNE5,JNE6; 220-227
%7,1777,1630,JNE7,JNE8,JNE9,JNEB,JLB,JGEB,JGB,JLEB; 230-237
%7,1777,1640,JULB,JUGEB,JUGB,JULEB,JZEQB,JZNEB,,JIW; 240-247
%7,1777,1650,ADD,SUB,MUL,DBL,DIV,LDIV,NEG,INC; 250-257
%7,1777,1660,AND,OR,XOR,SHIFT,DADD,DSUB,DCOMP,DUCOMP; 260-267
%7,1777,1670,ADD01,,,,,,,; 270-277
%7,1777,1700,EFC0,EFC1,EFC2,EFC3,EFC4,EFC5,EFC6,EFC7; 300-307
%7,1777,1710,EFC8,EFC9,EFC10,EFC11,EFC12,EFC13,EFC14,EFC15; 310-317
%7,1777,1720,EFCB,LFC1,LFC2,LFC3,LFC4,LFC5,LFC6,LFC7; 320-327
%7,1777,1730,LFC8,,,,,,,; 330-337
%7,1777,1740,,LFCB,SFC,RET,LLKB,PORTO,PORTI,KFCB; 340-347
%7,1777,1750,DESCB,DESCBS,BLT,BLTL,BLTC,,ALLOC,FREE; 350-357
%7,1777,1760,IWDC,DWDC,STOP,CATCH,MISC,BITBLT,STARTIO,JRAM; 360-367
%7,1777,1770,DST,LST,LSTF,,WR,RR,BRK,StkUf; 370-377
;-----------------------------------------------------------------
; Main interpreter loop
;-----------------------------------------------------------------
;
; Enter here to interpret ib. Control passes here to process odd byte of previously
; fetched word or when preceding opcode "forgot" it should go to 'nextA'. A 'TASK'
; should appear in the instruction preceding the one that branched here.
;
XM0400> next: L<-0, :nextBa; (if from JRAM, switch banks)
XM0000> nextBa: SINK<-ib, BUS; dispatch on ib
XM0001> ib<-L, T<-0+1, BUS=0, :NOOP; establish exit state
;-----------------------------------------------------------------
; NOOP - must be opcode 0
; control also comes here from certain jump instructions
;-----------------------------------------------------------------
!1,1,nextAput;
XM1400> NOOP: L<-mpc+T, TASK, :nextAput;
;
; Enter here to fetch new word and interpret even byte. A 'TASK' should appear in the
; instruction preceding the one that branched here.
;
XM0401> nextA: L<-XMAR<-mpc+1, :nextAcom; initiate fetch
;
; Enter here when fetch address has been computed and left in L. A 'TASK' should
; appear in the instruction that branches here.
;
XM0003> nextAput: temp<-L; stash to permit TASKing
XM0002> L<-XMAR<-temp, :nextAcom;
;
; Enter here to do what 'nextA' does but without checking for interrupts
;
XM0004> nextAdeaf: L<-XMAR<-mpc+1;
XM0005> nextAdeafa: mpc<-L, BUS=0, :nextAcomx;
;
; Common fetch code for 'nextA' and 'nextAput'
;
!1,2,nextAi,nextAni;
!1,2,nextAini,nextAii;
XM0012> nextAcom: mpc<-L; updated pc
XM0013> SINK<-NWW, BUS=0; check pending interrupts
XM0014> nextAcomx: T<-177400, :nextAi;
;
; No interrupt pending. Dispatch on even byte, store odd byte in ib.
;
XM0007> nextAni: L<-MD AND T, BUS, :nextAgo; L<-"B"^8, dispatch on "A"
XM0015> nextAgo: ib<-L LCY 8, L<-T<-0+1, :NOOP; establish exit state
;
; Interrupt pending - check if enabled.
;
XM0006> nextAi: L<-MD;
XM0016> SINK<-wdc, BUS=0; check wakeup counter
XM0017> T<-M.T, :nextAini; isolate left byte
XM0010> nextAini: SINK<-M, L<-T, BUS, :nextAgo; dispatch even byte
;
; Interrupt pending and enabled.
;
!1,2,nextXBini,nextXBii;
XM0011> nextAii: L<-mpc-1; back up mpc for Savpcinframe
XM0022> mpc<-L, L<-0, :nextXBii;
;
; Enter here to fetch word and interpret odd byte only (odd-destination jumps).
;
!1,2,nextXBi,nextXBni;
XM0023> nextXB: L<-XMAR<-mpc+T;
XM0026> SINK<-NWW, BUS=0, :nextXBdeaf; check pending interrupts
;
; Enter here (with branch (1) pending) from Xfer to do what 'nextXB' does but without
; checking for interrupts. L has appropriate word PC.
;
XM0027> nextXBdeaf: mpc<-L, :nextXBi;
;
; No interrupt pending. Store odd byte in ib.
;
XM0025> nextXBni: L<-MD, TASK, :nextXBini;
XM0020> nextXBini: ib<-L LCY 8, :next; skip over even byte (TASK
; prevents L<-0, :nextBa)
;
; Interrupt pending - check if enabled.
;
XM0024> nextXBi: SINK<-wdc, BUS=0, :nextXBni; check wakeup counter
;
; Interrupt pending and enabled.
;
XM0021> nextXBii: ib<-L, :Intstop; ib = 0 for even, ~= 0 for odd
;-----------------------------------------------------------------
; S u b r o u t i n e s
;-----------------------------------------------------------------
;
; The two most heavily used subroutines (Popsub and Getalpha) often
; share common return points. In addition, some of these return points have
; additional addressing requirements. Accordingly, the following predefinitions
; have been rather carefully constructed to accommodate all of these requirements.
; Any alteration is fraught with peril.
; [A historical note: an attempt to merge in the returns from FetchAB as well
; failed because more than 31D distinct return points were then required. Without
; adding new constants to the ROM, the extra returns could not be accommodated.
; However, for Popsub alone, additional returns are possible - see Xpopsub.]
;
; Return Points (sr0-sr17)
!17,20,Fieldra,SFCr,pushTB,pushTA,LLBr,LGBr,SLBr,SGBr,
LADRBr,GADRBr,RFr,Xret,INCr,RBr,WBr,Xpopret;
; Extended Return Points (sr20-sr37)
; Note: KFCr and EFCr must be odd!
!17,20,XbrkBr,KFCr,LFCr,EFCr,WSDBra,DBLr,LINBr,LDIVf,
Dpush,Dpop,RD0r,Splitcomr,RXLPrb,WXLPrb,MISCr,RWBLra;
; Returns for Xpopsub only
!17,20,WSTRrB,WSTRrA,JRAMr,WRr,STARTIOr,PORTOr,WD0r,ALLOCrx,
FREErx,NEGr,RFSra,RFSrb,WFSra,DESCBcom,RFCr,NILCKr;
; Extended Return Machinery (via Xret)
!1,2,XretB,XretA;
XM0053> Xret: SINK<-DISP, BUS, :XretB;
XM0030> XretB: :XbrkBr;
XretA: SINK<-0, BUS=0, :XbrkBr; keep ball 1 in air
;-----------------------------------------------------------------
; Pop subroutine:
; Entry conditions:
; Normal IR linkage
; Exit conditions:
; Stack popped into T and L
;-----------------------------------------------------------------
!1,1,Popsub; shakes B/A dispatch
!7,1,Popsuba; shakes IR<- dispatch
!17,20,Tpop,Tpop0,Tpop1,Tpop2,Tpop3,Tpop4,Tpop5,Tpop6,Tpop7,,,,,,,;
XM0033> Popsub: L<-stkp-1, BUS, TASK, :Popsuba;
XM0037> Popsuba: stkp<-L, :Tpop; old stkp > 0
;-----------------------------------------------------------------
; Xpop subroutine:
; Entry conditions:
; L has return number
; Exit conditions:
; Stack popped into T and L
; Invoking instruction should specify 'TASK'
;-----------------------------------------------------------------
!1,1,Xpopsub; shakes B/A dispatch
XM0035> Xpopsub: saveret<-L;
XM0120> Tpop: IR<-sr17, :Popsub; returns to Xpopret
; Note: putting Tpop here makes
; stack underflow logic work if
; stkp=0
XM0057> Xpopret: SINK<-saveret, BUS;
XM0032> :WSTRrB;
;-----------------------------------------------------------------
; Getalpha subroutine:
; Entry conditions:
; L untouched from instruction fetch
; Exit conditions:
; alpha byte in T
; branch 1 pending if return to 'nextA' desirable
; L=0 if branch 1 pending, L=1 if no branch pending
;-----------------------------------------------------------------
!1,2,Getalpha,GetalphaA;
!7,1,Getalphax; shake IR<- dispatch
!7,1,GetalphaAx; shake IR<- dispatch
XM0132> Getalpha: T<-ib, IDISP;
XM0137> Getalphax: ib<-L RSH 1, L<-0, BUS=0, :Fieldra; ib<-0, set branch 1 pending
XM0133> GetalphaA: L<-XMAR<-mpc+1; initiate fetch
XM0147> GetalphaAx: mpc<-L;
XM0034> T<-177400; mask for new ib
XM0036> L<-MD AND T, T<-MD; L: new ib, T: whole word
XM0131> Getalphab: T<-377.T, IDISP; T now has alpha
XM0134> ib<-L LCY 8, L<-0+1, :Fieldra; return: no branch pending
;-----------------------------------------------------------------
; FetchAB subroutine:
; Entry conditions: none
; Exit conditions:
; T: <+1>
; ib: unchanged (caller must ensure return to 'nextA')
;-----------------------------------------------------------------
!1,1,FetchAB; drops ball 1
!7,1,FetchABx; shakes IR<- dispatch
!7,10,LIWr,JWr,,,,,,; return points
XM0135> etchAB: L<-XMAR<-mpc+1, :FetchABx;
XM0157> FetchABx: mpc<-L, IDISP;
XM0136> T<-MD, :LIWr;
;-----------------------------------------------------------------
; Splitalpha subroutine:
; Entry conditions:
; L: return index
; entry at Splitalpha if instruction is A-aligned, entry at
; SplitalphaB if instruction is B-aligned
; entry at Splitcomr splits byte in T (used by field instructions)
; Exit conditions:
; lefthalf: alpha[0-3]
; righthalf: alpha[4-7]
;-----------------------------------------------------------------
!1,2,Splitalpha,SplitalphaB;
!1,1,Splitx; drop ball 1
%160,377,217,Split0,Split1,Split2,Split3,Split4,Split5,Split6,Split7;
!1,2,Splitout0,Splitout1;
!7,10,RILPr,RIGPr,WILPr,RXLPra,WXLPra,Fieldrb,,; subroutine returns
XM0140> Splitalpha: saveret<-L, L<-0+1, :Splitcom; L<-1 for Getalpha
XM0141> SplitalphaB: saveret<-L, L<-0, BUS=0, :Splitcom; (keep ball 1 in air)
XM0142> Splitcom: IR<-sr33, :Getalpha; T:alpha[0-7]
XM0073> Splitcomr: L<-17 AND T, :Splitx; L:alpha[4-7]
XM0143> Splitx: righthalf<-L, L<-T, TASK; L:alpha, righthalf:alpha[4-7]
XM0146> temp<-L; temp:alpha
XM0150> L<-temp, BUS; dispatch on alpha[1-3]
XM0151> temp<-L LCY 8, SH<0, :Split0; dispatch on alpha[0]
XM0217> Split0: L<-T<-0, :Splitout0; L,T:alpha[1-3]
Split1: L<-T<-ONE, :Splitout0;
Split2: L<-T<-2, :Splitout0;
Split3: L<-T<-3, :Splitout0;
Split4: L<-T<-4, :Splitout0;
Split5: L<-T<-5, :Splitout0;
Split6: L<-T<-6, :Splitout0;
Split7: L<-T<-7, :Splitout0;
XM0145> Splitout1: L<-10+T, :Splitout0; L:alpha[0-3]
XM0144> Splitout0: SINK<-saveret, BUS, TASK; dispatch return
XM0152> lefthalf<-L, :RILPr; lefthalf:alpha[0-3]
;-----------------------------------------------------------------
; D i s p a t c h e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Pop-into-T (and L) dispatch:
; dispatches on old stkp, so Tpop0 = 1 mod 20B.
;-----------------------------------------------------------------
XM121> Tpop0: L<-T<-stk0, IDISP, :Tpopexit;
XM122> Tpop1: L<-T<-stk1, IDISP, :Tpopexit;
XM123> Tpop2: L<-T<-stk2, IDISP, :Tpopexit;
XM124> Tpop3: L<-T<-stk3, IDISP, :Tpopexit;
XM125> Tpop4: L<-T<-stk4, IDISP, :Tpopexit;
XM126> Tpop5: L<-T<-stk5, IDISP, :Tpopexit;
XM127> Tpop6: L<-T<-stk6, IDISP, :Tpopexit;
XM130> Tpop7: L<-T<-stk7, IDISP, :Tpopexit;
XM0153> Tpopexit: :Fieldra; to permit TASK in Popsub
;-----------------------------------------------------------------
; pushMD dispatch:
; pushes memory value on stack
; The invoking instruction must load MAR and may optionally keep ball 1
; in the air by having a branch pending. That is, entry at 'pushMD' will
; cause control to pass to 'next', while entry at 'pushMDA' will cause
; control to pass to 'nextA'.
;-----------------------------------------------------------------
!3,4,pushMD,pushMDA,StoreB,StoreA;
!17,20,push0,push1,push2,push3,push4,push5,push6,push7,push10,,,,,,,;
XM0164> pushMD: L<-stkp+1, IR<-stkp; (IR<- causes no branch)
XM0154> stkp<-L, T<-0+1, :pushMDa;
XM0165> pushMDA: L<-stkp+1, IR<-stkp; (IR<- causes no branch)
XM0155> stkp<-L, T<-0, :pushMDa;
XM0156> pushMDa: SINK<-DISP, L<-T, BUS; dispatch on old stkp value
XM0162> L<-MD, SH=0, TASK, :push0;
;-----------------------------------------------------------------
; Push-T dispatch:
; pushes T on stack
; The invoking instruction may optionally keep ball 1 in the air by having a
; branch pending. That is, entry at 'pushTB' will cause control to pass
; to 'next', while entry at 'pushTA' will cause control to pass to 'nextA'.
;-----------------------------------------------------------------
!1,2,pushT1B,pushT1A; keep ball 1 in air
XM0042> pushTB: L<-stkp+1, BUS, :pushT1B;
XM0043> pushTA: L<-stkp+1, BUS, :pushT1A;
XM0176> pushT1B: stkp<-L, L<-T, TASK, :push0;
XM0177> pushT1A: stkp<-L, BUS=0, L<-T, TASK, :push0; BUS=0 keeps branch pending
;-----------------------------------------------------------------
; push dispatch:
; strictly vanilla-flavored
; may (but need not) have branch (1) pending if return to 'nextA' is desired
; invoking instruction should specify TASK
;-----------------------------------------------------------------
; Note: the following pre-def occurs here so that dpushof1 can be referenced in push10
!17,20,dpush,,dpush1,dpush2,dpush3,dpush4,dpush5,dpush6,dpush7,dpushof1,dpushof2,,,,,;
XM0440> push0: stk0<-L, :next;
XM0441> push1: stk1<-L, :next;
XM0442> push2: stk2<-L, :next;
XM0443> push3: stk3<-L, :next;
XM0444> push4: stk4<-L, :next;
XM0445> push5: stk5<-L, :next;
XM0446> push6: stk6<-L, :next;
XM0447> push7: stk7<-L, :next;
XM0450> push10: :dpushof1; honor TASK, stack overflow
;-----------------------------------------------------------------
; Double-word push dispatch:
; picks up alpha from ib, adds it to T, then pushes and
;
; entry at 'Dpusha' substitutes L for ib.
; entry at 'Dpushc' and 'DpB' is used by RR 6 logic.
; entry at 'dpush' is used by MUL/DIV/LDIV logic.
; returns to 'nextA' <=> ib = 0 or entry at 'Dpush'
;-----------------------------------------------------------------
!1,2,DpA,DpB;
!1,1,Dpushb; shakes B/A dispatch from RCLK
!5,2,Dpushx,RCLKr; shakes IR<-2000 dispatch and
; provides return to RCLK
XM0070> Dpush: MAR<-L<-ib+T, :DpB; L: address of low half
XM0202> Dpusha: SINK<-ib, BUS=0;
XM0203> MAR<-L<-M+T, :DpA;
XM0200> DpA: IR<-0, :Dpushb; mACSOURCE will produce 0
XM0201> DpB: IR<-2000, :Dpushb; mACSOURCE will produce 1
XM0163> Dpushb: temp<-L, :Dpushx; temp: address of low half
XM0204> Dpushx: L<-MD, TASK, :Dpushc;
XM0206> Dpushc: taskhole<-L; taskhole: low half bits
XM0207> T<-0+1;
XM0210> L<-stkp+T+1;
XM0211> MAR<-temp+1; fetch high half
XM0212> stkp<-L; stkp <- stkp+2
XM0213> L<-taskhole; L: low half bits
XM0214> SINK<-stkp, BUS, :dpush; dispatch on new stkp
XM0460> dpush: T<-MD, :dpush; T: high half bits
XM0462> dpush1: stk0<-L, L<-T, TASK, mACSOURCE, :push1; stack cells are S-registers,
XM0463> dpush2: stk1<-L, L<-T, TASK, mACSOURCE, :push2; so mACSOURCE does not affect
XM0464> dpush3: stk2<-L, L<-T, TASK, mACSOURCE, :push3; addressing.
XM0465> dpush4: stk3<-L, L<-T, TASK, mACSOURCE, :push4;
XM0466> dpush5: stk4<-L, L<-T, TASK, mACSOURCE, :push5;
XM0467> dpush6: stk5<-L, L<-T, TASK, mACSOURCE, :push6;
XM0470> dpush7: stk6<-L, L<-T, TASK, mACSOURCE, :push7;
XM0471> dpushof1: T<-sStackOverflow, :KFCr;
XM0472> dpushof2: T<-sStackOverflow, :KFCr;
;-----------------------------------------------------------------
; TOS+T dispatch:
; adds TOS to T, then initiates memory operation on result.
; used as both dispatch table and subroutine - fall-through to 'pushMD'.
; dispatches on old stkp, so MAStkT0 = 1 mod 20B.
;-----------------------------------------------------------------
!17,20,MAStkT,MAStkT0,MAStkT1,MAStkT2,MAStkT3,MAStkT4,MAStkT5,MAStkT6,MAStkT7,,,,,,,;
XM0501> MAStkT0: MAR<-stk0+T, :pushMD;
XM0502> MAStkT1: MAR<-stk1+T, :pushMD;
XM0503> MAStkT2: MAR<-stk2+T, :pushMD;
XM0504> MAStkT3: MAR<-stk3+T, :pushMD;
XM0505> MAStkT4: MAR<-stk4+T, :pushMD;
XM0506> MAStkT5: MAR<-stk5+T, :pushMD;
XM0507> MAStkT6: MAR<-stk6+T, :pushMD;
XM0510> MAStkT7: MAR<-stk7+T, :pushMD;
;-----------------------------------------------------------------
; Common exit used to reset the stack pointer
; the instruction that branches here should have a 'TASK'
; Setstkp must be odd, StkOflw used by PUSH
;-----------------------------------------------------------------
!17,11,Setstkp,,,,,,,,StkOflw;
XM0527> Setstkp: stkp<-L, :next; branch (1) may be pending
XM0537> StkOflw: :dpushof1; honor TASK, dpushof1 is odd
;-----------------------------------------------------------------
; Stack Underflow Handling
;-----------------------------------------------------------------
XM1777> StkUf: T<-sStackUnderflow, :KFCr; catches dispatch of stkp = -1
;-----------------------------------------------------------------
; Store dispatch:
; pops TOS to MD.
; called from many places.
; dispatches on old stkp, so MDpop0 = 1 mod 20B.
; The invoking instruction must load MAR and may optionally keep ball 1
; in the air by having a branch pending. That is, entry at 'StoreB' will
; cause control to pass to 'next', while entry at 'StoreA' will cause
; control to pass to 'nextA'.
;-----------------------------------------------------------------
!1,2,StoreBa,StoreAa;
!17,20,MDpopuf,MDpop0,MDpop1,MDpop2,MDpop3,MDpop4,MDpop5,MDpop6,MDpop7,,,,,,,;
XM0166> StoreB: L<-stkp-1, BUS;
XM0220> StoreBa: stkp<-L, TASK, :MDpopuf;
XM0167> StoreA: L<-stkp-1, BUS;
XM0221> StoreAa: stkp<-L, BUS=0, TASK, :MDpopuf; keep branch (1) alive
XM0541> MDpop0: MD<-stk0, :next;
XM0542> MDpop1: MD<-stk1, :next;
XM0543> MDpop2: MD<-stk2, :next;
XM0544> MDpop3: MD<-stk3, :next;
XM0545> MDpop4: MD<-stk4, :next;
XM0546> MDpop5: MD<-stk5, :next;
XM0547> MDpop6: MD<-stk6, :next;
XM0550> MDpop7: MD<-stk7, :next;
;-----------------------------------------------------------------
; Double-word pop dispatch:
; picks up alpha from ib, adds it to T, then pops stack into result and
; result+1
; entry at 'Dpopa' substitutes L for ib.
; returns to 'nextA' <=> ib = 0 or entry at 'Dpop'
;-----------------------------------------------------------------
!17,20,dpopuf2,dpopuf1,dpop1,dpop2,dpop3,dpop4,dpop5,dpop6,dpop7,,,,,,,;
!1,1,Dpopb; required by placement of
; MDpopuf only.
XM0071> Dpop: L<-T<-ib+T+1;
XM0540> MDpopuf: IR<-0, :Dpopb; Note: MDpopuf is merely a
; convenient label which leads
; to a BUS dispatch on stkp in
; the case that stkp is -1. It
; is used by the Store dispatch
; above.
XM0216> Dpopa: L<-T<-M+T+1;
XM0222> IR<-ib, :Dpopb;
XM0215> Dpopb: MAR<-T, temp<-L;
XM0560> dpopuf2: L<-stkp-1, BUS;
XM0223> stkp<-L, TASK, :dpopuf2;
XM0561> dpopuf1: :StkUf; stack underflow, honor TASK
XM0562> dpop1: MD<-stk1, :Dpopx;
XM0563> dpop2: MD<-stk2, :Dpopx;
XM0564> dpop3: MD<-stk3, :Dpopx;
XM0565> dpop4: MD<-stk4, :Dpopx;
XM0566> dpop5: MD<-stk5, :Dpopx;
XM0567> dpop6: MD<-stk6, :Dpopx;
XM0570> dpop7: MD<-stk7, :Dpopx;
XM0224> Dpopx: SINK<-DISP, BUS=0;
XM0500> MAStkT: MAR<-temp-1, :StoreB;
;-----------------------------------------------------------------
; Get operation-specific code from other files
;-----------------------------------------------------------------
#MesacROM.mu;
; *** 11/23/15 - START OF MESACROM.MU ***
;-----------------------------------------------------------------
; MesacROM.Mu - Jumps, Load/Store, Read/Write, Binary/Unary/Stack Operators
; Last modified by Levin - March 7, 1979 8:29 AM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; J u m p s
;-----------------------------------------------------------------
; The following requirements are assumed:
; 1) J2-J9, JB are usable (in that order) as subroutine
; returns (by JEQx and JNEx).
; 2) since J2-J9 and JB are opcode entry points,
; they must meet requirements set by opcode dispatch.
;-----------------------------------------------------------------
; Jn - jump PC-relative
;-----------------------------------------------------------------
!1,2,JnA,Jbranchf;
XM1600> J2: L<-ONE, :JnA;
XM1601> J3: L<-2, :JnA;
XM1602> J4: L<-3, :JnA;
XM1603> J5: L<-4, :JnA;
XM1604> J6: L<-5, :JnA;
XM1605> J7: L<-6, :JnA;
XM1606> J8: L<-7, :JnA;
XM1607> J9: L<-10, :JnA;
XM0226> JnA: L<-M-1, :Jbranchf; A-aligned - adjust distance
;-----------------------------------------------------------------
; JB - jump PC-relative by alpha, assuming:
; JB is A-aligned
; Note: JEQB and JNEB come here with branch (1) pending
;-----------------------------------------------------------------
!1,1,JBx; shake JEQB/JNEB branch
!1,1,Jbranch; must be odd (shakes IR<- below)
XM1610> JB: T<-ib, :JBx;
XM0225> JBx: L<-400 OR T; <-DISP will do sign extension
XM0230> IR<-M; 400 above causes branch (1)
XM0232> L<-DISP-1, :Jbranch; L: ib (sign extended) - 1
;-----------------------------------------------------------------
; JW - jump PC-relative by alphabeta, assuming:
; if JW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after JW
;-----------------------------------------------------------------
XM1611> JW: IR<-sr1, :FetchAB; returns to JWr
JWr: L<-ALLONES+T, :Jbranch; L: alphabeta-1
;-----------------------------------------------------------------
; Jump destination determination
; L has (signed) distance from even byte of word addressed by mpc+1
;-----------------------------------------------------------------
!1,2,Jforward,Jbackward;
!1,2,Jeven,Jodd;
XM0231> Jbranch: T<-0+1, SH<0; dispatch fwd/bkwd target
XM0227> Jbranchf: SINK<-M, BUSODD, TASK, :Jforward; dispatch even/odd target
XM0234> Jforward: temp<-L RSH 1, :Jeven; stash positive word offset
Jbackward: temp<-L MRSH 1, :Jeven; stash negative word offset
XM0240> Jeven: T<-temp+1, :NOOP; fetch and execute even byte
XM0240> Jodd: T<-temp+1, :nextXB; fetch and execute odd byte
;-----------------------------------------------------------------
; JZEQB - if TOS (popped) = 0, jump PC-relative by alpha, assuming:
; stack has precisely one element
; JZEQB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!1,2,Jcz,Jco;
XM1644> JZEQB: SINK<-stk0, BUS=0; test TOS = 0
XM0233> L<-stkp-1, TASK, :Jcz;
;-----------------------------------------------------------------
; JZNEB - if TOS (popped) ~= 0, jump PC-relative by alpha, assuming:
; stack has precisely one element
; JZNEB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!1,2,JZNEBne,JZNEBeq;
XM1645> JZNEB: SINK<-stk0, BUS=0; test TOS = 0
XM0236> L<-stkp-1, TASK, :JZNEBne;
XM0244> JZNEBne: stkp<-L, :JB; branch, pick up alpha
XM0245> JZNEBeq: stkp<-L, :nextA; no branch, alignment => nextA
;-----------------------------------------------------------------
; JEQn - if TOS (popped) = TOS (popped), jump PC-relative by n, assuming:
; stack has precisely two elements
;-----------------------------------------------------------------
!1,2,JEQnB,JEQnA;
!7,1,JEQNEcom; shake IR<- dispatch
XM1612> JEQ2: IR<-sr0, L<-T, :JEQnB; returns to J2
XM1613> JEQ3: IR<-sr1, L<-T, :JEQnB; returns to J3
XM1614> JEQ4: IR<-sr2, L<-T, :JEQnB; returns to J4
XM1615> JEQ5: IR<-sr3, L<-T, :JEQnB; returns to J5
XM1616> JEQ6: IR<-sr4, L<-T, :JEQnB; returns to J6
XM1617> JEQ7: IR<-sr5, L<-T, :JEQnB; returns to J7
XM1620> JEQ8: IR<-sr6, L<-T, :JEQnB; returns to J8
XM1621> JEQ9: IR<-sr7, L<-T, :JEQnB; returns to J9
;-----------------------------------------------------------------
; JEQB - if TOS (popped) = TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JEQB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1622> JEQB: IR<-sr10, :JEQnA; returns to JB
;-----------------------------------------------------------------
; JEQ common code
;-----------------------------------------------------------------
!1,2,JEQcom,JNEcom; return points from JEQNEcom
XM246> JEQnB: temp<-L RSH 1, L<-T, :JEQNEcom; temp:0, L:1 (for JEQNEcom)
XM247> JEQnA: temp<-L, L<-T, :JEQNEcom; temp:1, L:1 (for JEQNEcom)
!1,2,JEQne,JEQeq;
XM0250> JEQcom: L<-stkp-T-1, :JEQne; L: old stkp - 2
XM0252> JEQne: SINK<-temp, BUS, TASK, :Setstkp; no jump, reset stkp
XM0253> JEQeq: stkp<-L, IDISP, :JEQNExxx; jump, set stkp, then dispatch
;
; JEQ/JNE common code
;
; !7,1,JEQNEcom; appears above with JEQn
; !1,2,JEQcom,JNEcom; appears above with JEQB
XM0267> JEQNEcom: T<-stk1;
XM0254> L<-stk0-T, SH=0; dispatch EQ/NE
XM0255> T<-0+1, SH=0, :JEQcom; test outcome and return
XM0256> JEQNExxx: SINK<-temp, BUS, :J2; even/odd dispatch
;-----------------------------------------------------------------
; JNEn - if TOS (popped) ~= TOS (popped), jump PC-relative by n, assuming:
; stack has precisely two elements
;-----------------------------------------------------------------
!1,2,JNEnB,JNEnA;
XM1623> JNE2: IR<-sr0, L<-T, :JNEnB; returns to J2
XM1624> JNE3: IR<-sr1, L<-T, :JNEnB; returns to J3
XM1625> JNE4: IR<-sr2, L<-T, :JNEnB; returns to J4
XM1626> JNE5: IR<-sr3, L<-T, :JNEnB; returns to J5
XM1627> JNE6: IR<-sr4, L<-T, :JNEnB; returns to J6
XM1630> JNE7: IR<-sr5, L<-T, :JNEnB; returns to J7
XM1631> JNE8: IR<-sr6, L<-T, :JNEnB; returns to J8
XM1632> JNE9: IR<-sr7, L<-T, :JNEnB; returns to J9
;-----------------------------------------------------------------
; JNEB - if TOS (popped) = TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JNEB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1633> JNEB: IR<-sr10, :JNEnA; returns to JB
;-----------------------------------------------------------------
; JNE common code
;-----------------------------------------------------------------
XM0260> JNEnB: temp<-L RSH 1, L<-0, :JEQNEcom; temp:0, L:0
XM0261> JNEnA: temp<-L, L<-0, :JEQNEcom; temp:1, L:0
!1,2,JNEne,JNEeq;
JNEcom: L<-stkp-T-1, :JNEne; L: old stkp - 2
JNEne: stkp<-L, IDISP, :JEQNExxx; jump, set stkp, then dispatch
JNEeq: SINK<-temp, BUS, TASK, :Setstkp; no jump, reset stkp
;-----------------------------------------------------------------
; JrB - for r in {L,LE,G,GE,UL,ULE,UG,UGE}
; if TOS (popped) r TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JrB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
; The values loaded into IR are not returns but encoded actions:
; Bit 12: 0 => branch if carry zero
; 1 => branch if carry one (mask value: 10)
; Bit 15: 0 => perform add-complement before testing carry
; 1 => perform subtract before testing carry (mask value: 1)
; (These values were chosen because of the masks available for use with <-DISP
; in the existing constants ROM. Note that IR<- causes no dispatch.)
XM1634> JLB: IR<-10, :Jscale; adc, branch if carry one
XM1637> JLEB: IR<-11, :Jscale; sub, branch if carry one
XM1636> JGB: IR<-ONE, :Jscale; sub, branch if carry zero
XM1635> JGEB: IR<-0, :Jscale; adc, branch if carry zero
XM1640> JULB: IR<-10, :Jnoscale; adc, branch if carry one
XM1643> JULEB: IR<-11, :Jnoscale; sub, branch if carry one
XM1642> JUGB: IR<-ONE, :Jnoscale; sub, branch if carry zero
XM1641> JUGEB: IR<-0, :Jnoscale; adc, branch if carry zero
;-----------------------------------------------------------------
; Comparison "subroutine":
;-----------------------------------------------------------------
!1,2,Jadc,Jsub;
; !1,2,Jcz,Jco; appears above with JZEQB
!1,2,Jnobz,Jbz;
!1,2,Jbo,Jnobo;
XM0266> Jscale: T<-77777, :Jadjust;
Jnoscale: T<-ALLONES, :Jadjust;
XM0275> Jadjust: L<-stk1+T+1; L:stk1 + (0 or 100000)
XM0276> temp<-L;
XM0300> SINK<-DISP, BUSODD; dispatch ADC/SUB
XM0301> T<-stk0+T+1, :Jadc;
XM0264> Jadc: L<-temp-T-1, :Jcommon; perform add complement
Jsub: L<-temp-T, :Jcommon; perform subtract
XM0302> Jcommon: T<-ONE; warning: not T<-0+1
XM0303> L<-stkp-T-1, ALUCY; test ADC/SUB outcome
XM0304> SINK<-DISP, SINK<-lgm10, BUS=0, TASK, :Jcz; dispatch on encoded bit 12
XM0242> Jcz: stkp<-L, :Jnobz; carry is zero (stkp<-stkp-2)
Jco: stkp<-L, :Jbo; carry is one (stkp<-stkp-2)
XM0270> Jnobz: L<-mpc+1, TASK, :nextAput; no jump, alignment=>nextAa
Jbz: T<-ib, :JBx; jump
Jbo: T<-ib, :JBx; jump
Jnobo: L<-mpc+1, TASK, :nextAput; no jump, alignment=>nextAa
;-----------------------------------------------------------------
; JIW - see Principles of Operation for description
; assumes:
; stack contains precisely two elements
; if JIW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after JIW
;-----------------------------------------------------------------
!1,2,JIuge,JIul;
!1,1,JIWx;
XM1647> JIW: L<-stkp-T-1, TASK, :JIWx; stkp<-stkp-2
XM0305> JIWx: stkp<-L;
XM0310> T<-stk0;
XM0311> L<-XMAR<-mpc+1; load alphabeta
XM0312> mpc<-L;
XM0313> L<-stk1-T-1; do unsigned compare
XM0314> ALUCY;
XM0315> T<-MD, :JIuge;
XM0306> JIuge: L<-mpc+1, TASK, :nextAput; out of bounds - to 'nextA'
XM0307> JIul: L<-cp+T, TASK; (removing this TASK saves a
XM0316> taskhole<-L; word, but leaves a run of
XM0320> T<-taskhole; 15 instructions)
XM0321> XMAR<-stk0+T; fetch <+alphabeta+X>
XM0322> NOP;
XM0323> L<-MD-1, :Jbranch; L: offset
;-----------------------------------------------------------------
; L o a d s
;-----------------------------------------------------------------
; Note: These instructions keep track of their parity
;-----------------------------------------------------------------
; LLn - push <+n>
; Note: LL3 must be odd!
;-----------------------------------------------------------------
; Note: lp is offset by 2, hence the adjustments below
XM1410> LL0: MAR<-lp-T-1, :pushMD;
XM1411> LL1: MAR<-lp-1, :pushMD;
XM1412> LL2: MAR<-lp, :pushMD;
XM1413> LL3: MAR<-lp+T, :pushMD;
XM1414> LL4: MAR<-lp+T+1, :pushMD;
XM1415> LL5: T<-3, SH=0, :LL3; pick up ball 1
XM1416> LL6: T<-4, SH=0, :LL3; pick up ball 1
XM1417> LL7: T<-5, SH=0, :LL3; pick up ball 1
;-----------------------------------------------------------------
; LLB - push <+alpha>
;-----------------------------------------------------------------
XM1420> LLB: IR<-sr4, :Getalpha; returns to LLBr
XM0044> LLBr: T<-nlpoffset+T+1, SH=0, :LL3; undiddle lp, pick up ball 1
;-----------------------------------------------------------------
; LLDB - push <+alpha>, push <+alpha+1>
; LLDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1421> LLDB: T<-lp, :LDcommon;
XM0324> LDcommon: T<-nlpoffset+T+1, :Dpush;
;-----------------------------------------------------------------
; LGn - push <+n>
; Note: LG2 must be odd!
;-----------------------------------------------------------------
; Note: gp is offset by 1, hence the adjustments below
XM1437> LG0: MAR<-gp-1, :pushMD;
XM1440> LG1: MAR<-gp, :pushMD;
XM1441> LG2: MAR<-gp+T, :pushMD;
XM1442> LG3: MAR<-gp+T+1, :pushMD;
XM1443> LG4: T<-3, SH=0, :LG2; pick up ball 1
XM1444> LG5: T<-4, SH=0, :LG2; pick up ball 1
XM1445> LG6: T<-5, SH=0, :LG2; pick up ball 1
XM1446> LG7: T<-6, SH=0, :LG2; pick up ball 1
;-----------------------------------------------------------------
; LGB - push <+alpha>
;-----------------------------------------------------------------
XM1447> LGB: IR<-sr5, :Getalpha; returns to LGBr
XM0045> GBr: T<-ngpoffset+T+1, SH=0, :LG2; undiddle gp, pick up ball 1
;-----------------------------------------------------------------
; LGDB - push <+alpha>, push <+alpha+1>
; LGDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1450> LGDB: T<-gp+T+1, :LDcommon; T: gp-gpoffset+lpoffset
;-----------------------------------------------------------------
; LIn - push n
;-----------------------------------------------------------------
!1,2,LI0xB,LI0xA; keep ball 1 in air
; Note: all BUS dispatches use old stkp value, not incremented one
XM1456> LI0: L<-stkp+1, BUS, :LI0xB;
XM1457> LI1: L<-stkp+1, BUS, :pushT1B;
XM1460> LI2: T<-2, :pushTB;
XM1461> LI3: T<-3, :pushTB;
XM1462> LI4: T<-4, :pushTB;
XM1463> LI5: T<-5, :pushTB;
XM1464> LI6: T<-6, :pushTB;
XM0326> LI0xB: stkp<-L, L<-0, TASK, :push0;
LI0xA: stkp<-L, BUS=0, L<-0, TASK, :push0; BUS=0 keeps branch pending
;-----------------------------------------------------------------
; LIN1 - push -1
;-----------------------------------------------------------------
XM1465> LIN1: T<-ALLONES, :pushTB;
;-----------------------------------------------------------------
; LINI - push 100000
;-----------------------------------------------------------------
XM1466> LINI: T<-100000, :pushTB;
;-----------------------------------------------------------------
; LIB - push alpha
;-----------------------------------------------------------------
XM1467> LIB: IR<-sr2, :Getalpha; returns to pushTB
; Note: pushT1B will handle
; any pending branch
;-----------------------------------------------------------------
; LINB - push (alpha OR 377B8)
;-----------------------------------------------------------------
XM1471> LINB: IR<-sr26, :Getalpha; returns to LINBr
XM0066> LINBr: T<-177400 OR T, :pushTB;
;-----------------------------------------------------------------
; LIW - push alphabeta, assuming:
; if LIW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after LIW
;-----------------------------------------------------------------
XM1470> LIW: IR<-msr0, :FetchAB; returns to LIWr
XM0160> LIWr: L<-stkp+1, BUS, :pushT1A; duplicates pushTA, but
; because of overlapping
; return points, we
; can't use it
;-----------------------------------------------------------------
; S t o r e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; SLn - <+n><-TOS (popped)
; Note: SL3 is odd!
;-----------------------------------------------------------------
; Note: lp is offset by 2, hence the adjustments below
XM1422> SL0: MAR<-lp-T-1, :StoreB;
XM1423> SL1: MAR<-lp-1, :StoreB;
XM1424> SL2: MAR<-lp, :StoreB;
XM1425> SL3: MAR<-lp+T, :StoreB;
XM1426> SL4: MAR<-lp+T+1, :StoreB;
XM1427> SL5: T<-3, SH=0, :SL3;
XM1430> SL6: T<-4, SH=0, :SL3;
XM1431> SL7: T<-5, SH=0, :SL3;
;-----------------------------------------------------------------
; SLB - <+alpha><-TOS (popped)
;-----------------------------------------------------------------
XM1432> SLB: IR<-sr6, :Getalpha; returns to SLBr
XM0046> SLBr: T<-nlpoffset+T+1, SH=0, :SL3; undiddle lp, pick up ball 1
;-----------------------------------------------------------------
; SLDB - <+alpha+1><-TOS (popped), <+alpha><-TOS (popped), assuming:
; SLDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1562> SLDB: T<-lp, :SDcommon;
XM0325> SDcommon: T<-nlpoffset+T+1, :Dpop;
;-----------------------------------------------------------------
; SGn - <+n><-TOS (popped)
; Note: SG2 must be odd!
;-----------------------------------------------------------------
; Note: gp is offset by 1, hence the adjustments below
XM1451> SG0: MAR<-gp-1, :StoreB;
XM1452> SG1: MAR<-gp, :StoreB;
XM1453> SG2: MAR<-gp+T, :StoreB;
XM1454> SG3: MAR<-gp+T+1, :StoreB;
;-----------------------------------------------------------------
; SGB - <+alpha><-TOS (popped)
;-----------------------------------------------------------------
XM1455> SGB: IR<-sr7, :Getalpha; returns to SGBr
XM0047> SGBr: T<-ngpoffset+T+1, SH=0, :SG2; undiddle gp, pick up ball 1
;-----------------------------------------------------------------
; SGDB - <+alpha+1><-TOS (popped), <+alpha><-TOS (popped), assuming:
; SGDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1563> SGDB: T<-gp+T+1, :SDcommon; T: gp-gpoffset+lpoffset
;-----------------------------------------------------------------
; P u t s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PLn - <+n><-TOS (stack is not popped)
;-----------------------------------------------------------------
!1,1,PLcommon; drop ball 1
; Note: lp is offset by 2, hence the adjustments below
XM1433> PL0: MAR<-lp-T-1, SH=0, :PLcommon; pick up ball 1
XM1434> PL1: MAR<-lp-1, SH=0, :PLcommon;
XM1435> PL2: MAR<-lp, SH=0, :PLcommon;
XM1436> PL3: MAR<-lp+T, SH=0, :PLcommon;
XM0331> PLcommon: L<-stkp, BUS, :StoreBa; don't decrement stkp
;-----------------------------------------------------------------
; B i n a r y o p e r a t i o n s
;-----------------------------------------------------------------
; Warning! Before altering this list, be certain you understand the additional addressing
; requirements imposed on some of these return locations! However, it is safe to add new
; return points at the end of the list.
!37,40,ADDr,SUBr,ANDr,ORr,XORr,MULr,DIVr,LDIVr,SHIFTr,EXCHr,RSTRr,WSTRr,WSBr,WS0r,WSFr,WFr,
WSDBrb,WFSrb,BNDCKr,RWBLrb,WBLrb,,,,,,,,,,,;
;-----------------------------------------------------------------
; Binary operations common code
; Entry conditions:
; Both IR and T hold return number. (More precisely, entry at
; 'BincomB' requires return number in IR, entry at 'BincomA' requires
; return number in T.)
; Exit conditions:
; left operand in L (M), right operand in T
; stkp positioned for subsequent push (i.e. points at left operand)
; dispatch pending (for push0) on return
; if entry occurred at BincomA, IR has been modified so
; that mACSOURCE will produce 1
;-----------------------------------------------------------------
; dispatches on stkp-1, so Binpop1 = 1 mod 20B
!17,20,Binpop,Binpop1,Binpop2,Binpop3,Binpop4,Binpop5,Binpop6,Binpop7,,,,,,,,;
!1,2,BincomB,BincomA;
!4,1,Bincomx; shake IR<- in BincomA
XM0332> BincomB: L<-T<-stkp-1, :Bincomx; value for dispatch into Binpop
XM0334> Bincomx: stkp<-L, L<-T;
XM0330> L<-M-1, BUS, TASK; L:value for push dispatch
XM0335> Bincomd: temp2<-L, :Binpop; stash briefly
XM0333> BincomA: L<-2000 OR T; make mACSOURCE produce 1
XM0620> Binpop: IR<-M, :BincomB;
XM0621> Binpop1: T<-stk1;
XM0336> L<-stk0, :Binend;
XM0622> Binpop2: T<-stk2;
XM0340> L<-stk1, :Binend;
XM0623> Binpop3: T<-stk3;
XM0341> L<-stk2, :Binend;
XM0624> Binpop4: T<-stk4;
XM0342> L<-stk3, :Binend;
XM0625> Binpop5: T<-stk5;
XM0343> L<-stk4, :Binend;
XM0626> Binpop6: T<-stk6;
XM0344> L<-stk5, :Binend;
XM0627> Binpop7: T<-stk7;
XM0345> L<-stk6, :Binend;
XM0346> Binend: SINK<-DISP, BUS; perform return dispatch
XM0347> SINK<-temp2, BUS, :ADDr; perform push dispatch
;-----------------------------------------------------------------
; ADD - replace with sum of top two stack elements
;-----------------------------------------------------------------
XM1650> ADD: IR<-T<-ret0, :BincomB;
XM1000> ADDr: L<-M+T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; ADD01 - replace stk0 with +
;-----------------------------------------------------------------
!1,1,ADD01x; drop ball 1
XM1670> ADD01: T<-stk1-1, :ADD01x;
XM0351> ADD01x: T<-stk0+T+1, SH=0; pick up ball 1
XM0350> L<-stkp-1, :pushT1B; no dispatch => to push0
;-----------------------------------------------------------------
; SUB - replace with difference of top two stack elements
;-----------------------------------------------------------------
XM1651> SUB: IR<-T<-ret1, :BincomB;
XM1001> SUBr: L<-M-T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; AND - replace with AND of top two stack elements
;-----------------------------------------------------------------
XM1660> AND: IR<-T<-ret2, :BincomB;
XM1002> ANDr: L<-M AND T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; OR - replace with OR of top two stack elements
;-----------------------------------------------------------------
XM1661> OR: IR<-T<-ret3, :BincomB;
XM1003> ORr: L<-M OR T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; XOR - replace with XOR of top two stack elements
;-----------------------------------------------------------------
XM1662> XOR: IR<-T<-ret4, :BincomB;
XM1004> XORr: L<-M XOR T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; MUL - replace with product of top two stack elements
; high-order bits of product recoverable by PUSH
;-----------------------------------------------------------------
!7,1,MULDIVcoma; shakes stack dispatch
!1,2,GoROMMUL,GoROMDIV;
!7,2,MULx,DIVx; also shakes bus dispatch
XM1652> MUL: IR<-T<-ret5, :BincomB;
XM1005> MULr: AC1<-L, L<-T, :MULDIVcoma; stash multiplicand
XM0367> MULDIVcoma: AC2<-L, L<-0, :MULx; stash multiplier or divisor
XM0416> MULx: AC0<-L, T<-0+1, :MULDIVcomb; AC0<-0 keeps ROM happy
XM0417> DIVx: AC0<-L, T<-0, BUS=0, :MULDIVcomb; BUS=0 => GoROMDIV
XM0354> MULDIVcomb: L<-MULDIVretloc+T, SWMODE, :GoROMMUL; prepare return address
XM0352> GoROMMUL: PC<-L, :ROMMUL; go to ROM multiply
XM0353> GoROMDIV: PC<-L, :ROMDIV; go to ROM divide
MULDIVret: :MULDIVret1; No divide - someday a trap
; perhaps, but garbage now.
MULDIVret1: T<-AC1; Normal return
L<-stkp+1;
L<-T, SINK<-M, BUS;
T<-AC0, :dpush; Note! not a subroutine
; call, but a direct
; dispatch.
;-----------------------------------------------------------------
; DIV - push quotient of top two stack elements (popped)
; remainder recoverable by PUSH
;-----------------------------------------------------------------
XM1654> DIV: IR<-T<-ret6, :BincomB;
XM1006> DIVr: AC1<-L, L<-T, BUS=0, :MULDIVcoma; BUS=0 => DIVx
;-----------------------------------------------------------------
; LDIV - push quotient of ,,/ (all popped)
; remainder recoverable by PUSH
;-----------------------------------------------------------------
XM1655> LDIV: IR<-sr27, :Popsub; get divisor
XM0067> LDIVf: AC2<-L; stash it
XM0361> IR<-T<-ret7, :BincomB; L:low bits, T:high bits
XM1007> LDIVr: AC1<-L, L<-T, IR<-0, :DIVx; stash low part of dividend
; and ensure mACSOURCE of 0.
;-----------------------------------------------------------------
; SHIFT - replace with shifted by
; > 0 => left shift, < 0 => right shift
;-----------------------------------------------------------------
!7,1,SHIFTx; shakes stack dispatch
!1,2,Lshift,Rshift;
!1,2,DoShift,Shiftdone;
!1,2,DoRight,DoLeft;
!1,1,Shiftdonex;
XM1663> SHIFT: IR<-T<-ret10, :BincomB;
XM1010> SHIFTr: temp<-L, L<-T, TASK, :SHIFTx; L: value, T: count
XM0427> SHIFTx: count<-L;
XM0366> L<-T<-count;
XM0372> L<-0-T, SH<0; L: -count, T: count
XM0374> IR<-sr1, :Lshift; IR<- causes no branch
XM0362> Lshift: L<-37 AND T, TASK, :Shiftcom; mask to reasonable size
XM0363> Rshift: T<-37, IR<-37; equivalent to IR<-msr0
L<-M AND T, TASK, :Shiftcom; mask to reasonable size
XM0376> Shiftcom: count<-L, :Shiftloop;
XM0402> Shiftloop: L<-count-1, BUS=0; test for completion
XM0403> count<-L, IDISP, :DoShift;
XM0364> DoShift: L<-temp, TASK, :DoRight;
XM0370> DoRight: temp<-L RSH 1, :Shiftloop;
XM0371> DoLeft: temp<-L LSH 1, :Shiftloop;
XM0365> Shiftdone: SINK<-temp2, BUS, :Shiftdonex; dispatch to push result
XM0373> Shiftdonex: L<-temp, TASK, :push0;
;-----------------------------------------------------------------
; D o u b l e - P r e c i s i o n A r i t h m e t i c
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; DADD - add two double-word quantities, assuming:
; stack contains precisely 4 elements
;-----------------------------------------------------------------
!1,1,DoRamDoubles; shake B/A dispatch
XM1664> DADD: L<-4, SWMODE, :DoRamDoubles; drop ball 1
XM0405> DoRamDoubles: SINK<-M, BUS, TASK, :ramOverflow; go to overflow code in RAM
;-----------------------------------------------------------------
; DSUB - subtract two double-word quantities, assuming:
; stack contains precisely 4 elements
;-----------------------------------------------------------------
XM1665> DSUB: L<-5, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; DCOMP - compare two long integers, assuming:
; stack contains precisely 4 elements
; result left on stack is -1, 0, or +1 (single-precision)
; (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------
XM1666> DCOMP: L<-6, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; DUCOMP - compare two long cardinals, assuming:
; stack contains precisely 4 elements
; result left on stack is -1, 0, or +1 (single-precision)
; (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------
XM1667> DUCOMP: L<-7, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; R a n g e C h e c k i n g
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; NILCK - check TOS for NIL (0), trap if so
;-----------------------------------------------------------------
!1,2,InRange,OutOfRange;
XM1571> NILCK: L<-ret17, :Xpopsub; returns to NILCKr
XM0117> NILCKr: T<-ONE, SH=0, :NILCKpush; test TOS=0
XM0404> NILCKpush: L<-stkp+T, :InRange;
XM0410> InRange: SINK<-ib, BUS=0, TASK, :Setstkp; pick up ball 1
XM0411> OutOfRange: T<-sBoundsFaultm1+T+1, :KFCr; T:SD index; go trap
;-----------------------------------------------------------------
; BNDCK - check subrange inclusion
; if TOS-1 ~IN [0..TOS) then trap (test is unsigned)
; only TOS is popped off
;-----------------------------------------------------------------
!7,1,BNDCKx; shake push dispatch
XM1573> BNDCK: IR<-T<-ret22, :BincomB; returns to BNDCKr
BNDCKr: SINK<-M-T, :BNDCKx; L: value, T: limit
BNDCKx: T<-0, ALUCY, :NILCKpush;
;-----------------------------------------------------------------
; R e a d s
;-----------------------------------------------------------------
; Note: RBr must be odd!
;-----------------------------------------------------------------
; Rn - TOS<-<+n>
;-----------------------------------------------------------------
XM1500> R0: T<-0, SH=0, :RBr;
XM1501> R1: T<-ONE, SH=0, :RBr;
XM1502> R2: T<-2, SH=0, :RBr;
XM1503> R3: T<-3, SH=0, :RBr;
XM1504> R4: T<-4, SH=0, :RBr;
;-----------------------------------------------------------------
; RB - TOS<-<+alpha>, assuming:
;-----------------------------------------------------------------
!1,2,ReadB,ReadA; keep ball 1 in air
XM1505> RB: IR<-sr15, :Getalpha; returns to RBr
XM0055> RBr: L<-stkp-1, BUS, :ReadB;
XM0412> ReadB: stkp<-L, :MAStkT; to pushMD
ReadA: stkp<-L, BUS=0, :MAStkT; to pushMDA
;-----------------------------------------------------------------
; RDB - temp<-+alpha, push <>, push <+1>, assuming:
; RDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1514> RDB: IR<-sr30, :Popsub; returns to Dpush
;-----------------------------------------------------------------
; RD0 - temp<-, push <>, push <+1>
;-----------------------------------------------------------------
XM1515> RD0: IR<-sr32, :Popsub; returns to RD0r
XM0072> RD0r: L<-0, :Dpusha;
;-----------------------------------------------------------------
; RILP - push <<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
XM1524> RILP: L<-ret0, :Splitalpha; get two 4-bit values
XM0170> RILPr: T<-lp, :RIPcom; T:address of local 2
;-----------------------------------------------------------------
; RIGP - push <<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
!3,1,IPcom; shake IR<- at WILPr
XM1525> RIGP: L<-ret1, :Splitalpha; get two 4-bit values
RIGPr: T<-gp+1, :RIPcom; T:address of global 2
XM0414> RIPcom: IR<-msr0, :IPcom; set up return to pushMD
XM0423> IPcom: T<--3+T+1; T:address of local or global 0
XM0415> MAR<-lefthalf+T; start memory cycle
XM0421> L<-righthalf;
XM0422> IPcomx: T<-MD, IDISP; T:local/global value
XM0424> MAR<-M+T, :pushMD; start fetch/store
;-----------------------------------------------------------------
; RIL0 - push <<>>
;-----------------------------------------------------------------
!1,2,RILxB,RILxA;
XM1527> RIL0: MAR<-lp-T-1, :RILxB; fetch local 0
XM0452> RILxB: IR<-msr0, L<-0, :IPcomx; to pushMD
RILxA: IR<-sr1, L<-sr1 AND T, :IPcomx; to pushMDA, L<-0(!)
;-----------------------------------------------------------------
; RXLP - TOS<-<+<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
XM1522> RXLP: L<-ret3, :Splitalpha; will return to RXLPra
RXLPra: IR<-sr34, :Popsub; fetch TOS
XM0074> RXLPrb: L<-righthalf+T, TASK; L:TOS+alpha[4-7]
XM0425> righthalf<-L, :RILPr; now act like RILP
;-----------------------------------------------------------------
; W r i t e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Wn - < (popped)+n><- (popped)
;-----------------------------------------------------------------
!1,2,WnB,WnA; keep ball 1 in air
XM1506> W0: T<-0, :WnB;
XM1507> W1: T<-ONE, :WnB;
XM1510> W2: T<-2, :WnB;
XM0454> WnB: IR<-sr2, :Wsub; returns to StoreB
WnA: IR<-sr3, :Wsub; returns to StoreA
;-----------------------------------------------------------------
; Write subroutine:
;-----------------------------------------------------------------
!7,1,Wsubx; shake IR<- dispatch
XM0426> Wsub: L<-stkp-1, BUS, :Wsubx;
XM0457> Wsubx: stkp<-L, IDISP, :MAStkT;
;-----------------------------------------------------------------
; WB - < (popped)+alpha><- (popped)
;-----------------------------------------------------------------
XM1511> WB: IR<-sr16, :Getalpha; returns to WBr
XM0056> WBr: :WnB; branch may be pending
;-----------------------------------------------------------------
; WSB - act like WB but with stack values reversed, assuming:
; WSB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!7,1,WSBx; shake stack dispatch
XM1531> WSB: IR<-T<-ret14, :BincomA; alignment requires BincomA
WSBr: T<-M, L<-T, :WSBx;
WSBx: MAR<-ib+T, :WScom;
WScom: temp<-L;
WScoma: L<-stkp-1;
MD<-temp;
mACSOURCE, TASK, :Setstkp;
;-----------------------------------------------------------------
; WS0 - act like WSB but with alpha value of zero
;-----------------------------------------------------------------
!7,1,WS0x; shake stack dispatch
XM1530> WS0: IR<-T<-ret15, :BincomB;
WS0r: T<-M, L<-T, :WS0x;
WS0x: MAR<-T, :WScom;
;-----------------------------------------------------------------
; WILP - <+alpha[0-3]>+alpha[4-7] <- (popped)
;-----------------------------------------------------------------
XM1526> WILP: L<-ret2, :Splitalpha; get halves of alpha
XM0172> WILPr: IR<-sr2; IPcom will exit to StoreB
XM0473> T<-lp, :IPcom; prepare to undiddle
;-----------------------------------------------------------------
; WXLP - +<+alpha[0-3]>+alpha[4-7] <- (both popped)
;-----------------------------------------------------------------
XM1523> WXLP: L<-ret4, :Splitalpha; get halves of alpha
WXLPra: IR<-sr35, :Popsub; fetch TOS
XM0075> WXLPrb: L<-righthalf+T, TASK; L:TOS+alpha[4-7]
XM0474> righthalf<-L, :WILPr; now act like WILP
;-----------------------------------------------------------------
; WDB - temp<-alpha+ (popped), pop into +1 and , assuming:
; WDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1516> WDB: IR<-sr31, :Popsub; returns to Dpop
;-----------------------------------------------------------------
; WD0 - temp<- (popped), pop into +1 and
;-----------------------------------------------------------------
XM1517> WD0: L<-ret6, TASK, :Xpopsub; returns to WD0r
XM0106> D0r: L<-0, :Dpopa;
;-----------------------------------------------------------------
; WSDB - like WDB but with address below data words, assuming:
; WSDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!7,1,WSDBx;
XM1533> WSDB: IR<-sr24, :Popsub; get low data word
XM0064> WSDBra: saveret<-L; stash it briefly
XM0475> IR<-T<-ret20, :BincomA; alignment requires BincomA
WSDBrb: T<-M, L<-T, :WSDBx; L:high data, T:address
WSDBx: MAR<-T<-ib+T+1; start store of low data word
temp<-L, L<-T; temp:high data
temp2<-L, TASK; temp2:updated address
MD<-saveret; stash low data word
MAR<-temp2-1, :WScoma; start store of high data word
;-----------------------------------------------------------------
; L o n g P o i n t e r o p e r a t i o n s
;-----------------------------------------------------------------
!1,1,RWBLcom; drop ball 1
;-----------------------------------------------------------------
; RBL - like RB, but uses a long pointer
;-----------------------------------------------------------------
XM1537> RBL: L<-M AND NOT T, T<-M, SH=0, :RWBLcom; L: ret0, T: L at entry
;-----------------------------------------------------------------
; WBL - like WB, but uses a long pointer
;-----------------------------------------------------------------
XM1540> WBL: L<-T, T<-M, SH=0, :RWBLcom; L: ret1, T: L at entry
;
; Common long pointer code
;
!1,2,RWBLcomB,RWBLcomA;
!1,1,RWBLxa; drop ball 1
!7,1,RWBLxb; shake stkp dispatch
!7,1,WBLx; shake stkp dispatch
!3,4,RBLra,WBLra,WBLrc,;
!3,4,RWBLdone,RBLdone,,WBLdone;
XM0515> RWBLcom: entry<-L, L<-T, :RWBLcomB; stash return, restore L
XM0520> RWBLcomB: IR<-sr37, :Getalpha;
XM0521> RWBLcomA: IR<-sr37, :GetalphaA;
XM0077> RWBLra: IR<-ret23, L<-T, :RWBLxa; L: alpha byte
XM0523> RWBLxa: alpha<-L, :BincomB; stash alpha, get long pointer
RWBLrb: MAR<-BankReg, :RWBLxb; fetch bank register
RWBLxb: L<-T, T<-M; T: low half, L: high half
temp<-L; temp: high pointer
L<-alpha+T; L: low pointer+alpha
T<-MD; T: bank register to save
MAR<-BankReg; reaccess bank register
frame<-L, L<-T; frame: pointer
taskhole<-L, TASK; taskhole: old bank register
MD<-temp, :WBLx; set new alternate bank value
WBLx: XMAR<-frame; start memory access
L<-entry+1, BUS; dispatch RBL/WBL
entry<-L, L<-T, :RBLra; (L<-T for WBLrc only)
RBLra: T<-MD, :RWBLtail; T: data from memory
WBLra: IR<-ret24, :BincomB; returns to WBLrb
WBLrb: T<-M, :WBLx; T: data to write
WBLrc: MD<-M, :RWBLtail; stash data in memory
RWBLtail: MAR<-BankReg;
SINK<-entry, BUS; dispatch return
RWBLdone: MD<-taskhole, :RWBLdone; restore bank register
RBLdone: L<-temp2+1, BUS, :pushT1B; temp2: original stkp-2
WBLdone: L<-temp2, TASK, :Setstkp; temp2: original stkp-3
;-----------------------------------------------------------------
; U n a r y o p e r a t i o n s
;-----------------------------------------------------------------
; XMESA Note: Untail is wired down by a pre-def in MesaROM.mu
;-----------------------------------------------------------------
; INC - TOS <- +1
;-----------------------------------------------------------------
XM1657> INC: IR<-sr14, :Popsub;
XM0054> INCr: T<-0+T+1, :pushTB;
;-----------------------------------------------------------------
; NEG - TOS <- -
;-----------------------------------------------------------------
XM1656> NEG: L<-ret11, TASK, :Xpopsub;
XM0111> NEGr: L<-0-T, :Untail;
;-----------------------------------------------------------------
; DBL - TOS <- 2*
;-----------------------------------------------------------------
XM1653> DBL: IR<-sr25, :Popsub;
XM0065> DBLr: L<-M+T, :Untail;
;-----------------------------------------------------------------
; Unary operation common code
;-----------------------------------------------------------------
XM0407> Untail: T<-M, :pushTB;
;-----------------------------------------------------------------
; S t a c k a n d M i s c e l l a n e o u s O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PUSH - add 1 to stack pointer
;-----------------------------------------------------------------
!1,1,PUSHx;
XM1564> PUSH: L<-stkp+1, BUS, :PUSHx; BUS checks for overflow
XM0553> PUSHx: SINK<-ib, BUS=0, TASK, :Setstkp; pick up ball 1
;-----------------------------------------------------------------
; POP - subtract 1 from stack pointer
;-----------------------------------------------------------------
XM1565> POP: L<-stkp-1, SH=0, TASK, :Setstkp; L=0 <=> branch 1 pending
; need not check stkp=0
;-----------------------------------------------------------------
; DUP - temp<- (popped), push , push
;-----------------------------------------------------------------
!1,1,DUPx;
XM1570> DUP: IR<-sr2, :DUPx; returns to pushTB
XM0555> DUPx: L<-stkp, BUS, TASK, :Popsuba; don't pop stack
;-----------------------------------------------------------------
; EXCH - exchange top two stack elements
;-----------------------------------------------------------------
!1,1,EXCHx; drop ball 1
XM1566> EXCH: IR<-ret11, :EXCHx;
XM0571> EXCHx: L<-stkp-1; dispatch on stkp-1
XM0552> L<-M+1, BUS, TASK, :Bincomd; set temp2<-stkp
EXCHr: T<-M, L<-T, :dpush; Note: dispatch using temp2
;-----------------------------------------------------------------
; LADRB - push alpha+lp (undiddled)
;-----------------------------------------------------------------
!1,1,LADRBx; shake branch from Getalpha
XM1472> LADRB: IR<-sr10, :Getalpha; returns to LADRBr
XM0050> LADRBr: T<-nlpoffset+T+1, :LADRBx;
XM0573> LADRBx: L<-lp+T, :Untail;
;-----------------------------------------------------------------
; GADRB - push alpha+gp (undiddled)
;-----------------------------------------------------------------
!1,1,GADRBx; shake branch from Getalpha
XM1472> GADRB: IR<-sr11, :Getalpha; returns to GADRBr
XM0051> GADRBr: T<-ngpoffset+T+1, :GADRBx;
XM0575> GADRBx: L<-gp+T, :Untail;
;-----------------------------------------------------------------
; S t r i n g O p e r a t i o n s
;-----------------------------------------------------------------
!7,1,STRsub; shake stack dispatch
!1,2,STRsubA,STRsubB;
!1,2,RSTRrx,WSTRrx;
STRsub: L<-stkp-1; update stack pointer
stkp<-L;
L<-ib+T; compute index and offset
SINK<-M, BUSODD, TASK;
count<-L RSH 1, :STRsubA;
STRsubA: L<-177400, :STRsubcom; left byte
STRsubB: L<-377, :STRsubcom; right byte
STRsubcom: T<-temp; get string address
MAR<-count+T; start fetch of word
T<-M; move mask to more useful place
SINK<-DISP, BUSODD; dispatch to caller
mask<-L, SH<0, :RSTRrx; dispatch B/A, mask for WSTR
;-----------------------------------------------------------------
; RSTR - push byte of string using base () and index ()
; assumes RSTR is A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
!1,2,RSTRB,RSTRA;
XM1520> RSTR: IR<-T<-ret12, :BincomB;
RSTRr: temp<-L, :STRsub; stash string base address
RSTRrx: L<-MD AND T, TASK, :RSTRB; isolate good bits
RSTRB: temp<-L, :RSTRcom;
RSTRA: temp<-L LCY 8, :RSTRcom; right-justify byte
RSTRcom: T<-temp, :pushTA; go push result byte
;-----------------------------------------------------------------
; WSTR - pop into string byte using base () and index ()
; assumes WSTR is A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
!1,2,WSTRB,WSTRA;
XM1521> WSTR: IR<-T<-ret13, :BincomB;
WSTRr: temp<-L, :STRsub; stash string base
WSTRrx: L<-MD AND NOT T, :WSTRB; isolate good bits
WSTRB: temp2<-L, L<-ret0, TASK, :Xpopsub; stash them, return to WSTRrB
WSTRA: temp2<-L, L<-ret0+1, TASK, :Xpopsub; stash them, return to WSTRrA
XM0101> WSTRrA: taskhole<-L LCY 8; move new data to odd byte
XM0633> T<-taskhole, :WSTRrB;
XM0100> WSTRrB: T<-mask.T;
XM0636> L<-temp2 OR T;
XM0637> T<-temp; retrieve string address
XM0640> MAR<-count+T;
XM0641> TASK;
XM0642> MD<-M, :nextA;
;-----------------------------------------------------------------
; F i e l d I n s t r u c t i o n s
;-----------------------------------------------------------------
; temp2 is coded as follows:
; 0 - RF, RFS
; 1 - WF, WSF, WFS
; 2 - RFC
%1,3,2,RFrr,WFrr; returns from Fieldsub
!7,1,Fieldsub; shakes stack dispatch
; !7,1,WFr; (required by WSFr) is implicit in ret17 (!)
;-----------------------------------------------------------------
; RF - push field specified by beta in word at (popped) + alpha
; if RF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after RF
;-----------------------------------------------------------------
XM1512> RF: IR<-sr12, :Popsub;
XM0052> RFr: L<-ret0, :Fieldsub;
RFrr: T<-mask.T, :pushTA; alignment requires pushTA
;-----------------------------------------------------------------
; WF - pop data in into field specified by beta in word at (popped) + alpha
; if WF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after WF
;-----------------------------------------------------------------
; !1,2,WFnzct,WFret; - see location-specific definitions
XM1513> WF: IR<-T<-ret17, :BincomB; L:new data, T:address
WFr: newfield<-L, L<-ret0+1, :Fieldsub; (actually, L<-ret1)
WFrr: T<-mask;
L<-M AND NOT T; set old field bits to zero
temp<-L; stash result
T<-newfield.T; save new field bits
L<-temp OR T, TASK; merge old and new
CYCOUT<-L; stash briefly
T<-index, BUS=0; get position, test for zero
L<-WFretloc, :WFnzct; get return address from ROM
WFnzct: PC<-L; stash return
L<-20-T, SWMODE; L:remaining count to cycle
T<-CYCOUT, :RAMCYCX; go cycle remaining amount
WFret: MAR<-frame; start memory
L<-stkp-1; pop remaining word
MD<-CYCOUT, TASK, :JZNEBeq; stash data, go update stkp
;-----------------------------------------------------------------
; WSF - like WF, but with top two stack elements reversed
; if WSF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after WSF
;-----------------------------------------------------------------
XM1532> WSF: IR<-T<-ret16, :BincomB; L:address, T:new data
WSFr: L<-T, T<-M, :WFr;
;-----------------------------------------------------------------
; RFS - like RF, but with a word containing alpha and beta on top of stack
; if RFS is A-aligned, B byte is irrelevant
;-----------------------------------------------------------------
XM1535> RFS: L<-ret12, TASK, :Xpopsub; get alpha and beta
XM0112> RFSra: temp<-L; stash for WFSa
XM0661> L<-ret13, TASK, :Xpopsub; T:address
XM0113> RFSrb: L<-ret0, BUS=0, :Fieldsub; returns quickly to WFSa
;-----------------------------------------------------------------
; WFS - like WF, but with a word containing alpha and beta on top of stack
; if WFS is A-aligned, B byte is irrelevant
;-----------------------------------------------------------------
!1,2,Fieldsuba,WFSa;
XM1536> WFS: L<-ret14, TASK, :Xpopsub; get alpha and beta
XM0114> WFSra: temp<-L; stash temporarily
XM0664> IR<-T<-ret21, :BincomB; L:new data, T:address
WFSrb: newfield<-L, L<-ret0+1, BUS=0, :Fieldsub; returns quickly to WFSa
WFSa: frame<-L; stash address
T<-177400; to separate alpha and beta
L<-temp AND T, T<-temp, :Getalphab; L:alpha, T:both
; returns to Fieldra
;-----------------------------------------------------------------
; RFC - like RF, but uses ++ as address
; if RFC is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after RF
;-----------------------------------------------------------------
XM1534> FC: L<-ret16, TASK, :Xpopsub; get index into code segment
XM0116> RFCr: L<-cp+T;
XM0667> T<-M; T:address
XM0670> L<-ret2, :Fieldsub; returns to RFrr
;-----------------------------------------------------------------
; Field instructions common code
; Entry conditions:
; L holds return offset
; T holds base address
; Exit conditions:
; mask: right-justified mask
; frame: updated address, including alpha
; index: left cycles needed to right-justify field [0-15]
; L,T: data word from location cycled left bits
;-----------------------------------------------------------------
%2,3,1,NotCodeSeg,IsCodeSeg;
XM0657> Fieldsub: temp2<-L, L<-T, IR<-msr0, TASK, :Fieldsuba; stash return
XM0662> Fieldsuba: frame<-L, :GetalphaA; stash base address
; T: beta, ib: alpha
XM0040> Fieldra: L<-ret5;
XM0672> saveret<-L, :Splitcomr; get two halves of beta
Fieldrb: T<-righthalf; index for MASKTAB
MAR<-MASKTAB+T; start fetch of mask
T<-lefthalf+T+1; L:left-cycle count
L<-17 AND T; mask to 4 bits
index<-L; stash position
L<-MD, TASK; L:mask for caller's use
mask<-L; stash mask
SINK<-temp2, BUS; temp2=2 <=> RFC
T<-frame, :NotCodeSeg; get base address
NotCodeSeg: L<-MAR<-ib+T, :StashFieldLoc; add alpha
IsCodeSeg: XMAR<-ib+T, :DoCycle; add alpha
StashFieldLoc: frame<-L, :DoCycle; stash updated address for WF
DoCycle: L<-Fieldretloc; return location from RAMCYCX
PC<-L;
T<-MD, SWMODE; data word into T for cycle
L<-index, :RAMCYCX; count to cycle, go do it
Fieldrc: SINK<-temp2, BUSODD; return dispatch
L<-T<-CYCOUT, :RFrr; cycled data word in L and T
; *** 11/23/15 - END OF MESACROM.MU ***
#MesadROM.mu;
; *** 11/23/15 - START OF MESADROM.MU ***
;-----------------------------------------------------------------
; MesadROM.Mu - Xfer, State switching, process support, Nova interface
; Last modified by Levin - February 27, 1979 4:50 PM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; F r a m e A l l o c a t i o n
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Alloc subroutine:
; allocates a frame
; Entry conditions:
; frame size index (fsi) in T
; Exit conditions:
; frame pointer in L, T, and frame
; if allocation fails, alternate return address is taken and
; temp2 is shifted left by 1 (for ALLOC)
;-----------------------------------------------------------------
!1,2,ALLOCr,XferGr; subroutine returns
!1,2,ALLOCrf,XferGrf; failure returns
!3,4,Alloc0,Alloc1,Alloc2,Alloc3; dispatch on pointer flag
; if more than 2 callers, un-comment the following pre-definition:
; !17,1,Allocx; shake IR<- dispatch
XM0722> AllocSub: L<-avm1+T+1, TASK, :Allocx; fetch av entry
XM0723> Allocx: entry<-L; save av entry address
XM0730> L<-MAR<-entry;
XM0731> T<-3; mask for pointer flags
XM0732> L<-MD AND T, T<-MD; (L<-MD AND 3, T<-MD)
XM0733> temp<-L, L<-MAR<-T; start reading pointer
XM0734> SINK<-temp, BUS; branch on bits 14:15
XM0735> frame<-L, :Alloc0;
;
; Bits 14:15 = 00, a frame of the right index is queued for allocation
;
XM0724> Alloc0: L<-MD, TASK; new entry for frame vector
XM0736> temp<-L; new value of vector entry
XM0737> MAR<-entry; update frame vector
XM0740> L<-T<-frame, IDISP; establish exit conditions
XM0741> MD<-temp, :ALLOCr; update and return
;
; Bits 14:15 = 01, allocation list empty: restore argument, take failure return
;
XM0725> Alloc1: L<-temp2, IDISP, TASK; restore parameter
XM0742> temp2<-L LSH 1, :ALLOCrf; allocation failed
;
; Bits 14:15 = 10, a pointer to an alternate list to use
;
XM0726> Alloc2: temp<-L RSH 1, :Allocp; indirection: index<-index/4
XM0743> Allocp: L<-temp, TASK;
XM0744> temp<-L RSH 1;
XM0745> T<-temp, :AllocSub;
XM0727> Alloc3: temp<-L RSH 1, :Allocp; (treat type 3 as type 2)
;-----------------------------------------------------------------
; Free subroutine:
; frees a frame
; Entry conditions: address of frame is in 'frame'
; Exit conditions: 'frame' left pointing at released frame (for LSTF)
;-----------------------------------------------------------------
!3,4,RETr,FREEr,LSTFr,; FreeSub returns
!17,1,Freex; shake IR<- dispatch
XM0746> FreeSub: MAR<-frame-1; start read of fsi word
XM0757> Freex: NOP; wait for memory
XM0747> T<-MD; T<-index
XM0753> L<-MAR<-avm1+T+1; fetch av entry
XM0754> entry<-L; save av entry address
XM0755> L<-MD; read current pointer
XM0756> MAR<-frame; write it into current frame
XM0760> temp<-L, TASK;
XM0761> MD<-temp; write!
XM0762> MAR<-entry; entry points at frame
XM0763> IDISP, TASK;
XM0764> MD<-frame, :RETr; free
;-----------------------------------------------------------------
; ALLOC - allocate a frame whose fsi is specified by (popped)
;-----------------------------------------------------------------
!1,1,Savpcinframe; (here so ALLOCrf can call it)
; The following logically belongs here; however, because the entry point to general Xfer is
; known to the outside world, the real declaration appears in MesaROM.mu.
; !7,10,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr,,; return points for Savpcinframe
!1,2,doAllocTrap,XferGfz; used by XferGrf
XM1756> ALLOC: L<-ret7, TASK, :Xpopsub; returns to ALLOCrx
XM0107> ALLOCrx: temp2<-L LSH 1, IR<-msr0, :AllocSub; L,T: fsi
XM0716> ALLOCr: L<-stkp+1, BUS, :pushT1B; duplicates pushTB
;
; Allocation failed - save mpc, undiddle lp, push fsi*4 on stack, then trap
;
XM0720> ALLOCrf: IR<-sr5, :Savpcinframe; failure because lists empty
ALLOCrfr: L<-temp2, TASK, :doAllocTrap; pick up trap parameter
;
; Inform software that allocation failed
;
doAllocTrap: ATPreg<-L; store param. to trap proc.
T<-sAllocTrap, :Mtrap; go trap to software
;-----------------------------------------------------------------
; FREE - release the frame whose address is (popped)
;-----------------------------------------------------------------
XM1757> FREE: L<-ret10, TASK, :Xpopsub; returns to FREErx
XM0110> FREErx: frame<-L, TASK;
XM0771> IR<-sr1, :FreeSub;
FREEr: :next;
;-----------------------------------------------------------------
; D e s c r i p t o r I n s t r u c t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; DESCB - push <+gfi offset>+2*alpha+1 (masking gfi word appropriately)
; DESCB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1750> DESCB: T<-gp;
XM0772> T<-ngpoffset+T+1, :DESCBcom; T:address of frame
XM0115> DESCBcom: MAR<-gfioffset+T; start fetch of gfi word
XM0773> T<-gfimask; mask to isolate gfi bits
XM0774> T<-MD.T; T:gfi
XM0775> L<-ib+T, T<-ib; L:gfi+alpha, T:alpha
XM1025> T<-M+T+1, :pushTA; pushTA because A-aligned
;-----------------------------------------------------------------
; DESCBS - push <+gfi offset>+2*alpha+1 (masking gfi word appropriately)
; DESCBS is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1751> DESCBS: L<-ret15, TASK, :Xpopsub; returns to DESCBcom
;-----------------------------------------------------------------
; T r a n s f e r O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Savpcinframe subroutine:
; stashes C-relative (mpc,ib) in current local frame
; undiddles lp into my and lp
; Entry conditions: none
; Exit conditions:
; current frame+1 holds pc relative to code segment base (+ = even, - = odd)
; lp is undiddled
; my has undiddled lp (source link for Xfer)
;-----------------------------------------------------------------
; !1,1,Savpcinframe; required by PORTO
; !7,10,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr,,; returns (appear with ALLOC)
!7,1,Savpcx; shake IR<- dispatch
!1,2,Spcodd,Spceven; pc odd or even
XM0765> Savpcinframe: T<-cp, :Savpcx; code segment base
XM1027> Savpcx: L<-mpc-T; L is code-relative pc
XM1026> SINK<-ib, BUS=0; check for odd or even pc
XM1032> T<-M, :Spcodd; pick up pc word addr
XM1030> Spcodd: L<-0-T, TASK, :Spcopc; - pc => odd, this word
XM1031> Spceven: L<-0+T+1, TASK, :Spcopc; + pc => even, next word
XM1033> Spcopc: taskhole<-L; pc value to save
XM1034> L<-0; (can't merge above - TASK)
XM1035> T<-npcoffset; offset to pc stash
XM1036> MAR<-lp-T, T<-lp; (MAR<-lp-npcoffset, T<-lp)
XM1037> ib<-L; clear ib for XferG
XM1040> L<-nlpoffset+T+1; L:undiddled lp
XM1041> MD<-taskhole; stash pc in frame+pcoffset
XM1042> my<-L, IDISP, TASK; store undiddled lp
XM1043> lp<-L, :XferGT;
;-----------------------------------------------------------------
; Loadgc subroutine:
; load global pointer and code pointer given local pointer or GFT pointer
; Entry conditions:
; T contains either local frame pointer or GFT pointer
; memory fetch of T has been started
; pending branch (1) catches zero pointer
; Exit conditions:
; lp diddled (to framebase+6)
; mpc set from second word of entry (PC or EV offset)
; first word of code segment set to 1 (used by code swapper)
; Assumes only 2 callers
;-----------------------------------------------------------------
!1,2,Xfer0r,Xfer1r; return points
!1,2,Loadgc,LoadgcTrap;
!1,2,LoadgcOK,LoadgcNull; good global frame or null
!1,2,LoadgcIn,LoadgcSwap; in-core or swapped out
!1,2,LoadgcDiv2,LoadgcDiv4; first/second shift
!1,2,LoadgcNoXM,LoadgcIsXM; short/long codebase
XM1046> Loadgc: L<-lpoffset+T; diddle (presumed) lp
XM1060> lp<-L; (only correct if frame ptr)
XM1061> T<-MD; global frame address
XM1062> L<-MD; 2nd word (PC or EV offset)
XM1063> MAR<-cpoffset+T; read code pointer
XM1064> mpc<-L, L<-T; copy g to L for null test
XM1065> L<-cpoffset+T+1, SH=0; test gf=0
XM1066> taskhole<-L, :LoadgcOK; taskhole:addr of hi code base
XM1050> LoadgcOK: L<-MD, BUSODD, TASK; L: low bits of code base
XM1067> cp<-L, :LoadgcIn; stash low bits, branch if odd
XM1052> LoadgcIn: MAR<-BankReg; access bank register
XM1070> T<-14; mask to save primary bank
XM1071> L<-MD AND T; L: primary bank *4
XM1072> temp2<-L, :LoadgcShift; temp2: primary bank *4
XM1073> LoadgcShift: newfield<-L RSH 1, L<-0-T, :LoadgcDiv2; newfield: bank*2, L: negative
XM1054> LoadgcDiv2: L<-newfield, SH<0, TASK, :LoadgcShift; SH<0 forces branch, TASK safe
XM1055> LoadgcDiv4: MAR<-T<-taskhole; fetch high bits of code base
XM1074> L<-gpcpoffset+T; diddle gp
XM1075> gp<-L;
XM1076> T<-177400; mask for high bits
XM1077> L<-MD AND T, T<-MD;
XM1100> T<-3.T, SH=0; T: bank if long codebase
XM1101> MAR<-BankReg, :LoadgcNoXM; initiate store
XM1056> LoadgcNoXM: T<-newfield, :LoadgcIsXM; T: MDS bank
XM1057> LoadgcIsXM: L<-temp2 OR T, TASK; L: new bank registers
XM1102> MD<-M; stash bank
XM1103> XMAR<-cp; access first cseg word
XM1104> IDISP, TASK; dispatch return
XM1105> MD<-ONE, :Xfer0r;
;
; picked up global frame of zero somewhere, call it unbound
;
!1,1,Stashmx;
LoadgcNull: T<-sUnbound, :Stashmx; BUSODD may be pending
;
; swapped code segment, trap to software
;
LoadgcSwap: T<-sSwapTrap, :Stashmx;
;
; destination link = 0
;
LoadgcTrap: T<-sControlFault, :Mtrap;
;-----------------------------------------------------------------
; CheckXferTrap subroutine:
; Handles Xfer trapping
; Entry conditions:
; IR: return number in DISP
; T: parameter to be passed to trap routine
; Exit conditions:
; if trapping enabled, initiates trap and doesn't return.
;------------------------------------------------------------------
!3,4,Xfers,XferG,RETxr,; returns from CheckXferTrap
!1,2,NoXferTrap,DoXferTrap;
!3,1,DoXferTrapx;
XM01106> CheckXferTrap: L<-XTSreg, BUSODD; XTSreg[15]=1 => trap
XM01116> SINK<-DISP, BUS, :NoXferTrap; dispatch (possible) return
XM01114> NoXferTrap: XTSreg<-L RSH 1, :Xfers; reset XTSreg[15] to 0 or 1
XM01115> DoXferTrap: L<-DISP, :DoXferTrapx; tell trap handler which case
DoXferTrapx: XTSreg<-L LCY 8, L<-T; L:trap parameter
XTPreg<-L;
T<-sXferTrap, :Mtrap; off to trap sequence
;-----------------------------------------------------------------
; Xfer open subroutine:
; decodes general destination link for Xfer
; Entry conditions:
; source link in my
; destination link in mx
; Exit conditions:
; if destination is frame pointer, does complete xfer and exits to Ifetch.
; if destination is procedure descriptor, locates global frame and entry
; number, then exits to 'XferG'.
;------------------------------------------------------------------
!3,4,Xfer0,Xfer1,Xfer2,Xfer3; destination link type
XM00431> Xfer: T<-mx; mx[14:15] is dest link type
XM01121> IR<-0, :CheckXferTrap;
XM01110> Xfers: L<-3 AND T; extract type bits
XM01122> SINK<-M, L<-T, BUS; L:dest link, branch on type
XM01123> SH=0, MAR<-T, :Xfer0; check for link = 0. Memory
; data is used only if link
; is frame pointer or indirect
;-----------------------------------------------------------------
; mx[14-15] = 00
; Destination link is frame pointer
;-----------------------------------------------------------------
XM01124> Xfer0: IR<-msr0, :Loadgc; to LoadgcNull if dest link = 0
XM1044> Xfer0r: L<-T<-mpc; offset from cp: - odd, + even
;
; If 'brkbyte' ~= 0, we are proceeding from a breakpoint.
; pc points to the BRK instruction:
; even pc => fetch word, stash left byte in ib, and execute brkbyte
; odd pc => clear ib, execute brkbyte
;
!1,2,Xdobreak,Xnobreak;
!1,2,Xfer0B,Xfer0A;
!1,2,XbrkB,XbrkA;
!1,2,XbrkBgo,XbrkAgo;
XM1140> SINK<-brkbyte, BUS=0; set up by Loadstate
XM1141> SH<0, L<-0, :Xdobreak; dispatch even/odd pc
;
; Not proceeding from a breakpoint - simply pick up next instruction
;
XM1131> Xnobreak: :Xfer0B;
XM1132> Xfer0B: L<-XMAR<-cp+T, :nextAdeafa; fetch word, pc even
XM1133> Xfer0A: L<-XMAR<-cp-T; fetch word, pc odd
XM1142> mpc<-L, :nextXBni;
;
; Proceeding from a breakpoint - dispatch brkbyte and clear it
;
XM1130> Xdobreak: ib<-L, :XbrkB; clear ib for XbrkA
XM1134> XbrkB: IR<-sr20; here if BRK at even byte
XM1143> L<-XMAR<-cp+T, :GetalphaAx; set up ib (return to XbrkBr)
XM1135> XbrkA: L<-cp-T; here if BRK at odd byte
XM1144> mpc<-L, L<-0, BUS=0, :XbrkBr; ib already zero (to XbrkAgo)
XM0060> XbrkBr: SINK<-brkbyte, BUS, :XbrkBgo; dispatch brkbyte
XM1136> XbrkBgo: brkbyte<-L RSH 1, T<-0+1, :NOOP; clear brkbyte, act like nextA
XM1137> XbrkAgo: brkbyte<-L, T<-0+1, BUS=0, :NOOP; clear brkbyte, act like next
;-----------------------------------------------------------------
; mx[14-15] = 01
; Destination link is procedure descriptor:
; mx[0-8]: GFT index (gfi)
; mx[9-13]: EV bias, or entry number (en)
;-----------------------------------------------------------------
Xfer1: temp<-L RSH 1; temp:ep*2+garbage
count<-L MLSH 1; since L=T, count<-L LCY 1;
L<-count, TASK; gfi now in 0-7 and 15
count<-L LCY 8; count:gfi w/high bits garbage
L<-count, TASK;
count<-L LSH 1; count:gfi*2 w/high garbage
T<-count;
T<-1777.T; T:gfi*2
MAR<-gftm1+T+1; fetch GFT[T]
IR<-sr1, :Loadgc; pick up two word entry into
; gp and mpc
Xfer1r: L<-temp, TASK; L:en*2+high bits of garbage
count<-L RSH 1; count:en+high garbage
T<-count;
T<-enmask.T; T:en
L<-mpc+T+1, TASK; (mpc has EV base in code seg)
count<-L LSH 1, :XferG; count:ep*2
;-----------------------------------------------------------------
; mx[14-15] = 10
; Destination link is indirect:
; mx[0-15]: address of location holding destination link
;-----------------------------------------------------------------
Xfer2: NOP; wait for memory
T<-MD, :Xfers;
;-----------------------------------------------------------------
; mx[14-15] = 11
; Destination link is unbound:
; mx[0-15]: passed to trap handler
;-----------------------------------------------------------------
Xfer3: T<-sUnbound, :Stashmx;
;-----------------------------------------------------------------
; XferG open subroutine:
; allocates new frame and patches links
; Entry conditions:
; 'count' holds index into code segment entry vector
; assumes lp is undiddled (in case of AllocTrap)
; assumes gp (undiddled) and cp set up
; Exit conditions:
; exits to instruction fetch (or AllocTrap)
;-----------------------------------------------------------------
;
; Pick up new pc from specified entry in entry vector
;
XM0430> XferGT: T<-count; parameter to CheckXferTrap
XM1164> IR<-ONE, :CheckXferTrap;
XferG: T<-count; index into entry vector
XMAR<-cp+T; fetch of new pc and fsi
T<-cp-1; point just before bytes
; (main loop increments mpc)
IR<-sr1; note: does not cause branch
L<-MD+T; relocate pc from cseg base
T<-MD; second word contains fsi
mpc<-L; new pc setup, ib already 0
T<-377.T, :AllocSub; mask for size index
;
; Stash source link in new frame, establishing dynamic link
;
XferGr: MAR<-retlinkoffset+T; T has new frame base
L<-lpoffset+T; diddle new lp
lp<-L; install diddled lp
MD<-my; source link to new frame
;
; Stash new global pointer in new frame (same for local call)
;
MAR<-T; write gp to word 0 of frame
T<-gpoffset; offset to point at gf base
L<-gp-T, TASK; subtract off offset
MD<-M, :nextAdeaf; global pointer stashed, GO!
;
; Frame allocation failed - push destination link, then trap
;
; !1,2,doAllocTrap,XferGfz; (appears with ALLOC)
XferGrf: L<-mx, BUS=0; pick up destination, test = 0
T<-count-1, :doAllocTrap; T:2*ep+1
; if destination link is zero (i.e. local procedure call), we must first
; fabricate the destination link
XferGfz: L<-T, T<-ngfioffset; offset from gp to gfi word
MAR<-gp-T; start fetch of gfi word
count<-L LSH 1; count:4*ep+2
L<-count-1; L:4*ep+1
T<-gfimask; mask to save gfi only
T<-MD.T; T:gfi
L<-M+T, :doAllocTrap; L:gfi+4*ep+1 (descriptor)
;-----------------------------------------------------------------
; Getlink subroutine:
; fetches control link from either global frame or code segment
; Entry conditions:
; temp: - (index of desired link + 1)
; IR: DISP field zero/non-zero to select return point (2 callers only)
; Exit conditions:
; L,T: desired control link
;-----------------------------------------------------------------
!1,2,EFCgetr,LLKBr; return points
!1,2,framelink,codelink;
!7,1,Fetchlink; shake IR<- in KFCB
XM1216> Getlink: T<-gp; diddled frame address
XM1220> MAR<-T<-ngpoffset+T+1; fetch word 0 of global frame
XM1221> L<-temp+T, T<-temp; L:address of link in frame
XM1222> taskhole<-L; stash it
XM1223> L<-cp+T; L:address of link in code
XM1224> SINK<-MD, BUSODD, TASK; test bit 15 of word zero
XM1225> temp2<-L, :framelink; stash code link address
XM1214> framelink: MAR<-taskhole, :Fetchlink; fetch link from frame
XM1215> codelink: XMAR<-temp2, :Fetchlink; fetch link from code
XM1217> Fetchlink: SINK<-DISP, BUS=0; dispatch to caller
XM1226> L<-T<-MD, :EFCgetr;
;-----------------------------------------------------------------
; EFCn - perform XFER to destination specified by external link n
;-----------------------------------------------------------------
; !1,1,EFCr; implicit in EFCr's return number (23B)
XM1700> EFC0: IR<-ONE, T<-ONE-1, :EFCr; 0th control link
XM1701> EFC1: IR<-T<-ONE, :EFCr; 1st control link
XM1702> EFC2: IR<-T<-2, :EFCr; . . .
XM1703> EFC3: IR<-T<-3, :EFCr;
XM1704> EFC4: IR<-T<-4, :EFCr;
XM1705> EFC5: IR<-T<-5, :EFCr;
XM1706> EFC6: IR<-T<-6, :EFCr;
XM1707> EFC7: IR<-T<-7, :EFCr;
XM1710> EFC8: IR<-T<-10, :EFCr;
XM1711> EFC9: IR<-T<-11, :EFCr;
XM1712> EFC10: IR<-T<-12, :EFCr;
XM1713> EFC11: IR<-T<-13, :EFCr;
XM1714> EFC12: IR<-T<-14, :EFCr;
XM1715> EFC13: IR<-T<-15, :EFCr;
XM1716> EFC14: IR<-T<-16, :EFCr;
XM1717> EFC15: IR<-T<-17, :EFCr;
;-----------------------------------------------------------------
; EFCB - perform XFER to destination specified by external link 'alpha'
;-----------------------------------------------------------------
!1,1,EFCdoGetlink; shake B/A dispatch (Getalpha)
XM1720> EFCB: IR<-sr23, :Getalpha; fetch link number
XM0063> EFCr: L<-0-T-1, TASK, :EFCdoGetlink; L:-(link number+1)
XM1227> EFCdoGetlink: temp<-L, :Getlink; stash index for Getlink
XM1212> EFCgetr: IR<-sr1, :SFCr; for Savpcinframe; no branch
;-----------------------------------------------------------------
; SFC - Stack Function Call (using descriptor on top of stack)
;-----------------------------------------------------------------
XM1742> SFC: IR<-sr1, :Popsub; get dest link for xfer
; now assume IR still has sr1
XM0041> SFCr: mx<-L, :Savpcinframe; set dest link, return to Xfer
;-----------------------------------------------------------------
; KFCB - Xfer using destination <+alpha>
;-----------------------------------------------------------------
; !1,1,KFCr; implicit in KFCr's return number (21B)
!1,1,KFCx; shake B/A dispatch (Getalpha)
; !7,1,Fetchlink; appears with Getlink
XM1747> KFCB: IR<-sr21, :Getalpha; fetch alpha
XM0061> KFCr: IR<-avm1, T<-avm1+T+1, :KFCx; DISP must be non zero
XM1231> KFCx: MAR<-sdoffset+T, :Fetchlink; Fetchlink shakes IR<- dispatch
;-----------------------------------------------------------------
; BRK - Breakpoint (equivalent to KFC 0)
;-----------------------------------------------------------------
KM1776> BRK: ib<-L, T<-sBRK, :KFCr; ib = 0 <=> BRK B-aligned
;-----------------------------------------------------------------
; Trap sequence:
; used to report various faults during Xfer
; Entry conditions:
; T: index in SD through which to trap
; Savepcinframe has already been called
; entry at Stashmx puts destination link in OTPreg before trapping
;-----------------------------------------------------------------
; !1,1,Stashmx; above with Loadgc code
Stashmx: L<-mx; can't TASK, T has trap index
OTPreg<-L, :Mtrap;
Mtrap: T<-avm1+T+1;
MAR<-sdoffset+T; fetch dest link for trap
NOP;
XM1235> Mtrapa: L<-MD, TASK; (enter here from PORTO)
XM1236> mx<-L, :Xfer;
;-----------------------------------------------------------------
; LFCn - call local procedure n (i.e. within same global frame)
;-----------------------------------------------------------------
!1,1,LFCx; shake B/A dispatch
XM1721> LFC1: L<-2, :LFCx;
XM1722> LFC2: L<-3, :LFCx;
XM1723> LFC3: L<-4, :LFCx;
XM1724> LFC4: L<-5, :LFCx;
XM1725> LFC5: L<-6, :LFCx;
XM1726> LFC6: L<-7, :LFCx;
XM1727> LFC7: L<-10, :LFCx;
XM1730> LFC8: L<-11, :LFCx;
XM1237> LFCx: count<-L LSH 1, L<-0, IR<-msr0, :SFCr; stash index of proc. (*2)
; dest link = 0 for local call
; will return to XferG
;-----------------------------------------------------------------
; LFCB - call local procedure number 'alpha' (i.e. within same global frame)
;-----------------------------------------------------------------
XM1741> LFCB: IR<-sr22, :Getalpha;
XM0062> LFCr: L<-0+T+1, :LFCx;
;-----------------------------------------------------------------
; RET - Return from function call.
;-----------------------------------------------------------------
!1,1,RETx; shake B/A branch
XM1743> RET: T<-lp, :RETx; local pointer
XM1241> RETx: IR<-2, :CheckXferTrap;
RETxr: MAR<-nretlinkoffset+T; get previous local frame
L<-nlpoffset+T+1;
frame<-L; stash for 'Free'
L<-MD; pick up prev frame pointer
mx<-L, L<-0, IR<-msr0, TASK; mx points to caller
my<-L, :FreeSub; clear my and go free frame
XM0750> RETr: T<-mx, :Xfers; xfer back to caller
;-----------------------------------------------------------------
; LINKB - store back link to enclosing context into local 0
; LINKB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1567> LINKB: MAR<-lp-T-1; address of local 0
XM1246> T<-ib;
XM1247> L<-mx-T, TASK; L: mx-alpha
XM1250> MD<-M, :nextA; local 0 <- mx-alpha
;-----------------------------------------------------------------
; LLKB - push external link 'alpha'
; LLKB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1744> LLKB: T<-ib; T:alpha
XM1251> L<-0-T-1, IR<-0, :EFCdoGetlink; L:-(alpha+1), go call Getlink
LLKBr: :pushTA; alignment requires pushTA
;-----------------------------------------------------------------
; P o r t O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PORTO - PORT Out (XFER thru PORT addressed by TOS)
;-----------------------------------------------------------------
XM1745> PORTO: IR<-sr3, :Savpcinframe; undiddle lp into my
PORTOpc: L<-ret5, TASK, :Xpopsub; returns to PORTOr
XM0105> PORTOr: MAR<-T; fetch from TOS
XM1252> L<-T;
XM1253> MD<-my; frame addr to word 0 of PORT
XM1254> MAR<-M+1; second word of PORT
XM1255> my<-L, :Mtrapa; source link to PORT address
;-----------------------------------------------------------------
; PORTI - PORT In (Fix up PORT return, always immediately after PORTO)
; assumes that my and mx remain from previous xfer
;-----------------------------------------------------------------
!1,1,PORTIx;
!1,2,PORTInz,PORTIz;
XM1746> PORTI: MAR<-mx, :PORTIx; first word of PORT
XM1257> PORTIx: SINK<-my, BUS=0;
XM1256> TASK, :PORTInz;
XM1260> PORTInz: MD<-0;
XM1262> MAR<-mx+1; store it as second word
XM1263> TASK, :PORTIz;
XM1261> PORTIz: MD<-my, :next; store my or zero
;-----------------------------------------------------------------
; S t a t e S w i t c h i n g
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Savestate subroutine:
; saves state of pre-empted emulation
; Entry conditions:
; L holds address where state is to be saved
; assumes undiddled lp
; Exit conditions:
; lp, stkp, and stack (from base to min[depth+2,8]) saved
;-----------------------------------------------------------------
; !1,2,DSTr1,Mstopc; actually appears as %1,1777,776,DSTr1,Mstopc; and is located
; in the front of the main file (Mesa.mu).
!17,20,Sav0r,Sav1r,Sav2r,Sav3r,Sav4r,Sav5r,Sav6r,Sav7r,Sav10r,Sav11r,DSTr,,,,,;
!1,2,Savok,Savmax;
XM1266> Savestate: temp<-L;
XM1267> Savestatea: T<--12+1; i.e. T<--11
XM1270> L<-lp, :Savsuba;
Sav11r: L<-stkp, :Savsub;
Sav10r: T<-stkp+1;
L<--7+T; check if stkp > 5 or negative
L<-0+T+1, ALUCY; L:stkp+2
temp2<-L, L<-0-T, :Savok; L:-stkp-1
Savmax: T<--7; stkp > 5 => save all
L<-stk7, :Savsuba;
Savok: SINK<-temp2, BUS; stkp < 6 => save to stkp+2
count<-L, :Sav0r;
XM1307> Sav7r: L<-stk6, :Savsub;
XM1306> Sav6r: L<-stk5, :Savsub;
XM1305> Sav5r: L<-stk4, :Savsub;
XM1304> Sav4r: L<-stk3, :Savsub;
XM1303> Sav3r: L<-stk2, :Savsub;
XM1302> Sav2r: L<-stk1, :Savsub;
XM1301> Sav1r: L<-stk0, :Savsub;
XM1300> Sav0r: SINK<-DISP, BUS; return to caller
XM1276> T<--12, :DSTr1; (for DST's benefit)
; Remember, T is negative
Savsub: T<-count;
XM1313> Savsuba: temp2<-L, L<-0+T+1;
XM1314> MAR<-temp-T;
XM1315> count<-L, L<-0-T; dispatch on pos. value
XM1316> SINK<-M, BUS, TASK;
XM1317> MD<-temp2, :Sav0r;
;-----------------------------------------------------------------
; Loadstate subroutine:
; load state for emulation
; Entry conditions:
; L points to block from which state is to be loaded
; Exit conditions:
; stkp, mx, my, and stack (from base to min[stkp+2,8]) loaded
; (i.e. two words past TOS are saved, if they exist)
; Note: if stkp underflows but an interrupt is taken before we detect
; it, the subsequent Loadstate (invoked by Mgo) will see 377B in the
; high byte of stkp. Thinking this a breakpoint resumption, we will
; load the state, then dispatch the 377 (via brkbyte) in Xfer0, causing
; a branch to StkUf (!) This is not a fool-proof check against a bad
; stkp value at entry, but it does protect against the most common
; kinds of stack errors.
;-----------------------------------------------------------------
!17,20,Lsr0,Lsr1,Lsr2,Lsr3,Lsr4,Lsr5,Lsr6,Lsr7,Lsr10,Lsr11,Lsr12,,,,,;
!1,2,Lsmax,Ldsuba;
!1,2,Lsr,BITBLTdoner;
XM01333> Loadstate: temp<-L, IR<-msr0, :NovaIntrOn; stash pointer
XM01336> Lsr: T<-12, :Ldsuba;
Lsr12: my<-L, :Ldsub;
Lsr11: mx<-L, :Ldsub;
Lsr10: stkp<-L;
T<-stkp; check for BRK resumption
L<-177400 AND T; (i.e. bytecode in stkp)
brkbyte<-L LCY 8; stash for Xfer
L<-T<-17.T; mask to 4 bits
L<--7+T; check stkp > 6
L<-T, SH<0;
stkp<-L, T<-0+T+1, :Lsmax; T:stkp+1
Lsmax: T<-7, :Ldsuba;
XM01327> Lsr7: stk7<-L, :Ldsub;
XM01326> Lsr6: stk6<-L, :Ldsub;
XM01325> Lsr5: stk5<-L, :Ldsub;
XM01324> Lsr4: stk4<-L, :Ldsub;
XM01323> Lsr3: stk3<-L, :Ldsub;
XM01322> Lsr2: stk2<-L, :Ldsub;
XM01321> Lsr1: stk1<-L, :Ldsub;
XM01320> Lsr0: stk0<-L, :Xfer;
XM01347> Ldsub: T<-count;
XM01335> Ldsuba: MAR<-temp+T;
XM01350> L<-ALLONES+T; decr count for next time
XM01351> count<-L, L<-T; use old value for dispatch
XM01352> SINK<-M, BUS;
XM01353> L<-MD, TASK, :Lsr0;
;-----------------------------------------------------------------
; DST - dump state at block starting at +alpha, reset stack pointer
; assumes DST is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1770> DST: T<-ib; get alpha
XM1354> T<-lp+T+1;
XM1355> L<-nlpoffset1+T+1, TASK; L:lp-lpoffset+alpha
XM1356> temp<-L, IR<-ret0, :Savestatea;
XM0776> DSTr1: L<-my, :Savsuba; save my too!
DSTr: temp<-L, L<-0, TASK, BUS=0, :Setstkp; zap stkp, return to 'nextA'
;-----------------------------------------------------------------
; LST - load state from block starting at +alpha
; assumes LST is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1771> LST: L<-ib;
XM1357> temp<-L, L<-0, TASK;
XM1360> ib<-L; make Savpcinframe happy
XM1361> IR<-sr4, :Savpcinframe; returns to LSTr
LSTr: T<-temp; get alpha back
L<-lp+T, TASK, :Loadstate; lp already undiddled
;-----------------------------------------------------------------
; LSTF - load state from block starting at +alpha, then free frame
; assumes LSTF is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1772> LSTF: T<-lpoffset;
XM1363> L<-lp-T, TASK; compute frame base
XM1364> frame<-L;
XM1365> IR<-sr2, :FreeSub;
LSTFr: T<-frame; set up by FreeSub
L<-ib+T, TASK, :Loadstate; get state from dead frame
;-----------------------------------------------------------------
; E m u l a t o r A c c e s s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; RR - push , where:
; RR is A-aligned (also ensures no pending branch at entry)
; alpha: 1 => wdc, 2 => XTSreg, 3 => XTPreg, 4 => ATPreg,
; 5 => OTPreg
;-----------------------------------------------------------------
!1,1,DoRamRWB; shake B/A dispatch (BLTL)
XM1775> RR: L<-0, SWMODE, :DoRamRWB;
XM1367> DoRamRWB: SINK<-M, BUS, L<-T, :ramOverflow; L<-T for WR
;-----------------------------------------------------------------
; WR - emulator register alpha <- (popped), where:
; WR is A-aligned (also ensures no pending branch at entry)
; alpha: 1 => wdc, 2 => XTSreg
;-----------------------------------------------------------------
XM1774> WR: L<-ret3, TASK, :Xpopsub;
XM0103> WRr: L<-2, SWMODE, :DoRamRWB;
;-----------------------------------------------------------------
; JRAM - JMPRAM for Mesa programs (when emulator is in ROM1)
;-----------------------------------------------------------------
XM1767> JRAM: L<-ret2, TASK, :Xpopsub;
XM0102> JRAMr: SINK<-M, BUS, SWMODE, :next; BUS applied to 'nextBa' (=0)
;-----------------------------------------------------------------
; P r o c e s s / M o n i t o r S u p p o r t
;-----------------------------------------------------------------
!1,1,MoveParms1; shake B/A dispatch
!1,1,MoveParms2; shake B/A dispatch
!1,1,MoveParms3; shake B/A dispatch
;!1,1,MoveParms4; shake B/A dispatch
;-----------------------------------------------------------------
; ME,MRE - Monitor Entry and Re-entry
; MXD - Monitor Exit and Depart
;-----------------------------------------------------------------
!1,1,FastMREx; drop ball 1
!1,1,FastEEx; drop ball 1
!7,1,FastEExx; shake IR<-isME/isMXD
!1,2,MXDr,MEr;
!7,1,FastEExxx; shake IR<-isMRE
%3,17,14,MXDrr,MErr,MRErr;
!1,2,FastEEtrap1,MEXDdone;
!1,2,FastEEtrap2,MREdone;
; The following constants are carefully chosen to agree with the above pre-defs
$isME $6001; IDISP:1, DISP:1, mACSOURCE:1
$isMRE $65403; IDISP:13, DISP:3, mACSOURCE:16
$isMXD $402; IDISP:0, DISP:2, mACSOURCE:0
XM1401> ME: IR<-isME, :FastEEx; indicate ME instruction
XM1404> MXD: IR<-isMXD, :FastEEx; indicate MXD instruction
XM1402> MRE: MAR<-HardMRE, :FastMREx; ~= 0 => do Nova code
XM1377> FastMREx: IR<-isMRE, :MXDr; indicate MRE instruction
XM1475> FastEEx: MAR<-stk0, IDISP, :FastEExx; fetch monitor lock
XM1477> FastEExx: T<-100000, :MXDr; value of unlocked monitor lock
XM1542> MXDr: L<-MD, mACSOURCE, :FastEExxx; L:0 if locked (or queue empty)
MEr: L<-MD-T, mACSOURCE, :FastEExxx; L:0 if unlocked
XM1547> FastEExxx: MAR<-stk0, SH=0, :MXDrr; start store, test lock state
; Note: if control goes to FastEEtrap1 or FastEEtrap2, AC1 or AC2 will be smashed,
; but their contents aren't guaranteed anyway.
; Note also that MErr and MXDrr cannot TASK.
XM1554> MXDrr: L<-T, T<-0, :FastEEtrap1; L:100000, T:0 (stkp value)
MErr: T<-0+1, :FastEEtrap1; L:0, T:1 (stkp value)
MRErr: L<-0+1, TASK, :FastEEtrap2; L:1 (stkp value)
MEXDdone: MD<-M, L<-T, TASK, :Setstkp;
MREdone: stkp<-L, :ME; queue empty, treat as ME
;-----------------------------------------------------------------
; MXW - Monitor Exit and Wait
;-----------------------------------------------------------------
XM1403> MXW: IR<-4, :MoveParms3; 3 parameters
;-----------------------------------------------------------------
; NOTIFY,BCAST - Awaken process(es) from condition variable
;-----------------------------------------------------------------
XM1405> NOTIFY: IR<-5, :MoveParms1; 1 parameter
XM1406> BCAST: IR<-6, :MoveParms1; 1 parameter
;-----------------------------------------------------------------
; REQUEUE - Move process from queue to queue
;-----------------------------------------------------------------
XM1407> REQUEUE: IR<-7, :MoveParms3; 3 parameter
;-----------------------------------------------------------------
; Parameter Transfer for Nova code linkages
; Entry Conditions:
; T: 1
; IR: dispatch vector index of Nova code to execute
;-----------------------------------------------------------------
;MoveParms4: L<-stk3, TASK; if you uncomment this, don't
; AC3<-L; forget the pre-def above!
XM1375> MoveParms3: L<-stk2, TASK;
XM1550> FastEEtrap2: AC2<-L; (enter here from MRE)
XM1373> MoveParms2: L<-stk1, TASK;
XM1544> FastEEtrap1: AC1<-L; (enter here from ME/MXD)
XM1371> MoveParms1: L<-stk0, TASK;
XM1370> AC0<-L;
XM1372> L<-0, TASK; indicate stack empty
XM1374> stkp<-L;
XM1376> T<-DISP+1, :STOP;
;-----------------------------------------------------------------
; M i s c e l l a n e o u s O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; CATCH - an emulator no-op of length 2.
; CATCH is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1763> CATCH: L<-mpc+1, TASK, :nextAput; duplicate of 'nextA'
;-----------------------------------------------------------------
; STOP - return to Nova at 'NovaDVloc+1'
; control also comes here from process opcodes with T set appropriately
;-----------------------------------------------------------------
!1,1,GotoNova; shake B/A dispatch
XM1762> STOP: L<-NovaDVloc+T, :GotoNova;
;-----------------------------------------------------------------
; STARTIO - perform Nova-like I/O function
;-----------------------------------------------------------------
XM1766> STARTIO: L<-ret4, TASK, :Xpopsub; get argument in L
XM0104> STARTIOr: SINK<-M, STARTF, :next;
;-----------------------------------------------------------------
; MISC - escape hatch for more than 256 opcodes
;-----------------------------------------------------------------
; !5,2,Dpushx,RCLKr; appears with Dpush
XM1764> MISC: IR<-sr36, :Getalpha; get argument in L
; throws away alpha for now
XM0076> MISCr: L<-CLOCKLOC-1, IR<-CLOCKLOC, :Dpushb; IR<- causes branch 1!
; (and mACSOURCE of 0)
; Dpushb shakes B/A dispatch
XM0205> RCLKr: L<-clockreg, :Dpushc; don't TASK here!
;-----------------------------------------------------------------
; BLT - block transfer
; assumes stack has precisely three elements:
; stk0 - address of first word to read
; stk1 - count of words to move
; stk2 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
!1,1,BLTx; shakes entry B/A branch
XM1752> BLT: stk7<-L, SWMODE, :BLTx; stk7=0 <=> branch pending
XM1553> BLTx: IR<-msr0, :ramBLTloop; IR<- is harmless
;-----------------------------------------------------------------
; BLTL - block transfer (long pointers)
; assumes stack has precisely three elements:
; stk0, stk1 - address of first word to read
; stk2 - count of words to move
; stk3, stk4 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
XM1753> BLTL: stk7<-L, L<-T, SWMODE, :DoRamRWB; stk7=0 <=> branch pending, L:1
;-----------------------------------------------------------------
; BLTC - block transfer from code segment
; assumes stack has precisely three elements:
; stk0 - offset from code base of first word to read
; stk1 - count of words to move
; stk2 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
!1,1,BLTCx; shake B/A dispatch
XM1754> BLTC: stk7<-L, SWMODE, :BLTCx;
XM1557> BLTCx: IR<-sr1, :ramBLTloop;
;-----------------------------------------------------------------
; BITBLT - do BITBLT using ROM subroutine
; If BITBLT A-aligned, B byte will be ignored
;-----------------------------------------------------------------
!1,1,BITBLTx; shake B/A dispatch
!7,1,DoBITBLTx; shake IR<- dispatch
!3,4,Mstop,,NovaIntrOff,DoBITBLT; includes NovaIntrOff returns
XM1765> BITBLT: stk7<-L, :BITBLTx; save even/odd across ROM call
XM1561> BITBLTx: L<-stk0, TASK;
XM1474> AC2<-L; stash descriptor table
XM1476> L<-stk1, TASK;
XM1546> AC1<-L;
XM1552> SINK<-wdc, BUS=0; check if Mesa interrupts off
XM1560> IR<-sr3, :NovaIntrOff; if so, shut off Nova's
XM1677> DoBITBLT: L<-BITBLTret, SWMODE, :DoBITBLTx; get return address
XM1577> DoBITBLTx: PC<-L, L<-0, :ROMBITBLT; L<-0 for Alto II ROM0 "feature"
BITBLTdone: IR<-sr1, :NovaIntrOn; ensure Nova interrupts are on
BITBLTdoner: brkbyte<-L, BUS=0, TASK, :Setstkp; don't bother to validate stkp
BITBLTintr: L<-AC1, SWMODE; pick up intermediate state
stk1<-L, :ramBLTint; stash instruction state
;-----------------------------------------------------------------
; M e s a / N o v a C o m m u n i c a t i o n
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Subroutines to Enable/Disable Nova Interrupts
;-----------------------------------------------------------------
; !3,4,Mstop,,NovaIntrOff,DoBITBLT; appears with BITBLT
; !1,2,Lsr,BITBLTdoner; appears with LoadState
!7,1,NovaIntrOffx; shake IR<- dispatch
XM1676> NovaIntrOff: T<-100000; disable bit
XM1737> NovaIntrOffx: L<-NWW OR T, TASK, IDISP; turn it on, dispatch return
XM1574> NWW<-L, :Mstop;
XM01575> NovaIntrOn: T<-100000; disable bit
XM01576> L<-NWW AND NOT T, IDISP; turn it off, dispatch return
XM01646> NWW<-L, L<-0, :Lsr;
;-----------------------------------------------------------------
; IWDC - Increment Wakeup Disable Counter (disable interrupts)
;-----------------------------------------------------------------
!1,2,IDnz,IDz;
XM1760> IWDC: L<-wdc+1, TASK, :IDnz; skip check for interrupts
;-----------------------------------------------------------------
; DWDC - Decrement Wakeup Disable Counter (enable interrupts)
;-----------------------------------------------------------------
!1,1,DWDCx;
XM1761> DWDC: MAR<-WWLOC, :DWDCx; OR WW into NWW
XM1671> DWDCx: T<-NWW;
XM1675> L<-MD OR T, TASK;
XM1731> NWW<-L;
XM1732> SINK<-ib, BUS=0;
XM1733> L<-wdc-1, TASK, :IDnz;
; Ensure that one instruction will execute before an interrupt is taken
XM1672> IDnz: wdc<-L, :next;
XM1673> IDz: wdc<-L, :nextAdeaf;
;-----------------------------------------------------------------
; Entry to Mesa Emulation
; AC0 holds address of current process state block
; Location 'PSBloc' is assumed to hold the same value
;-----------------------------------------------------------------
XM00420> Mgo: L<-AC0, :Loadstate;
;-----------------------------------------------------------------
; N o v a I n t e r f a c e
;-----------------------------------------------------------------
$START $L004020,0,0; Nova emulator return address
;-----------------------------------------------------------------
; Transfer to Nova code
; Entry conditions:
; L contains Nova PC to use
; Exit conditions:
; Control transfers to ROM0 at location 'START' to do Nova emulation
; Nova PC points to code to be executed
; Except for parameters expected by the target code, all Nova ACs
; contain garbage
; Nova interrupts are disabled
;-----------------------------------------------------------------
XM1541> GotoNova: PC<-L, IR<-msr0, :NovaIntrOff; stash Nova PC, return to Mstop
;-----------------------------------------------------------------
; Control comes here when an interrupt must be taken. Control will
; pass to the Nova emulator with interrupts enabled.
;-----------------------------------------------------------------
XM0406> Intstop: L<-NovaDVloc, TASK; resume at Nova loc. 30B
XM1734> PC<-L, :Mstop;
;-----------------------------------------------------------------
; Stash the Mesa pc and dump the current process state,
; then start fetching Nova instructions.
;-----------------------------------------------------------------
XM1674> Mstop: IR<-sr2, :Savpcinframe; save mpc for Nova code
XM0432> Mstopr: MAR<-CurrentState; get current state address
XM1735> IR<-ret1; will return to 'Mstopc'
XM1736> L<-MD, :Savestate; dump the state
; The following instruction must be at location 'SWRET', by convention.
; Strictly speaking, the following two lines should read:
;Mstopc: L<-T<-uCodeVersion; stash ucode version number
; L<-100000 OR T, SWMODE; version 1, XM
; However, under the assumption that uCodeVersion=1 (which it does, for Mesa 5.0), we can
; save an instruction as follows:
XM0777> Mstopc: L<-100000+1, SWMODE; version 1, XM
XM1740> cp<-L, :START; off to the Nova ...
; *** 11/23/15 - END OF MESADROM.MU ***
\ No newline at end of file
diff --git a/Contralto/Disassembly/MesaROM.mu b/Contralto/Disassembly/MesaROM.mu
new file mode 100644
index 0000000..3ae9183
--- /dev/null
+++ b/Contralto/Disassembly/MesaROM.mu
@@ -0,0 +1 @@
+;-----------------------------------------------------------------;
; X M E S A M I C R O C O D E ;
; Version 39-3 ;
;-----------------------------------------------------------------;
; MesaROM.Mu - Instruction fetch and general subroutines
; Last modified by Levin - March 6, 1979 10:40 AM
; 'uCodeVersion' is used by RunMesa to determine what version of the Mesa microcode is
; in ROM1. This version number should be incremented by 1 for every official release of
; the microcode. 'uCodeVersion' is mapped by RunMesa to the actual version number (which
; appears as a comment above). The reason for this mapping is the limited number of
; constants in the Alto constants ROM, otherwise, we would obviously have assigned
; 'uCodeVersion' the true microcode version number.
;
; The current table in RunMesa should have the following correspondences:
; uCodeVersion Microcode version Mesa release
; 0 34 4.1
; 1 39 5.0
$uCodeVersion $1;
;Completely rewritten by Roy Levin, Sept-Oct. 1977
;Modified by Johnsson; July 25, 1977 10:20 AM
;First version assembled 5 June 1975.
;Developed from Lampson's MESA.U of 21 March 1975.
;-----------------------------------------------------------------
; GLOBAL CONVENTIONS AND ASSUMPTIONS
;-----------------------------------------------------------------
; 1) Stack representation:
; stkp=0 => stack is empty
; sktp=10 => stack is full
; The validity checking that determines if the stack pointer is
; within this range is somewhat perfunctory. The approach taken is
; to include specific checks only where there absence would not lead
; to some catastrophic error. Hence, the stack is not checked for
; underflow, since allowing it to become negative will cause a disaster
; on the next stack dispatch.
; 2) Notation:
; Instruction labels correspond to opcodes in the obvious way. Suffixes
; of A and B (capitalized) refer to alignment in memory. 'A' is intended
; to suggest the right-hand byte of a memory word; 'B' is intended to
; suggest the left-hand byte. Labels terminating in a lower-case letter
; generally name local branch points within a particular group of
; opcodes. (Exception: subroutine names.) Labels terminating in 'x' generally
; exist only to satisfy alignment requirements imposed by various dispatches
; (most commonly IR<- and B/A in instruction fetch).
; 3) Tasking:
; Every effort has been made to ensure that a 'TASK' appears approximately
; every 12 instructions. Occasionally, this has not been possible,
; but (it is hoped that) violations occur only in infrequently executed
; code segments.
; 4) New symbols:
; In a few cases, the definitions of the standard Alto package
; (AltoConsts23.MU) have not been quite suitable to the needs of this
; microcode. Rather than change the standard package, we have defined
; new symbols (with names beginning with 'm') that are to be used instead
; of their standard counterparts. All such definitions appear together in
; Mesab.Mu.
; 5) Subroutine returns:
; Normally, subroutine returns using IDISP require one to deal with
; (the nuisance of) the dispatch caused by loading IR. Happily, however,
; no such dispatch occurs for 'msr0' and 'sr1' (the relevant bits
; are 0). To cut down on alignment restrictions, some subroutines
; assume they are called with only one of two returns and can
; therefore ignore the possibility of a pending IR<- dispatch.
; Such subroutines are clearly noted in the comments.
; 6) Frame pointer registers (lp and gp):
; These registers normally (i.e. except during Xfer) contain the
; addresses of local 2 and global 1, respectively. This optimizes accesses
; in such bytecodes as LL3 and SG2, which would otherwise require another cycle.
;-----------------------------------------------------------------
; Get definitions for ALTO and MESA
;-----------------------------------------------------------------
#AltoConsts23.mu;
#MesabROM.mu;
; *** 11/23/15 - START OF MESABROM.MU ***
;-----------------------------------------------------------------
; MesabROM.Mu - Registers, miscellaneous symbols and constants
; Last modified by Levin - February 27, 1979 4:49 PM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; R memories used by code in ROM0, correct to AltoCode23.Mu
;-----------------------------------------------------------------
; Nova Emulator Registers (some used by Mesa as well)
$AC3 $R0;
$MASK1 $R0;
$AC2 $R1;
$AC1 $R2;
$YMUL $R2;
$RETN $R2;
$AC0 $R3;
$SKEW $R3;
$NWW $R4;
$SAD $R5;
$CYRET $R5;
$TEMP $R5;
$PC $R6;
$XREG $R7;
$CYCOUT $R7;
$WIDTH $R7;
$PLIER $R7;
$XH $R10;
$DESTY $R10;
$WORD2 $R10;
$DWAX $R35;
$STARTBITSM1 $R35;
$MASK $R36;
$SWA $R36;
$DESTX $R36;
$LREG $R40;
$NLINES $R41;
$RAST1 $R42;
$SRCX $R43;
$SKMSK $R43;
$SRCY $R44;
$RAST2 $R44;
$CONST $R45;
$TWICE $R45;
$HCNT $R46;
$VINC $R46;
$HINC $R47;
$NWORDS $R50;
$MASK2 $R51;
;-----------------------------------------------------------------
; Registers used by standard Nova I/O controllers
;
; All names have been prefixed with 'x' to prevent conflicts when MesabROM is
; used by XMesa clients to assemble MesaXRAM with other microcode.
;-----------------------------------------------------------------
; Model 31 Disk
$xKWDCT $R31;
$xKWDCTW $R31;
$xCKSUMR $R32;
$xCKSUMRW $R32;
$xKNMAR $R33;
$xKNMARW $R33;
$xDCBR $R34;
; Display
$CURX $R20;
$CURDATA $R21;
$xCBA $R22;
$xAECL $R23;
$xSLC $R24;
$xMTEMP $R25;
$xHTAB $R26;
$xYPOS $R27;
$xDWA $R30;
; Ethernet
$xECNTR $R12;
$xEPNTR $R13;
; Memory Refresh
$xCLOCKTEMP $R11;
$xR37 $R37;
; Audio (obsolete)
$xAudioWdCt $R71;
$xAudioData $R72;
;-----------------------------------------------------------------
; Registers used by Mesa Emulator
;-----------------------------------------------------------------
; R registers
$temp $R35; Temporary (smashed by BITBLT)
$temp2 $R36; Temporary (smashed by BITBLT)
$mpc $R15; R register holds Mesa PC (points at word last read)
$stkp $R16; stack pointer [0-10] 0 empty, 10 full
$XTSreg $R17; xfer trap state
; Registers shared by Nova and Mesa emulators
; Nova ACs are set explicitly by Mesa process opcodes and for ROM0 calls
; Other R-registers smashed by BITBLT and other ROM0 subroutines
$brkbyte $R0; (AC3) bytecode to execute after a breakpoint
; Warning! brkbyte must be reset to 0 after ROM calls!
; (see BITBLT)
$mx $R1; (AC2) x register for XFER
; Warning! smashed by BITBLT and MUL/DIV/LDIV
$saveret $R2; (AC1) R-temporary for return indices and values
$newfield $R3; (AC0) new field bits for WF and friends
; Warning! must be R-register; assumed safe across CYCLE
$count $R5; scratch R register used for counting
$taskhole $R7; pigeonhole for saving things across TASKs
; Warning! smashed by all ROM calls!
$ib $R10; instruction byte, 0 if none (0,,byte)
; Warning! smashed by BITBLT
$clockreg $R37; low-order bits of real-time clock
; S registers, can't shift into them, BUS not zero while storing.
$my $R51; y register for XFER
$lp $R52; local pointer
$gp $R53; global pointer
$cp $R54; code pointer
$ATPreg $R55; allocation trap parameter
$OTPreg $R56; other trap parameter
$XTPreg $R57; xfer trap parameter
$wdc $R70; wakeup disable counter
; Mesa evaluation stack
$stk0 $R60; stack (bottom)
$stk1 $R61; stack
$stk2 $R62; stack
$stk3 $R63; stack
$stk4 $R64; stack
$stk5 $R65; stack
$stk6 $R66; stack
$stk7 $R67; stack (top)
; Miscellaneous S registers
$mask $R41; used by string instructions, among others
$unused1 $R42; not safe across call to BITBLT
$unused2 $R43; not safe across call to BITBLT
$alpha $R44; alpha byte (among other things)
$index $R45; frame size index (among other things)
$entry $R46; allocation table entry address (among other things)
$frame $R47; allocated frame pointer (among other things)
$righthalf $R41; right 4 bits of alpha or beta
$lefthalf $R45; left 4 bits of alpha or beta
$unused3 $R50; not safe across call to BITBLT
;-----------------------------------------------------------------
; Mnemonic constants for subroutine return indices used by BUS dispatch.
;-----------------------------------------------------------------
$ret0 $L0,12000,100; zero is always special
$ret1 $1;
$ret2 $2;
$ret3 $3;
$ret4 $4;
$ret5 $5;
$ret6 $6;
$ret7 $7;
$ret10 $10;
$ret11 $11;
$ret12 $12;
$ret13 $13;
$ret14 $14;
$ret15 $15;
$ret16 $16;
$ret17 $17;
$ret20 $20;
$ret21 $21;
$ret22 $22;
$ret23 $23;
$ret24 $24;
$ret25 $25;
$ret26 $26;
$ret27 $27;
$ret30 $30;
$ret31 $31;
$ret37 $37;
;-----------------------------------------------------------------
; Mesa Trap codes - index into sd vector
;-----------------------------------------------------------------
$sBRK $L0,12000,100; Breakpoint
$sStackError $2;
$sStackUnderflow $2; (trap handler distinguishes underflow from
$sStackOverflow $2; overflow by stkp value)
$sXferTrap $4;
$sAllocTrap $6;
$sControlFault $7;
$sSwapTrap $10;
$sUnbound $13;
$sBoundsFault $20;
$sPointerFault $21; must equal sBoundsFault+1
$sBoundsFaultm1 $17; must equal sBoundsFault-1
;-----------------------------------------------------------------
; Low- and high-core address definitions
;-----------------------------------------------------------------
$HardMRE $20; location which forces MRE to drop to Nova code
$CurrentState $23; location holding address of current state
$NovaDVloc $25; dispatch vector for Nova code
$avm1 $777; base of allocation vector for frames (-1)
$sdoffset $100; offset to base of sd from av
$gftm1 $1377; base of global frame table (-1)
$BankReg $177740; address of emulator's bank register
;-----------------------------------------------------------------
; Constants in ROM, but with unpleasant names
;-----------------------------------------------------------------
$12 $12; for function calls
$-12 $177766; for Savestate
$400 $400; for JB
;-----------------------------------------------------------------
; Frame offsets and other software/microcode agreements
;-----------------------------------------------------------------
$lpoffset $6; local frame overhead + 2
$nlpoffset $177771; = -(lpoffset + 1)
$nlpoffset1 $177770; = -(lpoffset + 2)
$pcoffset $1; offset from local frame base to saved pc
$npcoffset $5; = -(lpoffset+1+pcoffset) [see Savpcinframe]
$retlinkoffset $2; offset from local frame base to return link
$nretlinkoffset $177774; = -(lpoffset-retlinkoffset)
$gpoffset $4; global frame overhead + 1
$ngpoffset $177773; = -(gpoffset + 1)
$gfioffset $L0,12000,100; offset from global frame base to gfi word (=0)
$ngfioffset $4; = gpoffset-gfioffset [see XferGfz]
$cpoffset $1; offset from global frame base to code pointer
$gpcpoffset $2; offset from high code pointer to global 1
$gfimask $177600; mask to isolate gfi in global frame word 0
$enmask $37; mask to isolate entry number/4
;-----------------------------------------------------------------
; Symbols to be used instead of ones in the standard definitions
;-----------------------------------------------------------------
$mACSOURCE $L024016,000000,000000; sets only F2. ACSOURCE also sets BS and RSEL
$msr0 $L000000,012000,000100; IDISP => 0, no IR<- dispatch, a 'special' zero
$BUSAND~T $L000000,054015,000040; sets ALUF = 15B, doesn't require defined bus
;-----------------------------------------------------------------
; Linkages between ROM1 and RAM for overflow microcode
;-----------------------------------------------------------------
; Fixed locations in ROM1
$romnext $L004400,0,0; must correspond to next
$romnextA $L004401,0,0; must correspond to nextA
$romIntstop $L004406,0,0; must correspond to Intstop
$romUntail $L004407,0,0; must correspond to Untail
$romXfer $L004431,0,0; must correspond to Xfer
; Fixed locations in RAM
$ramBLTloop $L004403,0,0; must correspond to BLTloop
$ramBLTint $L004405,0,0; must correspond to BLTint
$ramOverflow $L004410,0,0; RR, BLTL, WR
; DADD, DSUB, DCOMP, DUCOMP
; *** 11/23/15 - END OF MESABROM.MU ***
;-----------------------------------------------------------------
; Location-specific Definitions
;-----------------------------------------------------------------
; There is a fundamental difficulty in the selection of addresses that are known and
; used outside the Mesa emulator. The problem arises in trying to select a single set of
; addresses that can be used regardless of the Alto's control memory configuration. In
; effect, this cannot be done. If an Alto has only a RAM (in addition, of course, to its
; basic ROM, ROM0), then the problem does not arise. However, suppose the Alto has both a
; RAM and a second ROM, ROM1. Then, when it is necessary to move from a control memory to
; one of the other two, the choice is conditioned on (1) the memory from which the transfer
; is occurring, and (2) bit 1 of the target address. Since we expect that, in most cases, an
; Alto running Mesa will have the Mesa emulator in ROM1, the externally-known addresses have
; been chosen to work in that case. They will also work, without alteration, on an Alto that
; has no ROM1. However, if it is necessary to run Mesa on an Alto with ROM1 and it is desired
; to use a Mesa emulator residing in the RAM (say, for debugging purposes), then the address
; values in the RAM version must be altered. This implies changes in both the RAM code itself
; and the Nova code that invokes the RAM (via the Nova JMPRAM instruction). Details
; concerning the necessary changes for re-assembly appear with the definitions below.
; Note concerning Alto IVs and Alto IIs with retrofitted 3K control RAMs:
;
; The above comments apply uniformly to these machines if "RAM" is systematically replaced
; by "RAM1" and "ROM1" is systematically replaced by "RAM2".
%1,1777,0,nextBa; forced to location 0 to save a word in JRAM
;-----------------------------------------------------------------
; Emulator Entry Point Definitions
; These addresses are known by the Nova code that interfaces to the emulator and by
; RAM code executing with the Mesa emulator in ROM1. They have been chosen so that
; both such "users" can use the same value. Precisely, this means that bit 1 (the
; 400 bit) must be set in the address. In a RAM version of the Mesa emulator intended
; to execute on an Alto with a second ROM, bit 1 must be zero.
;-----------------------------------------------------------------
%1,1777,420,Mgo; Normal entry to Mesa Emulator - load state
; of process specified by AC0.
%1,1777,400,next,nextA; Return to 'next' to continue in current Mesa
; process after Nova or RAM execution.
$Minterpret $L004400,0,0; Documentation refers to 'next' this way.
%1,1777,776,DSTr1,Mstopc; Return addresses for 'Savestate'. By
; standard convention, 'Mstopc' must be at 777.
;-----------------------------------------------------------------
; Linkage from RAM to ROM1
; The following predefs must correspond to the label definitions in MesabROM.mu
;-----------------------------------------------------------------
%1,1777,406,Intstop; must correspond to romIntstop
%1,1777,407,Untail; must correspond to romUntail
%7,1777,430,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr; Xfer must agree with romXfer
;-----------------------------------------------------------------
; Linkage from Mesa emulator to ROM0
; The Mesa emulator uses a number of subroutines that reside in ROM0. In posting a
; return address, the emulator must be aware of the control memory in which it resides,
; RAM or ROM1. These return addresses must satisfy the following constraint:
; no ROM1 extant or emulator in ROM1 => bit 1 of address must be 1
; ROM1 extant and emulator in RAM => bit 1 of address must be 0
; In addition, since these addresses must be passed as data to ROM0, it is desirable
; that they be available in the Alto's constants ROM. Finally, it is desirable that
; they be chosen not to mess up too many pre-defs. It should be noted that these
; issues do not affect the destination location in ROM0, since its address remains
; fixed (even with respect to bit 1 mapping) whether the Mesa emulator is in RAM or
; ROM1. [Note pertaining to Alto IVs and retrofitted Alto IIs with 3K RAMs: to avoid
; confusion, the comments above and below have not been revised to discuss 3K control
; RAMs. In all cases, there is an additional constraint that bit 2 of the return
; addresses must be 1. The suggested values observe this constraint, even though the
; comments do not explicitly mention it.]
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; MUL/DIV linkage:
; An additional constraint peculiar to the MUL/DIV microcode is that the high-order
; bits of the return address be 1's. Hence, the recommended values are:
; no ROM1 extant or emulator in ROM1 => MULDIVretloc = 177675B (OK to be odd)
; ROM1 extant and emulator in RAM => MULDIVretloc = 177162B (OK to be odd)
;-----------------------------------------------------------------
$ROMMUL $L004120,0,0; MUL routine address (120B) in ROM0
$ROMDIV $L004121,0,0; DIV routine address (121B) in ROM0
$MULDIVretloc $177675; (may be even or odd)
; The third value in the following pre-def must be: (MULDIVretloc AND 777B)
%1,1777,675,MULDIVret,MULDIVret1; return addresses from MUL/DIV in ROM0
;-----------------------------------------------------------------
; BITBLT linkage:
; An additional constraint peculiar to the BITBLT microcode is that the high-order
; bits of the return address be 1's. Hence, the recommended values are:
; no ROM1 extant or emulator in ROM1 => BITBLTret = 177714B
; ROM1 extant and emulator in RAM => BITBLTret = 177175B
;-----------------------------------------------------------------
$ROMBITBLT $L004124,0,0; BITBLT routine address (124B) in ROM0
$BITBLTret $177714; (may be even or odd)
; The third value in the following pre-def must be: (BITBLTret AND 777B)-1
%1,1777,713,BITBLTintr,BITBLTdone; return addresses from BITBLT in ROM0
;-----------------------------------------------------------------
; CYCLE linkage:
; A special constraint here is that WFretloc be odd. Recommended values are:
; no ROM1 extant or emulator in ROM1 => Fieldretloc = 612B, WFretloc = 605B
; ROM1 extant and emulator in RAM => Fieldretloc = 34104B, WFretloc = 14023B
;-----------------------------------------------------------------
$RAMCYCX $L004022,0,0; CYCLE routine address (22B) in ROM0
$Fieldretloc $612; RAMCYCX return to Fieldsub (even or odd)
$WFretloc $605; RAMCYCX return to WF (must be odd)
; The third value in the following pre-def must be: (Fieldretloc AND 1777B)
%1,1777,612,Fieldrc; return address from RAMCYCX to Fieldsub
; The third value in the following pre-def must be: (WFretloc AND 1777B)-1
%1,1777,604,WFnzct,WFret; return address from RAMCYCX to WF
;-----------------------------------------------------------------
; I n s t r u c t i o n f e t c h
;
; State at entry:
; 1) ib holds either the next instruction byte to interpret
; (right-justified) or 0 if a new word must be fetched.
; 2) control enters at one of the following points:
; a) next: ib must be interpreted
; b) nextA: ib is assumed to be uninteresting and a
; new instruction word is to be fetched.
; c) nextXB: a new word is to be fetched, and interpretation
; is to begin with the odd byte.
; d) nextAdeaf: similar to 'nextA', but does not check for
; pending interrupts.
; e) nextXBdeaf: similar to 'nextXB', but does not check for
; pending interrupts.
;
; State at exit:
; 1) ib is in an acceptable state for subsequent entry.
; 2) T contains the value 1.
; 3) A branch (1) is pending if ib = 0, meaning the next
; instruction may return to 'nextA'. (This is subsequently
; referred to as "ball 1", and code that nullifies its
; effect is labelled as "dropping ball 1".)
; 4) If a branch (1) is pending, L = 0. If no branch is
; pending, L = 1.
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Address pre-definitions for bytecode dispatch table.
;-----------------------------------------------------------------
; Table must have 2 high-order bits on for BUS branch at 'nextAni'.
;
; Warning! Many address inter-dependencies exist - think (at least) twice
; before re-ordering. Inserting new opcodes in previously unused slots,
; however, is safe.
; XMESA Note: RBL, WBL, and BLTL exist for XMESA only.
%7,1777,1400,NOOP,ME,MRE,MXW,MXD,NOTIFY,BCAST,REQUEUE; 000-007
%7,1777,1410,LL0,LL1,LL2,LL3,LL4,LL5,LL6,LL7; 010-017
%7,1777,1420,LLB,LLDB,SL0,SL1,SL2,SL3,SL4,SL5; 020-027
%7,1777,1430,SL6,SL7,SLB,PL0,PL1,PL2,PL3,LG0; 030-037
%7,1777,1440,LG1,LG2,LG3,LG4,LG5,LG6,LG7,LGB; 040-047
%7,1777,1450,LGDB,SG0,SG1,SG2,SG3,SGB,LI0,LI1; 050-057
%7,1777,1460,LI2,LI3,LI4,LI5,LI6,LIN1,LINI,LIB; 060-067
%7,1777,1470,LIW,LINB,LADRB,GADRB,,,,; 070-077
%7,1777,1500,R0,R1,R2,R3,R4,RB,W0,W1; 100-107
%7,1777,1510,W2,WB,RF,WF,RDB,RD0,WDB,WD0; 110-117
%7,1777,1520,RSTR,WSTR,RXLP,WXLP,RILP,RIGP,WILP,RIL0; 120-127
%7,1777,1530,WS0,WSB,WSF,WSDB,RFC,RFS,WFS,RBL; 130-137
%7,1777,1540,WBL,,,,,,,; 140-147
%7,1777,1550,,,,,,,,; 150-157
%7,1777,1560,,,SLDB,SGDB,PUSH,POP,EXCH,LINKB; 160-167
%7,1777,1570,DUP,NILCK,,BNDCK,,,,; 170-177
%7,1777,1600,J2,J3,J4,J5,J6,J7,J8,J9; 200-207
%7,1777,1610,JB,JW,JEQ2,JEQ3,JEQ4,JEQ5,JEQ6,JEQ7; 210-217
%7,1777,1620,JEQ8,JEQ9,JEQB,JNE2,JNE3,JNE4,JNE5,JNE6; 220-227
%7,1777,1630,JNE7,JNE8,JNE9,JNEB,JLB,JGEB,JGB,JLEB; 230-237
%7,1777,1640,JULB,JUGEB,JUGB,JULEB,JZEQB,JZNEB,,JIW; 240-247
%7,1777,1650,ADD,SUB,MUL,DBL,DIV,LDIV,NEG,INC; 250-257
%7,1777,1660,AND,OR,XOR,SHIFT,DADD,DSUB,DCOMP,DUCOMP; 260-267
%7,1777,1670,ADD01,,,,,,,; 270-277
%7,1777,1700,EFC0,EFC1,EFC2,EFC3,EFC4,EFC5,EFC6,EFC7; 300-307
%7,1777,1710,EFC8,EFC9,EFC10,EFC11,EFC12,EFC13,EFC14,EFC15; 310-317
%7,1777,1720,EFCB,LFC1,LFC2,LFC3,LFC4,LFC5,LFC6,LFC7; 320-327
%7,1777,1730,LFC8,,,,,,,; 330-337
%7,1777,1740,,LFCB,SFC,RET,LLKB,PORTO,PORTI,KFCB; 340-347
%7,1777,1750,DESCB,DESCBS,BLT,BLTL,BLTC,,ALLOC,FREE; 350-357
%7,1777,1760,IWDC,DWDC,STOP,CATCH,MISC,BITBLT,STARTIO,JRAM; 360-367
%7,1777,1770,DST,LST,LSTF,,WR,RR,BRK,StkUf; 370-377
;-----------------------------------------------------------------
; Main interpreter loop
;-----------------------------------------------------------------
;
; Enter here to interpret ib. Control passes here to process odd byte of previously
; fetched word or when preceding opcode "forgot" it should go to 'nextA'. A 'TASK'
; should appear in the instruction preceding the one that branched here.
;
XM0400> next: L<-0, :nextBa; (if from JRAM, switch banks)
XM0000> nextBa: SINK<-ib, BUS; dispatch on ib
XM0001> ib<-L, T<-0+1, BUS=0, :NOOP; establish exit state
;-----------------------------------------------------------------
; NOOP - must be opcode 0
; control also comes here from certain jump instructions
;-----------------------------------------------------------------
!1,1,nextAput;
XM1400> NOOP: L<-mpc+T, TASK, :nextAput;
;
; Enter here to fetch new word and interpret even byte. A 'TASK' should appear in the
; instruction preceding the one that branched here.
;
XM0401> nextA: L<-XMAR<-mpc+1, :nextAcom; initiate fetch
;
; Enter here when fetch address has been computed and left in L. A 'TASK' should
; appear in the instruction that branches here.
;
XM0003> nextAput: temp<-L; stash to permit TASKing
XM0002> L<-XMAR<-temp, :nextAcom;
;
; Enter here to do what 'nextA' does but without checking for interrupts
;
XM0004> nextAdeaf: L<-XMAR<-mpc+1;
XM0005> nextAdeafa: mpc<-L, BUS=0, :nextAcomx;
;
; Common fetch code for 'nextA' and 'nextAput'
;
!1,2,nextAi,nextAni;
!1,2,nextAini,nextAii;
XM0012> nextAcom: mpc<-L; updated pc
XM0013> SINK<-NWW, BUS=0; check pending interrupts
XM0014> nextAcomx: T<-177400, :nextAi;
;
; No interrupt pending. Dispatch on even byte, store odd byte in ib.
;
XM0007> nextAni: L<-MD AND T, BUS, :nextAgo; L<-"B"^8, dispatch on "A"
XM0015> nextAgo: ib<-L LCY 8, L<-T<-0+1, :NOOP; establish exit state
;
; Interrupt pending - check if enabled.
;
XM0006> nextAi: L<-MD;
XM0016> SINK<-wdc, BUS=0; check wakeup counter
XM0017> T<-M.T, :nextAini; isolate left byte
XM0010> nextAini: SINK<-M, L<-T, BUS, :nextAgo; dispatch even byte
;
; Interrupt pending and enabled.
;
!1,2,nextXBini,nextXBii;
XM0011> nextAii: L<-mpc-1; back up mpc for Savpcinframe
XM0022> mpc<-L, L<-0, :nextXBii;
;
; Enter here to fetch word and interpret odd byte only (odd-destination jumps).
;
!1,2,nextXBi,nextXBni;
XM0023> nextXB: L<-XMAR<-mpc+T;
XM0026> SINK<-NWW, BUS=0, :nextXBdeaf; check pending interrupts
;
; Enter here (with branch (1) pending) from Xfer to do what 'nextXB' does but without
; checking for interrupts. L has appropriate word PC.
;
XM0027> nextXBdeaf: mpc<-L, :nextXBi;
;
; No interrupt pending. Store odd byte in ib.
;
XM0025> nextXBni: L<-MD, TASK, :nextXBini;
XM0020> nextXBini: ib<-L LCY 8, :next; skip over even byte (TASK
; prevents L<-0, :nextBa)
;
; Interrupt pending - check if enabled.
;
XM0024> nextXBi: SINK<-wdc, BUS=0, :nextXBni; check wakeup counter
;
; Interrupt pending and enabled.
;
XM0021> nextXBii: ib<-L, :Intstop; ib = 0 for even, ~= 0 for odd
;-----------------------------------------------------------------
; S u b r o u t i n e s
;-----------------------------------------------------------------
;
; The two most heavily used subroutines (Popsub and Getalpha) often
; share common return points. In addition, some of these return points have
; additional addressing requirements. Accordingly, the following predefinitions
; have been rather carefully constructed to accommodate all of these requirements.
; Any alteration is fraught with peril.
; [A historical note: an attempt to merge in the returns from FetchAB as well
; failed because more than 31D distinct return points were then required. Without
; adding new constants to the ROM, the extra returns could not be accommodated.
; However, for Popsub alone, additional returns are possible - see Xpopsub.]
;
; Return Points (sr0-sr17)
!17,20,Fieldra,SFCr,pushTB,pushTA,LLBr,LGBr,SLBr,SGBr,
LADRBr,GADRBr,RFr,Xret,INCr,RBr,WBr,Xpopret;
; Extended Return Points (sr20-sr37)
; Note: KFCr and EFCr must be odd!
!17,20,XbrkBr,KFCr,LFCr,EFCr,WSDBra,DBLr,LINBr,LDIVf,
Dpush,Dpop,RD0r,Splitcomr,RXLPrb,WXLPrb,MISCr,RWBLra;
; Returns for Xpopsub only
!17,20,WSTRrB,WSTRrA,JRAMr,WRr,STARTIOr,PORTOr,WD0r,ALLOCrx,
FREErx,NEGr,RFSra,RFSrb,WFSra,DESCBcom,RFCr,NILCKr;
; Extended Return Machinery (via Xret)
!1,2,XretB,XretA;
XM0053> Xret: SINK<-DISP, BUS, :XretB;
XM0030> XretB: :XbrkBr;
XM0031> XretA: SINK<-0, BUS=0, :XbrkBr; keep ball 1 in air
;-----------------------------------------------------------------
; Pop subroutine:
; Entry conditions:
; Normal IR linkage
; Exit conditions:
; Stack popped into T and L
;-----------------------------------------------------------------
!1,1,Popsub; shakes B/A dispatch
!7,1,Popsuba; shakes IR<- dispatch
!17,20,Tpop,Tpop0,Tpop1,Tpop2,Tpop3,Tpop4,Tpop5,Tpop6,Tpop7,,,,,,,;
XM0033> Popsub: L<-stkp-1, BUS, TASK, :Popsuba;
XM0037> Popsuba: stkp<-L, :Tpop; old stkp > 0
;-----------------------------------------------------------------
; Xpop subroutine:
; Entry conditions:
; L has return number
; Exit conditions:
; Stack popped into T and L
; Invoking instruction should specify 'TASK'
;-----------------------------------------------------------------
!1,1,Xpopsub; shakes B/A dispatch
XM0035> Xpopsub: saveret<-L;
XM0120> Tpop: IR<-sr17, :Popsub; returns to Xpopret
; Note: putting Tpop here makes
; stack underflow logic work if
; stkp=0
XM0057> Xpopret: SINK<-saveret, BUS;
XM0032> :WSTRrB;
;-----------------------------------------------------------------
; Getalpha subroutine:
; Entry conditions:
; L untouched from instruction fetch
; Exit conditions:
; alpha byte in T
; branch 1 pending if return to 'nextA' desirable
; L=0 if branch 1 pending, L=1 if no branch pending
;-----------------------------------------------------------------
!1,2,Getalpha,GetalphaA;
!7,1,Getalphax; shake IR<- dispatch
!7,1,GetalphaAx; shake IR<- dispatch
XM0132> Getalpha: T<-ib, IDISP;
XM0137> Getalphax: ib<-L RSH 1, L<-0, BUS=0, :Fieldra; ib<-0, set branch 1 pending
XM0133> GetalphaA: L<-XMAR<-mpc+1; initiate fetch
XM0147> GetalphaAx: mpc<-L;
XM0034> T<-177400; mask for new ib
XM0036> L<-MD AND T, T<-MD; L: new ib, T: whole word
XM0131> Getalphab: T<-377.T, IDISP; T now has alpha
XM0134> ib<-L LCY 8, L<-0+1, :Fieldra; return: no branch pending
;-----------------------------------------------------------------
; FetchAB subroutine:
; Entry conditions: none
; Exit conditions:
; T: <+1>
; ib: unchanged (caller must ensure return to 'nextA')
;-----------------------------------------------------------------
!1,1,FetchAB; drops ball 1
!7,1,FetchABx; shakes IR<- dispatch
!7,10,LIWr,JWr,,,,,,; return points
XM0135> etchAB: L<-XMAR<-mpc+1, :FetchABx;
XM0157> FetchABx: mpc<-L, IDISP;
XM0136> T<-MD, :LIWr;
;-----------------------------------------------------------------
; Splitalpha subroutine:
; Entry conditions:
; L: return index
; entry at Splitalpha if instruction is A-aligned, entry at
; SplitalphaB if instruction is B-aligned
; entry at Splitcomr splits byte in T (used by field instructions)
; Exit conditions:
; lefthalf: alpha[0-3]
; righthalf: alpha[4-7]
;-----------------------------------------------------------------
!1,2,Splitalpha,SplitalphaB;
!1,1,Splitx; drop ball 1
%160,377,217,Split0,Split1,Split2,Split3,Split4,Split5,Split6,Split7;
!1,2,Splitout0,Splitout1;
!7,10,RILPr,RIGPr,WILPr,RXLPra,WXLPra,Fieldrb,,; subroutine returns
XM0140> Splitalpha: saveret<-L, L<-0+1, :Splitcom; L<-1 for Getalpha
XM0141> SplitalphaB: saveret<-L, L<-0, BUS=0, :Splitcom; (keep ball 1 in air)
XM0142> Splitcom: IR<-sr33, :Getalpha; T:alpha[0-7]
XM0073> Splitcomr: L<-17 AND T, :Splitx; L:alpha[4-7]
XM0143> Splitx: righthalf<-L, L<-T, TASK; L:alpha, righthalf:alpha[4-7]
XM0146> temp<-L; temp:alpha
XM0150> L<-temp, BUS; dispatch on alpha[1-3]
XM0151> temp<-L LCY 8, SH<0, :Split0; dispatch on alpha[0]
XM0217> Split0: L<-T<-0, :Splitout0; L,T:alpha[1-3]
XM0237> Split1: L<-T<-ONE, :Splitout0;
XM0257> Split2: L<-T<-2, :Splitout0;
XM0277> Split3: L<-T<-3, :Splitout0;
XM0317> Split4: L<-T<-4, :Splitout0;
XM0337> Split5: L<-T<-5, :Splitout0;
XM0357> Split6: L<-T<-6, :Splitout0;
XM0377> Split7: L<-T<-7, :Splitout0;
XM0145> Splitout1: L<-10+T, :Splitout0; L:alpha[0-3]
XM0144> Splitout0: SINK<-saveret, BUS, TASK; dispatch return
XM0152> lefthalf<-L, :RILPr; lefthalf:alpha[0-3]
;-----------------------------------------------------------------
; D i s p a t c h e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Pop-into-T (and L) dispatch:
; dispatches on old stkp, so Tpop0 = 1 mod 20B.
;-----------------------------------------------------------------
XM0121> Tpop0: L<-T<-stk0, IDISP, :Tpopexit;
XM0122> Tpop1: L<-T<-stk1, IDISP, :Tpopexit;
XM0123> Tpop2: L<-T<-stk2, IDISP, :Tpopexit;
XM0124> Tpop3: L<-T<-stk3, IDISP, :Tpopexit;
XM0125> Tpop4: L<-T<-stk4, IDISP, :Tpopexit;
XM0126> Tpop5: L<-T<-stk5, IDISP, :Tpopexit;
XM0127> Tpop6: L<-T<-stk6, IDISP, :Tpopexit;
XM0130> Tpop7: L<-T<-stk7, IDISP, :Tpopexit;
XM0153> Tpopexit: :Fieldra; to permit TASK in Popsub
;-----------------------------------------------------------------
; pushMD dispatch:
; pushes memory value on stack
; The invoking instruction must load MAR and may optionally keep ball 1
; in the air by having a branch pending. That is, entry at 'pushMD' will
; cause control to pass to 'next', while entry at 'pushMDA' will cause
; control to pass to 'nextA'.
;-----------------------------------------------------------------
!3,4,pushMD,pushMDA,StoreB,StoreA;
!17,20,push0,push1,push2,push3,push4,push5,push6,push7,push10,,,,,,,;
XM0164> pushMD: L<-stkp+1, IR<-stkp; (IR<- causes no branch)
XM0154> stkp<-L, T<-0+1, :pushMDa;
XM0165> pushMDA: L<-stkp+1, IR<-stkp; (IR<- causes no branch)
XM0155> stkp<-L, T<-0, :pushMDa;
XM0156> pushMDa: SINK<-DISP, L<-T, BUS; dispatch on old stkp value
XM0162> L<-MD, SH=0, TASK, :push0;
;-----------------------------------------------------------------
; Push-T dispatch:
; pushes T on stack
; The invoking instruction may optionally keep ball 1 in the air by having a
; branch pending. That is, entry at 'pushTB' will cause control to pass
; to 'next', while entry at 'pushTA' will cause control to pass to 'nextA'.
;-----------------------------------------------------------------
!1,2,pushT1B,pushT1A; keep ball 1 in air
XM0042> pushTB: L<-stkp+1, BUS, :pushT1B;
XM0043> pushTA: L<-stkp+1, BUS, :pushT1A;
XM0176> pushT1B: stkp<-L, L<-T, TASK, :push0;
XM0177> pushT1A: stkp<-L, BUS=0, L<-T, TASK, :push0; BUS=0 keeps branch pending
;-----------------------------------------------------------------
; push dispatch:
; strictly vanilla-flavored
; may (but need not) have branch (1) pending if return to 'nextA' is desired
; invoking instruction should specify TASK
;-----------------------------------------------------------------
; Note: the following pre-def occurs here so that dpushof1 can be referenced in push10
!17,20,dpush,,dpush1,dpush2,dpush3,dpush4,dpush5,dpush6,dpush7,dpushof1,dpushof2,,,,,;
XM0440> push0: stk0<-L, :next;
XM0441> push1: stk1<-L, :next;
XM0442> push2: stk2<-L, :next;
XM0443> push3: stk3<-L, :next;
XM0444> push4: stk4<-L, :next;
XM0445> push5: stk5<-L, :next;
XM0446> push6: stk6<-L, :next;
XM0447> push7: stk7<-L, :next;
XM0450> push10: :dpushof1; honor TASK, stack overflow
;-----------------------------------------------------------------
; Double-word push dispatch:
; picks up alpha from ib, adds it to T, then pushes and
;
; entry at 'Dpusha' substitutes L for ib.
; entry at 'Dpushc' and 'DpB' is used by RR 6 logic.
; entry at 'dpush' is used by MUL/DIV/LDIV logic.
; returns to 'nextA' <=> ib = 0 or entry at 'Dpush'
;-----------------------------------------------------------------
!1,2,DpA,DpB;
!1,1,Dpushb; shakes B/A dispatch from RCLK
!5,2,Dpushx,RCLKr; shakes IR<-2000 dispatch and
; provides return to RCLK
XM0070> Dpush: MAR<-L<-ib+T, :DpB; L: address of low half
XM0202> Dpusha: SINK<-ib, BUS=0;
XM0203> MAR<-L<-M+T, :DpA;
XM0200> DpA: IR<-0, :Dpushb; mACSOURCE will produce 0
XM0201> DpB: IR<-2000, :Dpushb; mACSOURCE will produce 1
XM0163> Dpushb: temp<-L, :Dpushx; temp: address of low half
XM0204> Dpushx: L<-MD, TASK, :Dpushc;
XM0206> Dpushc: taskhole<-L; taskhole: low half bits
XM0207> T<-0+1;
XM0210> L<-stkp+T+1;
XM0211> MAR<-temp+1; fetch high half
XM0212> stkp<-L; stkp <- stkp+2
XM0213> L<-taskhole; L: low half bits
XM0214> SINK<-stkp, BUS, :dpush; dispatch on new stkp
XM0460> dpush: T<-MD, :dpush; T: high half bits
XM0462> dpush1: stk0<-L, L<-T, TASK, mACSOURCE, :push1; stack cells are S-registers,
XM0463> dpush2: stk1<-L, L<-T, TASK, mACSOURCE, :push2; so mACSOURCE does not affect
XM0464> dpush3: stk2<-L, L<-T, TASK, mACSOURCE, :push3; addressing.
XM0465> dpush4: stk3<-L, L<-T, TASK, mACSOURCE, :push4;
XM0466> dpush5: stk4<-L, L<-T, TASK, mACSOURCE, :push5;
XM0467> dpush6: stk5<-L, L<-T, TASK, mACSOURCE, :push6;
XM0470> dpush7: stk6<-L, L<-T, TASK, mACSOURCE, :push7;
XM0471> dpushof1: T<-sStackOverflow, :KFCr;
XM0472> dpushof2: T<-sStackOverflow, :KFCr;
;-----------------------------------------------------------------
; TOS+T dispatch:
; adds TOS to T, then initiates memory operation on result.
; used as both dispatch table and subroutine - fall-through to 'pushMD'.
; dispatches on old stkp, so MAStkT0 = 1 mod 20B.
;-----------------------------------------------------------------
!17,20,MAStkT,MAStkT0,MAStkT1,MAStkT2,MAStkT3,MAStkT4,MAStkT5,MAStkT6,MAStkT7,,,,,,,;
XM0501> MAStkT0: MAR<-stk0+T, :pushMD;
XM0502> MAStkT1: MAR<-stk1+T, :pushMD;
XM0503> MAStkT2: MAR<-stk2+T, :pushMD;
XM0504> MAStkT3: MAR<-stk3+T, :pushMD;
XM0505> MAStkT4: MAR<-stk4+T, :pushMD;
XM0506> MAStkT5: MAR<-stk5+T, :pushMD;
XM0507> MAStkT6: MAR<-stk6+T, :pushMD;
XM0510> MAStkT7: MAR<-stk7+T, :pushMD;
;-----------------------------------------------------------------
; Common exit used to reset the stack pointer
; the instruction that branches here should have a 'TASK'
; Setstkp must be odd, StkOflw used by PUSH
;-----------------------------------------------------------------
!17,11,Setstkp,,,,,,,,StkOflw;
XM0527> Setstkp: stkp<-L, :next; branch (1) may be pending
XM0537> StkOflw: :dpushof1; honor TASK, dpushof1 is odd
;-----------------------------------------------------------------
; Stack Underflow Handling
;-----------------------------------------------------------------
XM1777> StkUf: T<-sStackUnderflow, :KFCr; catches dispatch of stkp = -1
;-----------------------------------------------------------------
; Store dispatch:
; pops TOS to MD.
; called from many places.
; dispatches on old stkp, so MDpop0 = 1 mod 20B.
; The invoking instruction must load MAR and may optionally keep ball 1
; in the air by having a branch pending. That is, entry at 'StoreB' will
; cause control to pass to 'next', while entry at 'StoreA' will cause
; control to pass to 'nextA'.
;-----------------------------------------------------------------
!1,2,StoreBa,StoreAa;
!17,20,MDpopuf,MDpop0,MDpop1,MDpop2,MDpop3,MDpop4,MDpop5,MDpop6,MDpop7,,,,,,,;
XM0166> StoreB: L<-stkp-1, BUS;
XM0220> StoreBa: stkp<-L, TASK, :MDpopuf;
XM0167> StoreA: L<-stkp-1, BUS;
XM0221> StoreAa: stkp<-L, BUS=0, TASK, :MDpopuf; keep branch (1) alive
XM0541> MDpop0: MD<-stk0, :next;
XM0542> MDpop1: MD<-stk1, :next;
XM0543> MDpop2: MD<-stk2, :next;
XM0544> MDpop3: MD<-stk3, :next;
XM0545> MDpop4: MD<-stk4, :next;
XM0546> MDpop5: MD<-stk5, :next;
XM0547> MDpop6: MD<-stk6, :next;
XM0550> MDpop7: MD<-stk7, :next;
;-----------------------------------------------------------------
; Double-word pop dispatch:
; picks up alpha from ib, adds it to T, then pops stack into result and
; result+1
; entry at 'Dpopa' substitutes L for ib.
; returns to 'nextA' <=> ib = 0 or entry at 'Dpop'
;-----------------------------------------------------------------
!17,20,dpopuf2,dpopuf1,dpop1,dpop2,dpop3,dpop4,dpop5,dpop6,dpop7,,,,,,,;
!1,1,Dpopb; required by placement of
; MDpopuf only.
XM0071> Dpop: L<-T<-ib+T+1;
XM0540> MDpopuf: IR<-0, :Dpopb; Note: MDpopuf is merely a
; convenient label which leads
; to a BUS dispatch on stkp in
; the case that stkp is -1. It
; is used by the Store dispatch
; above.
XM0216> Dpopa: L<-T<-M+T+1;
XM0222> IR<-ib, :Dpopb;
XM0215> Dpopb: MAR<-T, temp<-L;
XM0560> dpopuf2: L<-stkp-1, BUS;
XM0223> stkp<-L, TASK, :dpopuf2;
XM0561> dpopuf1: :StkUf; stack underflow, honor TASK
XM0562> dpop1: MD<-stk1, :Dpopx;
XM0563> dpop2: MD<-stk2, :Dpopx;
XM0564> dpop3: MD<-stk3, :Dpopx;
XM0565> dpop4: MD<-stk4, :Dpopx;
XM0566> dpop5: MD<-stk5, :Dpopx;
XM0567> dpop6: MD<-stk6, :Dpopx;
XM0570> dpop7: MD<-stk7, :Dpopx;
XM0224> Dpopx: SINK<-DISP, BUS=0;
XM0500> MAStkT: MAR<-temp-1, :StoreB;
;-----------------------------------------------------------------
; Get operation-specific code from other files
;-----------------------------------------------------------------
#MesacROM.mu;
; *** 11/23/15 - START OF MESACROM.MU ***
;-----------------------------------------------------------------
; MesacROM.Mu - Jumps, Load/Store, Read/Write, Binary/Unary/Stack Operators
; Last modified by Levin - March 7, 1979 8:29 AM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; J u m p s
;-----------------------------------------------------------------
; The following requirements are assumed:
; 1) J2-J9, JB are usable (in that order) as subroutine
; returns (by JEQx and JNEx).
; 2) since J2-J9 and JB are opcode entry points,
; they must meet requirements set by opcode dispatch.
;-----------------------------------------------------------------
; Jn - jump PC-relative
;-----------------------------------------------------------------
!1,2,JnA,Jbranchf;
XM1600> J2: L<-ONE, :JnA;
XM1601> J3: L<-2, :JnA;
XM1602> J4: L<-3, :JnA;
XM1603> J5: L<-4, :JnA;
XM1604> J6: L<-5, :JnA;
XM1605> J7: L<-6, :JnA;
XM1606> J8: L<-7, :JnA;
XM1607> J9: L<-10, :JnA;
XM0226> JnA: L<-M-1, :Jbranchf; A-aligned - adjust distance
;-----------------------------------------------------------------
; JB - jump PC-relative by alpha, assuming:
; JB is A-aligned
; Note: JEQB and JNEB come here with branch (1) pending
;-----------------------------------------------------------------
!1,1,JBx; shake JEQB/JNEB branch
!1,1,Jbranch; must be odd (shakes IR<- below)
XM1610> JB: T<-ib, :JBx;
XM0225> JBx: L<-400 OR T; <-DISP will do sign extension
XM0230> IR<-M; 400 above causes branch (1)
XM0232> L<-DISP-1, :Jbranch; L: ib (sign extended) - 1
;-----------------------------------------------------------------
; JW - jump PC-relative by alphabeta, assuming:
; if JW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after JW
;-----------------------------------------------------------------
XM1611> JW: IR<-sr1, :FetchAB; returns to JWr
XM0161> JWr: L<-ALLONES+T, :Jbranch; L: alphabeta-1
;-----------------------------------------------------------------
; Jump destination determination
; L has (signed) distance from even byte of word addressed by mpc+1
;-----------------------------------------------------------------
!1,2,Jforward,Jbackward;
!1,2,Jeven,Jodd;
XM0231> Jbranch: T<-0+1, SH<0; dispatch fwd/bkwd target
XM0227> Jbranchf: SINK<-M, BUSODD, TASK, :Jforward; dispatch even/odd target
XM0234> Jforward: temp<-L RSH 1, :Jeven; stash positive word offset
XM0235> Jbackward: temp<-L MRSH 1, :Jeven; stash negative word offset
XM0240> Jeven: T<-temp+1, :NOOP; fetch and execute even byte
XM0240> Jodd: T<-temp+1, :nextXB; fetch and execute odd byte
;-----------------------------------------------------------------
; JZEQB - if TOS (popped) = 0, jump PC-relative by alpha, assuming:
; stack has precisely one element
; JZEQB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!1,2,Jcz,Jco;
XM1644> JZEQB: SINK<-stk0, BUS=0; test TOS = 0
XM0233> L<-stkp-1, TASK, :Jcz;
;-----------------------------------------------------------------
; JZNEB - if TOS (popped) ~= 0, jump PC-relative by alpha, assuming:
; stack has precisely one element
; JZNEB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!1,2,JZNEBne,JZNEBeq;
XM1645> JZNEB: SINK<-stk0, BUS=0; test TOS = 0
XM0236> L<-stkp-1, TASK, :JZNEBne;
XM0244> JZNEBne: stkp<-L, :JB; branch, pick up alpha
XM0245> JZNEBeq: stkp<-L, :nextA; no branch, alignment => nextA
;-----------------------------------------------------------------
; JEQn - if TOS (popped) = TOS (popped), jump PC-relative by n, assuming:
; stack has precisely two elements
;-----------------------------------------------------------------
!1,2,JEQnB,JEQnA;
!7,1,JEQNEcom; shake IR<- dispatch
XM1612> JEQ2: IR<-sr0, L<-T, :JEQnB; returns to J2
XM1613> JEQ3: IR<-sr1, L<-T, :JEQnB; returns to J3
XM1614> JEQ4: IR<-sr2, L<-T, :JEQnB; returns to J4
XM1615> JEQ5: IR<-sr3, L<-T, :JEQnB; returns to J5
XM1616> JEQ6: IR<-sr4, L<-T, :JEQnB; returns to J6
XM1617> JEQ7: IR<-sr5, L<-T, :JEQnB; returns to J7
XM1620> JEQ8: IR<-sr6, L<-T, :JEQnB; returns to J8
XM1621> JEQ9: IR<-sr7, L<-T, :JEQnB; returns to J9
;-----------------------------------------------------------------
; JEQB - if TOS (popped) = TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JEQB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1622> JEQB: IR<-sr10, :JEQnA; returns to JB
;-----------------------------------------------------------------
; JEQ common code
;-----------------------------------------------------------------
!1,2,JEQcom,JNEcom; return points from JEQNEcom
XM0246> JEQnB: temp<-L RSH 1, L<-T, :JEQNEcom; temp:0, L:1 (for JEQNEcom)
XM0247> JEQnA: temp<-L, L<-T, :JEQNEcom; temp:1, L:1 (for JEQNEcom)
!1,2,JEQne,JEQeq;
XM0250> JEQcom: L<-stkp-T-1, :JEQne; L: old stkp - 2
XM0252> JEQne: SINK<-temp, BUS, TASK, :Setstkp; no jump, reset stkp
XM0253> JEQeq: stkp<-L, IDISP, :JEQNExxx; jump, set stkp, then dispatch
;
; JEQ/JNE common code
;
; !7,1,JEQNEcom; appears above with JEQn
; !1,2,JEQcom,JNEcom; appears above with JEQB
XM0267> JEQNEcom: T<-stk1;
XM0254> L<-stk0-T, SH=0; dispatch EQ/NE
XM0255> T<-0+1, SH=0, :JEQcom; test outcome and return
XM0256> JEQNExxx: SINK<-temp, BUS, :J2; even/odd dispatch
;-----------------------------------------------------------------
; JNEn - if TOS (popped) ~= TOS (popped), jump PC-relative by n, assuming:
; stack has precisely two elements
;-----------------------------------------------------------------
!1,2,JNEnB,JNEnA;
XM1623> JNE2: IR<-sr0, L<-T, :JNEnB; returns to J2
XM1624> JNE3: IR<-sr1, L<-T, :JNEnB; returns to J3
XM1625> JNE4: IR<-sr2, L<-T, :JNEnB; returns to J4
XM1626> JNE5: IR<-sr3, L<-T, :JNEnB; returns to J5
XM1627> JNE6: IR<-sr4, L<-T, :JNEnB; returns to J6
XM1630> JNE7: IR<-sr5, L<-T, :JNEnB; returns to J7
XM1631> JNE8: IR<-sr6, L<-T, :JNEnB; returns to J8
XM1632> JNE9: IR<-sr7, L<-T, :JNEnB; returns to J9
;-----------------------------------------------------------------
; JNEB - if TOS (popped) = TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JNEB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1633> JNEB: IR<-sr10, :JNEnA; returns to JB
;-----------------------------------------------------------------
; JNE common code
;-----------------------------------------------------------------
XM0260> JNEnB: temp<-L RSH 1, L<-0, :JEQNEcom; temp:0, L:0
XM0261> JNEnA: temp<-L, L<-0, :JEQNEcom; temp:1, L:0
!1,2,JNEne,JNEeq;
XM0251> JNEcom: L<-stkp-T-1, :JNEne; L: old stkp - 2
XM0262> JNEne: stkp<-L, IDISP, :JEQNExxx; jump, set stkp, then dispatch
XM0263> JNEeq: SINK<-temp, BUS, TASK, :Setstkp; no jump, reset stkp
;-----------------------------------------------------------------
; JrB - for r in {L,LE,G,GE,UL,ULE,UG,UGE}
; if TOS (popped) r TOS (popped), jump PC-relative by alpha, assuming:
; stack has precisely two elements
; JrB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
; The values loaded into IR are not returns but encoded actions:
; Bit 12: 0 => branch if carry zero
; 1 => branch if carry one (mask value: 10)
; Bit 15: 0 => perform add-complement before testing carry
; 1 => perform subtract before testing carry (mask value: 1)
; (These values were chosen because of the masks available for use with <-DISP
; in the existing constants ROM. Note that IR<- causes no dispatch.)
XM1634> JLB: IR<-10, :Jscale; adc, branch if carry one
XM1637> JLEB: IR<-11, :Jscale; sub, branch if carry one
XM1636> JGB: IR<-ONE, :Jscale; sub, branch if carry zero
XM1635> JGEB: IR<-0, :Jscale; adc, branch if carry zero
XM1640> JULB: IR<-10, :Jnoscale; adc, branch if carry one
XM1643> JULEB: IR<-11, :Jnoscale; sub, branch if carry one
XM1642> JUGB: IR<-ONE, :Jnoscale; sub, branch if carry zero
XM1641> JUGEB: IR<-0, :Jnoscale; adc, branch if carry zero
;-----------------------------------------------------------------
; Comparison "subroutine":
;-----------------------------------------------------------------
!1,2,Jadc,Jsub;
; !1,2,Jcz,Jco; appears above with JZEQB
!1,2,Jnobz,Jbz;
!1,2,Jbo,Jnobo;
XM0266> Jscale: T<-77777, :Jadjust;
XM0274> Jnoscale: T<-ALLONES, :Jadjust;
XM0275> Jadjust: L<-stk1+T+1; L:stk1 + (0 or 100000)
XM0276> temp<-L;
XM0300> SINK<-DISP, BUSODD; dispatch ADC/SUB
XM0301> T<-stk0+T+1, :Jadc;
XM0264> Jadc: L<-temp-T-1, :Jcommon; perform add complement
XM0265> Jsub: L<-temp-T, :Jcommon; perform subtract
XM0302> Jcommon: T<-ONE; warning: not T<-0+1
XM0303> L<-stkp-T-1, ALUCY; test ADC/SUB outcome
XM0304> SINK<-DISP, SINK<-lgm10, BUS=0, TASK, :Jcz; dispatch on encoded bit 12
XM0242> Jcz: stkp<-L, :Jnobz; carry is zero (stkp<-stkp-2)
XM0243> Jco: stkp<-L, :Jbo; carry is one (stkp<-stkp-2)
XM0270> Jnobz: L<-mpc+1, TASK, :nextAput; no jump, alignment=>nextAa
XM0271> Jbz: T<-ib, :JBx; jump
XM0272> Jbo: T<-ib, :JBx; jump
XM0273> Jnobo: L<-mpc+1, TASK, :nextAput; no jump, alignment=>nextAa
;-----------------------------------------------------------------
; JIW - see Principles of Operation for description
; assumes:
; stack contains precisely two elements
; if JIW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after JIW
;-----------------------------------------------------------------
!1,2,JIuge,JIul;
!1,1,JIWx;
XM1647> JIW: L<-stkp-T-1, TASK, :JIWx; stkp<-stkp-2
XM0305> JIWx: stkp<-L;
XM0310> T<-stk0;
XM0311> L<-XMAR<-mpc+1; load alphabeta
XM0312> mpc<-L;
XM0313> L<-stk1-T-1; do unsigned compare
XM0314> ALUCY;
XM0315> T<-MD, :JIuge;
XM0306> JIuge: L<-mpc+1, TASK, :nextAput; out of bounds - to 'nextA'
XM0307> JIul: L<-cp+T, TASK; (removing this TASK saves a
XM0316> taskhole<-L; word, but leaves a run of
XM0320> T<-taskhole; 15 instructions)
XM0321> XMAR<-stk0+T; fetch <+alphabeta+X>
XM0322> NOP;
XM0323> L<-MD-1, :Jbranch; L: offset
;-----------------------------------------------------------------
; L o a d s
;-----------------------------------------------------------------
; Note: These instructions keep track of their parity
;-----------------------------------------------------------------
; LLn - push <+n>
; Note: LL3 must be odd!
;-----------------------------------------------------------------
; Note: lp is offset by 2, hence the adjustments below
XM1410> LL0: MAR<-lp-T-1, :pushMD;
XM1411> LL1: MAR<-lp-1, :pushMD;
XM1412> LL2: MAR<-lp, :pushMD;
XM1413> LL3: MAR<-lp+T, :pushMD;
XM1414> LL4: MAR<-lp+T+1, :pushMD;
XM1415> LL5: T<-3, SH=0, :LL3; pick up ball 1
XM1416> LL6: T<-4, SH=0, :LL3; pick up ball 1
XM1417> LL7: T<-5, SH=0, :LL3; pick up ball 1
;-----------------------------------------------------------------
; LLB - push <+alpha>
;-----------------------------------------------------------------
XM1420> LLB: IR<-sr4, :Getalpha; returns to LLBr
XM0044> LLBr: T<-nlpoffset+T+1, SH=0, :LL3; undiddle lp, pick up ball 1
;-----------------------------------------------------------------
; LLDB - push <+alpha>, push <+alpha+1>
; LLDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1421> LLDB: T<-lp, :LDcommon;
XM0324> LDcommon: T<-nlpoffset+T+1, :Dpush;
;-----------------------------------------------------------------
; LGn - push <+n>
; Note: LG2 must be odd!
;-----------------------------------------------------------------
; Note: gp is offset by 1, hence the adjustments below
XM1437> LG0: MAR<-gp-1, :pushMD;
XM1440> LG1: MAR<-gp, :pushMD;
XM1441> LG2: MAR<-gp+T, :pushMD;
XM1442> LG3: MAR<-gp+T+1, :pushMD;
XM1443> LG4: T<-3, SH=0, :LG2; pick up ball 1
XM1444> LG5: T<-4, SH=0, :LG2; pick up ball 1
XM1445> LG6: T<-5, SH=0, :LG2; pick up ball 1
XM1446> LG7: T<-6, SH=0, :LG2; pick up ball 1
;-----------------------------------------------------------------
; LGB - push <+alpha>
;-----------------------------------------------------------------
XM1447> LGB: IR<-sr5, :Getalpha; returns to LGBr
XM0045> GBr: T<-ngpoffset+T+1, SH=0, :LG2; undiddle gp, pick up ball 1
;-----------------------------------------------------------------
; LGDB - push <+alpha>, push <+alpha+1>
; LGDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1450> LGDB: T<-gp+T+1, :LDcommon; T: gp-gpoffset+lpoffset
;-----------------------------------------------------------------
; LIn - push n
;-----------------------------------------------------------------
!1,2,LI0xB,LI0xA; keep ball 1 in air
; Note: all BUS dispatches use old stkp value, not incremented one
XM1456> LI0: L<-stkp+1, BUS, :LI0xB;
XM1457> LI1: L<-stkp+1, BUS, :pushT1B;
XM1460> LI2: T<-2, :pushTB;
XM1461> LI3: T<-3, :pushTB;
XM1462> LI4: T<-4, :pushTB;
XM1463> LI5: T<-5, :pushTB;
XM1464> LI6: T<-6, :pushTB;
XM0326> LI0xB: stkp<-L, L<-0, TASK, :push0;
XM0327> LI0xA: stkp<-L, BUS=0, L<-0, TASK, :push0; BUS=0 keeps branch pending
;-----------------------------------------------------------------
; LIN1 - push -1
;-----------------------------------------------------------------
XM1465> LIN1: T<-ALLONES, :pushTB;
;-----------------------------------------------------------------
; LINI - push 100000
;-----------------------------------------------------------------
XM1466> LINI: T<-100000, :pushTB;
;-----------------------------------------------------------------
; LIB - push alpha
;-----------------------------------------------------------------
XM1467> LIB: IR<-sr2, :Getalpha; returns to pushTB
; Note: pushT1B will handle
; any pending branch
;-----------------------------------------------------------------
; LINB - push (alpha OR 377B8)
;-----------------------------------------------------------------
XM1471> LINB: IR<-sr26, :Getalpha; returns to LINBr
XM0066> LINBr: T<-177400 OR T, :pushTB;
;-----------------------------------------------------------------
; LIW - push alphabeta, assuming:
; if LIW is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after LIW
;-----------------------------------------------------------------
XM1470> LIW: IR<-msr0, :FetchAB; returns to LIWr
XM0160> LIWr: L<-stkp+1, BUS, :pushT1A; duplicates pushTA, but
; because of overlapping
; return points, we
; can't use it
;-----------------------------------------------------------------
; S t o r e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; SLn - <+n><-TOS (popped)
; Note: SL3 is odd!
;-----------------------------------------------------------------
; Note: lp is offset by 2, hence the adjustments below
XM1422> SL0: MAR<-lp-T-1, :StoreB;
XM1423> SL1: MAR<-lp-1, :StoreB;
XM1424> SL2: MAR<-lp, :StoreB;
XM1425> SL3: MAR<-lp+T, :StoreB;
XM1426> SL4: MAR<-lp+T+1, :StoreB;
XM1427> SL5: T<-3, SH=0, :SL3;
XM1430> SL6: T<-4, SH=0, :SL3;
XM1431> SL7: T<-5, SH=0, :SL3;
;-----------------------------------------------------------------
; SLB - <+alpha><-TOS (popped)
;-----------------------------------------------------------------
XM1432> SLB: IR<-sr6, :Getalpha; returns to SLBr
XM0046> SLBr: T<-nlpoffset+T+1, SH=0, :SL3; undiddle lp, pick up ball 1
;-----------------------------------------------------------------
; SLDB - <+alpha+1><-TOS (popped), <+alpha><-TOS (popped), assuming:
; SLDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1562> SLDB: T<-lp, :SDcommon;
XM0325> SDcommon: T<-nlpoffset+T+1, :Dpop;
;-----------------------------------------------------------------
; SGn - <+n><-TOS (popped)
; Note: SG2 must be odd!
;-----------------------------------------------------------------
; Note: gp is offset by 1, hence the adjustments below
XM1451> SG0: MAR<-gp-1, :StoreB;
XM1452> SG1: MAR<-gp, :StoreB;
XM1453> SG2: MAR<-gp+T, :StoreB;
XM1454> SG3: MAR<-gp+T+1, :StoreB;
;-----------------------------------------------------------------
; SGB - <+alpha><-TOS (popped)
;-----------------------------------------------------------------
XM1455> SGB: IR<-sr7, :Getalpha; returns to SGBr
XM0047> SGBr: T<-ngpoffset+T+1, SH=0, :SG2; undiddle gp, pick up ball 1
;-----------------------------------------------------------------
; SGDB - <+alpha+1><-TOS (popped), <+alpha><-TOS (popped), assuming:
; SGDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1563> SGDB: T<-gp+T+1, :SDcommon; T: gp-gpoffset+lpoffset
;-----------------------------------------------------------------
; P u t s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PLn - <+n><-TOS (stack is not popped)
;-----------------------------------------------------------------
!1,1,PLcommon; drop ball 1
; Note: lp is offset by 2, hence the adjustments below
XM1433> PL0: MAR<-lp-T-1, SH=0, :PLcommon; pick up ball 1
XM1434> PL1: MAR<-lp-1, SH=0, :PLcommon;
XM1435> PL2: MAR<-lp, SH=0, :PLcommon;
XM1436> PL3: MAR<-lp+T, SH=0, :PLcommon;
XM0331> PLcommon: L<-stkp, BUS, :StoreBa; don't decrement stkp
;-----------------------------------------------------------------
; B i n a r y o p e r a t i o n s
;-----------------------------------------------------------------
; Warning! Before altering this list, be certain you understand the additional addressing
; requirements imposed on some of these return locations! However, it is safe to add new
; return points at the end of the list.
!37,40,ADDr,SUBr,ANDr,ORr,XORr,MULr,DIVr,LDIVr,SHIFTr,EXCHr,RSTRr,WSTRr,WSBr,WS0r,WSFr,WFr,
WSDBrb,WFSrb,BNDCKr,RWBLrb,WBLrb,,,,,,,,,,,;
;-----------------------------------------------------------------
; Binary operations common code
; Entry conditions:
; Both IR and T hold return number. (More precisely, entry at
; 'BincomB' requires return number in IR, entry at 'BincomA' requires
; return number in T.)
; Exit conditions:
; left operand in L (M), right operand in T
; stkp positioned for subsequent push (i.e. points at left operand)
; dispatch pending (for push0) on return
; if entry occurred at BincomA, IR has been modified so
; that mACSOURCE will produce 1
;-----------------------------------------------------------------
; dispatches on stkp-1, so Binpop1 = 1 mod 20B
!17,20,Binpop,Binpop1,Binpop2,Binpop3,Binpop4,Binpop5,Binpop6,Binpop7,,,,,,,,;
!1,2,BincomB,BincomA;
!4,1,Bincomx; shake IR<- in BincomA
XM0332> BincomB: L<-T<-stkp-1, :Bincomx; value for dispatch into Binpop
XM0334> Bincomx: stkp<-L, L<-T;
XM0330> L<-M-1, BUS, TASK; L:value for push dispatch
XM0335> Bincomd: temp2<-L, :Binpop; stash briefly
XM0333> BincomA: L<-2000 OR T; make mACSOURCE produce 1
XM0620> Binpop: IR<-M, :BincomB;
XM0621> Binpop1: T<-stk1;
XM0336> L<-stk0, :Binend;
XM0622> Binpop2: T<-stk2;
XM0340> L<-stk1, :Binend;
XM0623> Binpop3: T<-stk3;
XM0341> L<-stk2, :Binend;
XM0624> Binpop4: T<-stk4;
XM0342> L<-stk3, :Binend;
XM0625> Binpop5: T<-stk5;
XM0343> L<-stk4, :Binend;
XM0626> Binpop6: T<-stk6;
XM0344> L<-stk5, :Binend;
XM0627> Binpop7: T<-stk7;
XM0345> L<-stk6, :Binend;
XM0346> Binend: SINK<-DISP, BUS; perform return dispatch
XM0347> SINK<-temp2, BUS, :ADDr; perform push dispatch
;-----------------------------------------------------------------
; ADD - replace with sum of top two stack elements
;-----------------------------------------------------------------
XM1650> ADD: IR<-T<-ret0, :BincomB;
XM1000> ADDr: L<-M+T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; ADD01 - replace stk0 with +
;-----------------------------------------------------------------
!1,1,ADD01x; drop ball 1
XM1670> ADD01: T<-stk1-1, :ADD01x;
XM0351> ADD01x: T<-stk0+T+1, SH=0; pick up ball 1
XM0350> L<-stkp-1, :pushT1B; no dispatch => to push0
;-----------------------------------------------------------------
; SUB - replace with difference of top two stack elements
;-----------------------------------------------------------------
XM1651> SUB: IR<-T<-ret1, :BincomB;
XM1001> SUBr: L<-M-T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; AND - replace with AND of top two stack elements
;-----------------------------------------------------------------
XM1660> AND: IR<-T<-ret2, :BincomB;
XM1002> ANDr: L<-M AND T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; OR - replace with OR of top two stack elements
;-----------------------------------------------------------------
XM1661> OR: IR<-T<-ret3, :BincomB;
XM1003> ORr: L<-M OR T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; XOR - replace with XOR of top two stack elements
;-----------------------------------------------------------------
XM1662> XOR: IR<-T<-ret4, :BincomB;
XM1004> XORr: L<-M XOR T, mACSOURCE, TASK, :push0; M addressing unaffected
;-----------------------------------------------------------------
; MUL - replace with product of top two stack elements
; high-order bits of product recoverable by PUSH
;-----------------------------------------------------------------
!7,1,MULDIVcoma; shakes stack dispatch
!1,2,GoROMMUL,GoROMDIV;
!7,2,MULx,DIVx; also shakes bus dispatch
XM1652> MUL: IR<-T<-ret5, :BincomB;
XM1005> MULr: AC1<-L, L<-T, :MULDIVcoma; stash multiplicand
XM0367> MULDIVcoma: AC2<-L, L<-0, :MULx; stash multiplier or divisor
XM0416> MULx: AC0<-L, T<-0+1, :MULDIVcomb; AC0<-0 keeps ROM happy
XM0417> DIVx: AC0<-L, T<-0, BUS=0, :MULDIVcomb; BUS=0 => GoROMDIV
XM0354> MULDIVcomb: L<-MULDIVretloc+T, SWMODE, :GoROMMUL; prepare return address
XM0352> GoROMMUL: PC<-L, :ROMMUL; go to ROM multiply
XM0353> GoROMDIV: PC<-L, :ROMDIV; go to ROM divide
XM0675> MULDIVret: :MULDIVret1; No divide - someday a trap
; perhaps, but garbage now.
XM0676> MULDIVret1: T<-AC1; Normal return
XM0355> L<-stkp+1;
XM0356> L<-T, SINK<-M, BUS;
XM0360> T<-AC0, :dpush; Note! not a subroutine
; call, but a direct
; dispatch.
;-----------------------------------------------------------------
; DIV - push quotient of top two stack elements (popped)
; remainder recoverable by PUSH
;-----------------------------------------------------------------
XM1654> DIV: IR<-T<-ret6, :BincomB;
XM1006> DIVr: AC1<-L, L<-T, BUS=0, :MULDIVcoma; BUS=0 => DIVx
;-----------------------------------------------------------------
; LDIV - push quotient of ,,/ (all popped)
; remainder recoverable by PUSH
;-----------------------------------------------------------------
XM1655> LDIV: IR<-sr27, :Popsub; get divisor
XM0067> LDIVf: AC2<-L; stash it
XM0361> IR<-T<-ret7, :BincomB; L:low bits, T:high bits
XM1007> LDIVr: AC1<-L, L<-T, IR<-0, :DIVx; stash low part of dividend
; and ensure mACSOURCE of 0.
;-----------------------------------------------------------------
; SHIFT - replace with shifted by
; > 0 => left shift, < 0 => right shift
;-----------------------------------------------------------------
!7,1,SHIFTx; shakes stack dispatch
!1,2,Lshift,Rshift;
!1,2,DoShift,Shiftdone;
!1,2,DoRight,DoLeft;
!1,1,Shiftdonex;
XM1663> SHIFT: IR<-T<-ret10, :BincomB;
XM1010> SHIFTr: temp<-L, L<-T, TASK, :SHIFTx; L: value, T: count
XM0427> SHIFTx: count<-L;
XM0366> L<-T<-count;
XM0372> L<-0-T, SH<0; L: -count, T: count
XM0374> IR<-sr1, :Lshift; IR<- causes no branch
XM0362> Lshift: L<-37 AND T, TASK, :Shiftcom; mask to reasonable size
XM0363> Rshift: T<-37, IR<-37; equivalent to IR<-msr0
L<-M AND T, TASK, :Shiftcom; mask to reasonable size
XM0376> Shiftcom: count<-L, :Shiftloop;
XM0402> Shiftloop: L<-count-1, BUS=0; test for completion
XM0403> count<-L, IDISP, :DoShift;
XM0364> DoShift: L<-temp, TASK, :DoRight;
XM0370> DoRight: temp<-L RSH 1, :Shiftloop;
XM0371> DoLeft: temp<-L LSH 1, :Shiftloop;
XM0365> Shiftdone: SINK<-temp2, BUS, :Shiftdonex; dispatch to push result
XM0373> Shiftdonex: L<-temp, TASK, :push0;
;-----------------------------------------------------------------
; D o u b l e - P r e c i s i o n A r i t h m e t i c
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; DADD - add two double-word quantities, assuming:
; stack contains precisely 4 elements
;-----------------------------------------------------------------
!1,1,DoRamDoubles; shake B/A dispatch
XM1664> DADD: L<-4, SWMODE, :DoRamDoubles; drop ball 1
XM0405> DoRamDoubles: SINK<-M, BUS, TASK, :ramOverflow; go to overflow code in RAM
;-----------------------------------------------------------------
; DSUB - subtract two double-word quantities, assuming:
; stack contains precisely 4 elements
;-----------------------------------------------------------------
XM1665> DSUB: L<-5, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; DCOMP - compare two long integers, assuming:
; stack contains precisely 4 elements
; result left on stack is -1, 0, or +1 (single-precision)
; (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------
XM1666> DCOMP: L<-6, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; DUCOMP - compare two long cardinals, assuming:
; stack contains precisely 4 elements
; result left on stack is -1, 0, or +1 (single-precision)
; (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) )
;-----------------------------------------------------------------
XM1667> DUCOMP: L<-7, SWMODE, :DoRamDoubles; drop ball 1
;-----------------------------------------------------------------
; R a n g e C h e c k i n g
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; NILCK - check TOS for NIL (0), trap if so
;-----------------------------------------------------------------
!1,2,InRange,OutOfRange;
XM1571> NILCK: L<-ret17, :Xpopsub; returns to NILCKr
XM0117> NILCKr: T<-ONE, SH=0, :NILCKpush; test TOS=0
XM0404> NILCKpush: L<-stkp+T, :InRange;
XM0410> InRange: SINK<-ib, BUS=0, TASK, :Setstkp; pick up ball 1
XM0411> OutOfRange: T<-sBoundsFaultm1+T+1, :KFCr; T:SD index; go trap
;-----------------------------------------------------------------
; BNDCK - check subrange inclusion
; if TOS-1 ~IN [0..TOS) then trap (test is unsigned)
; only TOS is popped off
;-----------------------------------------------------------------
!7,1,BNDCKx; shake push dispatch
XM1573> BNDCK: IR<-T<-ret22, :BincomB; returns to BNDCKr
XM1022> BNDCKr: SINK<-M-T, :BNDCKx; L: value, T: limit
XM0437> BNDCKx: T<-0, ALUCY, :NILCKpush;
;-----------------------------------------------------------------
; R e a d s
;-----------------------------------------------------------------
; Note: RBr must be odd!
;-----------------------------------------------------------------
; Rn - TOS<-<+n>
;-----------------------------------------------------------------
XM1500> R0: T<-0, SH=0, :RBr;
XM1501> R1: T<-ONE, SH=0, :RBr;
XM1502> R2: T<-2, SH=0, :RBr;
XM1503> R3: T<-3, SH=0, :RBr;
XM1504> R4: T<-4, SH=0, :RBr;
;-----------------------------------------------------------------
; RB - TOS<-<+alpha>, assuming:
;-----------------------------------------------------------------
!1,2,ReadB,ReadA; keep ball 1 in air
XM1505> RB: IR<-sr15, :Getalpha; returns to RBr
XM0055> RBr: L<-stkp-1, BUS, :ReadB;
XM0412> ReadB: stkp<-L, :MAStkT; to pushMD
XM0413> ReadA: stkp<-L, BUS=0, :MAStkT; to pushMDA
;-----------------------------------------------------------------
; RDB - temp<-+alpha, push <>, push <+1>, assuming:
; RDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1514> RDB: IR<-sr30, :Popsub; returns to Dpush
;-----------------------------------------------------------------
; RD0 - temp<-, push <>, push <+1>
;-----------------------------------------------------------------
XM1515> RD0: IR<-sr32, :Popsub; returns to RD0r
XM0072> RD0r: L<-0, :Dpusha;
;-----------------------------------------------------------------
; RILP - push <<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
XM1524> RILP: L<-ret0, :Splitalpha; get two 4-bit values
XM0170> RILPr: T<-lp, :RIPcom; T:address of local 2
;-----------------------------------------------------------------
; RIGP - push <<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
!3,1,IPcom; shake IR<- at WILPr
XM1525> RIGP: L<-ret1, :Splitalpha; get two 4-bit values
XM0171>RIGPr: T<-gp+1, :RIPcom; T:address of global 2
XM0414> RIPcom: IR<-msr0, :IPcom; set up return to pushMD
XM0423> IPcom: T<--3+T+1; T:address of local or global 0
XM0415> MAR<-lefthalf+T; start memory cycle
XM0421> L<-righthalf;
XM0422> IPcomx: T<-MD, IDISP; T:local/global value
XM0424> MAR<-M+T, :pushMD; start fetch/store
;-----------------------------------------------------------------
; RIL0 - push <<>>
;-----------------------------------------------------------------
!1,2,RILxB,RILxA;
XM1527> RIL0: MAR<-lp-T-1, :RILxB; fetch local 0
XM0452> RILxB: IR<-msr0, L<-0, :IPcomx; to pushMD
XM0453> RILxA: IR<-sr1, L<-sr1 AND T, :IPcomx; to pushMDA, L<-0(!)
;-----------------------------------------------------------------
; RXLP - TOS<-<+<+alpha[0-3]>+alpha[4-7]>
;-----------------------------------------------------------------
XM1522> RXLP: L<-ret3, :Splitalpha; will return to RXLPra
XM0173> RXLPra: IR<-sr34, :Popsub; fetch TOS
XM0074> RXLPrb: L<-righthalf+T, TASK; L:TOS+alpha[4-7]
XM0425> righthalf<-L, :RILPr; now act like RILP
;-----------------------------------------------------------------
; W r i t e s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Wn - < (popped)+n><- (popped)
;-----------------------------------------------------------------
!1,2,WnB,WnA; keep ball 1 in air
XM1506> W0: T<-0, :WnB;
XM1507> W1: T<-ONE, :WnB;
XM1510> W2: T<-2, :WnB;
XM0454> WnB: IR<-sr2, :Wsub; returns to StoreB
XM0455> WnA: IR<-sr3, :Wsub; returns to StoreA
;-----------------------------------------------------------------
; Write subroutine:
;-----------------------------------------------------------------
!7,1,Wsubx; shake IR<- dispatch
XM0426> Wsub: L<-stkp-1, BUS, :Wsubx;
XM0457> Wsubx: stkp<-L, IDISP, :MAStkT;
;-----------------------------------------------------------------
; WB - < (popped)+alpha><- (popped)
;-----------------------------------------------------------------
XM1511> WB: IR<-sr16, :Getalpha; returns to WBr
XM0056> WBr: :WnB; branch may be pending
;-----------------------------------------------------------------
; WSB - act like WB but with stack values reversed, assuming:
; WSB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!7,1,WSBx; shake stack dispatch
XM1531> WSB: IR<-T<-ret14, :BincomA; alignment requires BincomA
XM1014> WSBr: T<-M, L<-T, :WSBx;
XM0477> WSBx: MAR<-ib+T, :WScom;
XM0436> WScom: temp<-L;
XM0451> WScoma: L<-stkp-1;
XM0456> MD<-temp;
XM0461> mACSOURCE, TASK, :Setstkp;
;-----------------------------------------------------------------
; WS0 - act like WSB but with alpha value of zero
;-----------------------------------------------------------------
!7,1,WS0x; shake stack dispatch
XM1530> WS0: IR<-T<-ret15, :BincomB;
XM1015> WS0r: T<-M, L<-T, :WS0x;
XM0517> WS0x: MAR<-T, :WScom;
;-----------------------------------------------------------------
; WILP - <+alpha[0-3]>+alpha[4-7] <- (popped)
;-----------------------------------------------------------------
XM1526> WILP: L<-ret2, :Splitalpha; get halves of alpha
XM0172> WILPr: IR<-sr2; IPcom will exit to StoreB
XM0473> T<-lp, :IPcom; prepare to undiddle
;-----------------------------------------------------------------
; WXLP - +<+alpha[0-3]>+alpha[4-7] <- (both popped)
;-----------------------------------------------------------------
XM1523> WXLP: L<-ret4, :Splitalpha; get halves of alpha
XM0174> WXLPra: IR<-sr35, :Popsub; fetch TOS
XM0075> WXLPrb: L<-righthalf+T, TASK; L:TOS+alpha[4-7]
XM0474> righthalf<-L, :WILPr; now act like WILP
;-----------------------------------------------------------------
; WDB - temp<-alpha+ (popped), pop into +1 and , assuming:
; WDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1516> WDB: IR<-sr31, :Popsub; returns to Dpop
;-----------------------------------------------------------------
; WD0 - temp<- (popped), pop into +1 and
;-----------------------------------------------------------------
XM1517> WD0: L<-ret6, TASK, :Xpopsub; returns to WD0r
XM0106> D0r: L<-0, :Dpopa;
;-----------------------------------------------------------------
; WSDB - like WDB but with address below data words, assuming:
; WSDB is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
!7,1,WSDBx;
XM1533> WSDB: IR<-sr24, :Popsub; get low data word
XM0064> WSDBra: saveret<-L; stash it briefly
XM0475> IR<-T<-ret20, :BincomA; alignment requires BincomA
XM1020> WSDBrb: T<-M, L<-T, :WSDBx; L:high data, T:address
XM0557> WSDBx: MAR<-T<-ib+T+1; start store of low data word
XM0476> temp<-L, L<-T; temp:high data
XM0511> temp2<-L, TASK; temp2:updated address
XM0512> MD<-saveret; stash low data word
XM0513> MAR<-temp2-1, :WScoma; start store of high data word
;-----------------------------------------------------------------
; L o n g P o i n t e r o p e r a t i o n s
;-----------------------------------------------------------------
!1,1,RWBLcom; drop ball 1
;-----------------------------------------------------------------
; RBL - like RB, but uses a long pointer
;-----------------------------------------------------------------
XM1537> RBL: L<-M AND NOT T, T<-M, SH=0, :RWBLcom; L: ret0, T: L at entry
;-----------------------------------------------------------------
; WBL - like WB, but uses a long pointer
;-----------------------------------------------------------------
XM1540> WBL: L<-T, T<-M, SH=0, :RWBLcom; L: ret1, T: L at entry
;
; Common long pointer code
;
!1,2,RWBLcomB,RWBLcomA;
!1,1,RWBLxa; drop ball 1
!7,1,RWBLxb; shake stkp dispatch
!7,1,WBLx; shake stkp dispatch
!3,4,RBLra,WBLra,WBLrc,;
!3,4,RWBLdone,RBLdone,,WBLdone;
XM0515> RWBLcom: entry<-L, L<-T, :RWBLcomB; stash return, restore L
XM0520> RWBLcomB: IR<-sr37, :Getalpha;
XM0521> RWBLcomA: IR<-sr37, :GetalphaA;
XM0077> RWBLra: IR<-ret23, L<-T, :RWBLxa; L: alpha byte
XM0523> RWBLxa: alpha<-L, :BincomB; stash alpha, get long pointer
XM1032> RWBLrb: MAR<-BankReg, :RWBLxb; fetch bank register
XM0577> RWBLxb: L<-T, T<-M; T: low half, L: high half
XM0514> temp<-L; temp: high pointer
XM0516> L<-alpha+T; L: low pointer+alpha
XM0522> T<-MD; T: bank register to save
XM0524> MAR<-BankReg; reaccess bank register
XM0525> frame<-L, L<-T; frame: pointer
XM0526> taskhole<-L, TASK; taskhole: old bank register
XM0533> MD<-temp, :WBLx; set new alternate bank value
XM0607> WBLx: XMAR<-frame; start memory access
XM0534> L<-entry+1, BUS; dispatch RBL/WBL
XM0535> entry<-L, L<-T, :RBLra; (L<-T for WBLrc only)
XM0530> RBLra: T<-MD, :RWBLtail; T: data from memory
XM0531> WBLra: IR<-ret24, :BincomB; returns to WBLrb
XM1024> WBLrb: T<-M, :WBLx; T: data to write
XM0532> WBLrc: MD<-M, :RWBLtail; stash data in memory
XM0536> RWBLtail: MAR<-BankReg;
XM0551> SINK<-entry, BUS; dispatch return
XM0600> RWBLdone: MD<-taskhole, :RWBLdone; restore bank register
XM0601> RBLdone: L<-temp2+1, BUS, :pushT1B; temp2: original stkp-2
XM0603> WBLdone: L<-temp2, TASK, :Setstkp; temp2: original stkp-3
;-----------------------------------------------------------------
; U n a r y o p e r a t i o n s
;-----------------------------------------------------------------
; XMESA Note: Untail is wired down by a pre-def in MesaROM.mu
;-----------------------------------------------------------------
; INC - TOS <- +1
;-----------------------------------------------------------------
XM1657> INC: IR<-sr14, :Popsub;
XM0054> INCr: T<-0+T+1, :pushTB;
;-----------------------------------------------------------------
; NEG - TOS <- -
;-----------------------------------------------------------------
XM1656> NEG: L<-ret11, TASK, :Xpopsub;
XM0111> NEGr: L<-0-T, :Untail;
;-----------------------------------------------------------------
; DBL - TOS <- 2*
;-----------------------------------------------------------------
XM1653> DBL: IR<-sr25, :Popsub;
XM0065> DBLr: L<-M+T, :Untail;
;-----------------------------------------------------------------
; Unary operation common code
;-----------------------------------------------------------------
XM0407> Untail: T<-M, :pushTB;
;-----------------------------------------------------------------
; S t a c k a n d M i s c e l l a n e o u s O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PUSH - add 1 to stack pointer
;-----------------------------------------------------------------
!1,1,PUSHx;
XM1564> PUSH: L<-stkp+1, BUS, :PUSHx; BUS checks for overflow
XM0553> PUSHx: SINK<-ib, BUS=0, TASK, :Setstkp; pick up ball 1
;-----------------------------------------------------------------
; POP - subtract 1 from stack pointer
;-----------------------------------------------------------------
XM1565> POP: L<-stkp-1, SH=0, TASK, :Setstkp; L=0 <=> branch 1 pending
; need not check stkp=0
;-----------------------------------------------------------------
; DUP - temp<- (popped), push , push
;-----------------------------------------------------------------
!1,1,DUPx;
XM1570> DUP: IR<-sr2, :DUPx; returns to pushTB
XM0555> DUPx: L<-stkp, BUS, TASK, :Popsuba; don't pop stack
;-----------------------------------------------------------------
; EXCH - exchange top two stack elements
;-----------------------------------------------------------------
!1,1,EXCHx; drop ball 1
XM1566> EXCH: IR<-ret11, :EXCHx;
XM0571> EXCHx: L<-stkp-1; dispatch on stkp-1
XM0552> L<-M+1, BUS, TASK, :Bincomd; set temp2<-stkp
XM1011> EXCHr: T<-M, L<-T, :dpush; Note: dispatch using temp2
;-----------------------------------------------------------------
; LADRB - push alpha+lp (undiddled)
;-----------------------------------------------------------------
!1,1,LADRBx; shake branch from Getalpha
XM1472> LADRB: IR<-sr10, :Getalpha; returns to LADRBr
XM0050> LADRBr: T<-nlpoffset+T+1, :LADRBx;
XM0573> LADRBx: L<-lp+T, :Untail;
;-----------------------------------------------------------------
; GADRB - push alpha+gp (undiddled)
;-----------------------------------------------------------------
!1,1,GADRBx; shake branch from Getalpha
XM1473> GADRB: IR<-sr11, :Getalpha; returns to GADRBr
XM0051> GADRBr: T<-ngpoffset+T+1, :GADRBx;
XM0575> GADRBx: L<-gp+T, :Untail;
;-----------------------------------------------------------------
; S t r i n g O p e r a t i o n s
;-----------------------------------------------------------------
!7,1,STRsub; shake stack dispatch
!1,2,STRsubA,STRsubB;
!1,2,RSTRrx,WSTRrx;
XM0617> STRsub: L<-stkp-1; update stack pointer
XM0554> stkp<-L;
XM0556> L<-ib+T; compute index and offset
XM0572> SINK<-M, BUSODD, TASK;
XM0574> count<-L RSH 1, :STRsubA;
XM0610> STRsubA: L<-177400, :STRsubcom; left byte
XM0611> STRsubB: L<-377, :STRsubcom; right byte
XM0576> STRsubcom: T<-temp; get string address
XM0602> MAR<-count+T; start fetch of word
XM0606> T<-M; move mask to more useful place
XM0613> SINK<-DISP, BUSODD; dispatch to caller
XM0616> mask<-L, SH<0, :RSTRrx; dispatch B/A, mask for WSTR
;-----------------------------------------------------------------
; RSTR - push byte of string using base () and index ()
; assumes RSTR is A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
!1,2,RSTRB,RSTRA;
XM1520> RSTR: IR<-T<-ret12, :BincomB;
XM1012> RSTRr: temp<-L, :STRsub; stash string base address
XM0614> RSTRrx: L<-MD AND T, TASK, :RSTRB; isolate good bits
XM0630> RSTRB: temp<-L, :RSTRcom;
XM0631> RSTRA: temp<-L LCY 8, :RSTRcom; right-justify byte
XM0632> RSTRcom: T<-temp, :pushTA; go push result byte
;-----------------------------------------------------------------
; WSTR - pop into string byte using base () and index ()
; assumes WSTR is A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
!1,2,WSTRB,WSTRA;
XM1521> WSTR: IR<-T<-ret13, :BincomB;
XM1013> WSTRr: temp<-L, :STRsub; stash string base
XM0615> WSTRrx: L<-MD AND NOT T, :WSTRB; isolate good bits
XM0634> WSTRB: temp2<-L, L<-ret0, TASK, :Xpopsub; stash them, return to WSTRrB
XM0635> WSTRA: temp2<-L, L<-ret0+1, TASK, :Xpopsub; stash them, return to WSTRrA
XM0101> WSTRrA: taskhole<-L LCY 8; move new data to odd byte
XM0633> T<-taskhole, :WSTRrB;
XM0100> WSTRrB: T<-mask.T;
XM0636> L<-temp2 OR T;
XM0637> T<-temp; retrieve string address
XM0640> MAR<-count+T;
XM0641> TASK;
XM0642> MD<-M, :nextA;
;-----------------------------------------------------------------
; F i e l d I n s t r u c t i o n s
;-----------------------------------------------------------------
; temp2 is coded as follows:
; 0 - RF, RFS
; 1 - WF, WSF, WFS
; 2 - RFC
%1,3,2,RFrr,WFrr; returns from Fieldsub
!7,1,Fieldsub; shakes stack dispatch
; !7,1,WFr; (required by WSFr) is implicit in ret17 (!)
;-----------------------------------------------------------------
; RF - push field specified by beta in word at (popped) + alpha
; if RF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after RF
;-----------------------------------------------------------------
XM1512> RF: IR<-sr12, :Popsub;
XM0052> RFr: L<-ret0, :Fieldsub;
XM0646> RFrr: T<-mask.T, :pushTA; alignment requires pushTA
;-----------------------------------------------------------------
; WF - pop data in into field specified by beta in word at (popped) + alpha
; if WF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after WF
;-----------------------------------------------------------------
; !1,2,WFnzct,WFret; - see location-specific definitions
XM1513> WF: IR<-T<-ret17, :BincomB; L:new data, T:address
XM1017> WFr: newfield<-L, L<-ret0+1, :Fieldsub; (actually, L<-ret1)
XM0647> WFrr: T<-mask;
XM0643> L<-M AND NOT T; set old field bits to zero
XM0644> temp<-L; stash result
XM0645> T<-newfield.T; save new field bits
XM0650> L<-temp OR T, TASK; merge old and new
XM0651> CYCOUT<-L; stash briefly
XM0652> T<-index, BUS=0; get position, test for zero
XM0653> L<-WFretloc, :WFnzct; get return address from ROM
XM0604> WFnzct: PC<-L; stash return
XM0654> L<-20-T, SWMODE; L:remaining count to cycle
XM0655> T<-CYCOUT, :RAMCYCX; go cycle remaining amount
XM0605> WFret: MAR<-frame; start memory
XM0656> L<-stkp-1; pop remaining word
XM0660> MD<-CYCOUT, TASK, :JZNEBeq; stash data, go update stkp
;-----------------------------------------------------------------
; WSF - like WF, but with top two stack elements reversed
; if WSF is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after WSF
;-----------------------------------------------------------------
XM1532> WSF: IR<-T<-ret16, :BincomB; L:address, T:new data
XM1016> WSFr: L<-T, T<-M, :WFr;
;-----------------------------------------------------------------
; RFS - like RF, but with a word containing alpha and beta on top of stack
; if RFS is A-aligned, B byte is irrelevant
;-----------------------------------------------------------------
XM1535> RFS: L<-ret12, TASK, :Xpopsub; get alpha and beta
XM0112> RFSra: temp<-L; stash for WFSa
XM0661> L<-ret13, TASK, :Xpopsub; T:address
XM0113> RFSrb: L<-ret0, BUS=0, :Fieldsub; returns quickly to WFSa
;-----------------------------------------------------------------
; WFS - like WF, but with a word containing alpha and beta on top of stack
; if WFS is A-aligned, B byte is irrelevant
;-----------------------------------------------------------------
!1,2,Fieldsuba,WFSa;
XM1536> WFS: L<-ret14, TASK, :Xpopsub; get alpha and beta
XM0114> WFSra: temp<-L; stash temporarily
XM0664> IR<-T<-ret21, :BincomB; L:new data, T:address
XM1021> WFSrb: newfield<-L, L<-ret0+1, BUS=0, :Fieldsub; returns quickly to WFSa
XM0663> WFSa: frame<-L; stash address
XM0665> T<-177400; to separate alpha and beta
XM0666> L<-temp AND T, T<-temp, :Getalphab; L:alpha, T:both
; returns to Fieldra
;-----------------------------------------------------------------
; RFC - like RF, but uses ++ as address
; if RFC is A-aligned, B byte is irrelevant
; alpha in B byte, beta in A byte of word after RF
;-----------------------------------------------------------------
XM1534> FC: L<-ret16, TASK, :Xpopsub; get index into code segment
XM0116> RFCr: L<-cp+T;
XM0667> T<-M; T:address
XM0670> L<-ret2, :Fieldsub; returns to RFrr
;-----------------------------------------------------------------
; Field instructions common code
; Entry conditions:
; L holds return offset
; T holds base address
; Exit conditions:
; mask: right-justified mask
; frame: updated address, including alpha
; index: left cycles needed to right-justify field [0-15]
; L,T: data word from location cycled left bits
;-----------------------------------------------------------------
%2,3,1,NotCodeSeg,IsCodeSeg;
XM0657> Fieldsub: temp2<-L, L<-T, IR<-msr0, TASK, :Fieldsuba; stash return
XM0662> Fieldsuba: frame<-L, :GetalphaA; stash base address
; T: beta, ib: alpha
XM0040> Fieldra: L<-ret5;
XM0672> saveret<-L, :Splitcomr; get two halves of beta
XM0175> Fieldrb: T<-righthalf; index for MASKTAB
XM0674> MAR<-MASKTAB+T; start fetch of mask
XM0677> T<-lefthalf+T+1; L:left-cycle count
XM0700> L<-17 AND T; mask to 4 bits
XM0701> index<-L; stash position
XM0702> L<-MD, TASK; L:mask for caller's use
XM0703> mask<-L; stash mask
XM0704> SINK<-temp2, BUS; temp2=2 <=> RFC
XM0705> T<-frame, :NotCodeSeg; get base address
XM0671> NotCodeSeg: L<-MAR<-ib+T, :StashFieldLoc; add alpha
XM0673> IsCodeSeg: XMAR<-ib+T, :DoCycle; add alpha
XM0706> StashFieldLoc: frame<-L, :DoCycle; stash updated address for WF
XM0707> DoCycle: L<-Fieldretloc; return location from RAMCYCX
XM0710> PC<-L;
XM0711> T<-MD, SWMODE; data word into T for cycle
XM0712> L<-index, :RAMCYCX; count to cycle, go do it
XM0612> Fieldrc: SINK<-temp2, BUSODD; return dispatch
XM0715> L<-T<-CYCOUT, :RFrr; cycled data word in L and T
; *** 11/23/15 - END OF MESACROM.MU ***
#MesadROM.mu;
; *** 11/23/15 - START OF MESADROM.MU ***
;-----------------------------------------------------------------
; MesadROM.Mu - Xfer, State switching, process support, Nova interface
; Last modified by Levin - February 27, 1979 4:50 PM
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; F r a m e A l l o c a t i o n
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Alloc subroutine:
; allocates a frame
; Entry conditions:
; frame size index (fsi) in T
; Exit conditions:
; frame pointer in L, T, and frame
; if allocation fails, alternate return address is taken and
; temp2 is shifted left by 1 (for ALLOC)
;-----------------------------------------------------------------
!1,2,ALLOCr,XferGr; subroutine returns
!1,2,ALLOCrf,XferGrf; failure returns
!3,4,Alloc0,Alloc1,Alloc2,Alloc3; dispatch on pointer flag
; if more than 2 callers, un-comment the following pre-definition:
; !17,1,Allocx; shake IR<- dispatch
XM0722> AllocSub: L<-avm1+T+1, TASK, :Allocx; fetch av entry
XM0723> Allocx: entry<-L; save av entry address
XM0730> L<-MAR<-entry;
XM0731> T<-3; mask for pointer flags
XM0732> L<-MD AND T, T<-MD; (L<-MD AND 3, T<-MD)
XM0733> temp<-L, L<-MAR<-T; start reading pointer
XM0734> SINK<-temp, BUS; branch on bits 14:15
XM0735> frame<-L, :Alloc0;
;
; Bits 14:15 = 00, a frame of the right index is queued for allocation
;
XM0724> Alloc0: L<-MD, TASK; new entry for frame vector
XM0736> temp<-L; new value of vector entry
XM0737> MAR<-entry; update frame vector
XM0740> L<-T<-frame, IDISP; establish exit conditions
XM0741> MD<-temp, :ALLOCr; update and return
;
; Bits 14:15 = 01, allocation list empty: restore argument, take failure return
;
XM0725> Alloc1: L<-temp2, IDISP, TASK; restore parameter
XM0742> temp2<-L LSH 1, :ALLOCrf; allocation failed
;
; Bits 14:15 = 10, a pointer to an alternate list to use
;
XM0726> Alloc2: temp<-L RSH 1, :Allocp; indirection: index<-index/4
XM0743> Allocp: L<-temp, TASK;
XM0744> temp<-L RSH 1;
XM0745> T<-temp, :AllocSub;
XM0727> Alloc3: temp<-L RSH 1, :Allocp; (treat type 3 as type 2)
;-----------------------------------------------------------------
; Free subroutine:
; frees a frame
; Entry conditions: address of frame is in 'frame'
; Exit conditions: 'frame' left pointing at released frame (for LSTF)
;-----------------------------------------------------------------
!3,4,RETr,FREEr,LSTFr,; FreeSub returns
!17,1,Freex; shake IR<- dispatch
XM0746> FreeSub: MAR<-frame-1; start read of fsi word
XM0757> Freex: NOP; wait for memory
XM0747> T<-MD; T<-index
XM0753> L<-MAR<-avm1+T+1; fetch av entry
XM0754> entry<-L; save av entry address
XM0755> L<-MD; read current pointer
XM0756> MAR<-frame; write it into current frame
XM0760> temp<-L, TASK;
XM0761> MD<-temp; write!
XM0762> MAR<-entry; entry points at frame
XM0763> IDISP, TASK;
XM0764> MD<-frame, :RETr; free
;-----------------------------------------------------------------
; ALLOC - allocate a frame whose fsi is specified by (popped)
;-----------------------------------------------------------------
!1,1,Savpcinframe; (here so ALLOCrf can call it)
; The following logically belongs here; however, because the entry point to general Xfer is
; known to the outside world, the real declaration appears in MesaROM.mu.
; !7,10,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr,,; return points for Savpcinframe
!1,2,doAllocTrap,XferGfz; used by XferGrf
XM1756> ALLOC: L<-ret7, TASK, :Xpopsub; returns to ALLOCrx
XM0107> ALLOCrx: temp2<-L LSH 1, IR<-msr0, :AllocSub; L,T: fsi
XM0716> ALLOCr: L<-stkp+1, BUS, :pushT1B; duplicates pushTB
;
; Allocation failed - save mpc, undiddle lp, push fsi*4 on stack, then trap
;
XM0720> ALLOCrf: IR<-sr5, :Savpcinframe; failure because lists empty
XM0435> ALLOCrfr: L<-temp2, TASK, :doAllocTrap; pick up trap parameter
;
; Inform software that allocation failed
;
XM0766> doAllocTrap: ATPreg<-L; store param. to trap proc.
XM0770> T<-sAllocTrap, :Mtrap; go trap to software
;-----------------------------------------------------------------
; FREE - release the frame whose address is (popped)
;-----------------------------------------------------------------
XM1757> FREE: L<-ret10, TASK, :Xpopsub; returns to FREErx
XM0110> FREErx: frame<-L, TASK;
XM0771> IR<-sr1, :FreeSub;
XM0751> FREEr: :next;
;-----------------------------------------------------------------
; D e s c r i p t o r I n s t r u c t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; DESCB - push <+gfi offset>+2*alpha+1 (masking gfi word appropriately)
; DESCB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1750> DESCB: T<-gp;
XM0772> T<-ngpoffset+T+1, :DESCBcom; T:address of frame
XM0115> DESCBcom: MAR<-gfioffset+T; start fetch of gfi word
XM0773> T<-gfimask; mask to isolate gfi bits
XM0774> T<-MD.T; T:gfi
XM0775> L<-ib+T, T<-ib; L:gfi+alpha, T:alpha
XM1025> T<-M+T+1, :pushTA; pushTA because A-aligned
;-----------------------------------------------------------------
; DESCBS - push <+gfi offset>+2*alpha+1 (masking gfi word appropriately)
; DESCBS is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1751> DESCBS: L<-ret15, TASK, :Xpopsub; returns to DESCBcom
;-----------------------------------------------------------------
; T r a n s f e r O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Savpcinframe subroutine:
; stashes C-relative (mpc,ib) in current local frame
; undiddles lp into my and lp
; Entry conditions: none
; Exit conditions:
; current frame+1 holds pc relative to code segment base (+ = even, - = odd)
; lp is undiddled
; my has undiddled lp (source link for Xfer)
;-----------------------------------------------------------------
; !1,1,Savpcinframe; required by PORTO
; !7,10,XferGT,Xfer,Mstopr,PORTOpc,LSTr,ALLOCrfr,,; returns (appear with ALLOC)
!7,1,Savpcx; shake IR<- dispatch
!1,2,Spcodd,Spceven; pc odd or even
XM0765> Savpcinframe: T<-cp, :Savpcx; code segment base
XM1027> Savpcx: L<-mpc-T; L is code-relative pc
XM1026> SINK<-ib, BUS=0; check for odd or even pc
XM1032> T<-M, :Spcodd; pick up pc word addr
XM1030> Spcodd: L<-0-T, TASK, :Spcopc; - pc => odd, this word
XM1031> Spceven: L<-0+T+1, TASK, :Spcopc; + pc => even, next word
XM1033> Spcopc: taskhole<-L; pc value to save
XM1034> L<-0; (can't merge above - TASK)
XM1035> T<-npcoffset; offset to pc stash
XM1036> MAR<-lp-T, T<-lp; (MAR<-lp-npcoffset, T<-lp)
XM1037> ib<-L; clear ib for XferG
XM1040> L<-nlpoffset+T+1; L:undiddled lp
XM1041> MD<-taskhole; stash pc in frame+pcoffset
XM1042> my<-L, IDISP, TASK; store undiddled lp
XM1043> lp<-L, :XferGT;
;-----------------------------------------------------------------
; Loadgc subroutine:
; load global pointer and code pointer given local pointer or GFT pointer
; Entry conditions:
; T contains either local frame pointer or GFT pointer
; memory fetch of T has been started
; pending branch (1) catches zero pointer
; Exit conditions:
; lp diddled (to framebase+6)
; mpc set from second word of entry (PC or EV offset)
; first word of code segment set to 1 (used by code swapper)
; Assumes only 2 callers
;-----------------------------------------------------------------
!1,2,Xfer0r,Xfer1r; return points
!1,2,Loadgc,LoadgcTrap;
!1,2,LoadgcOK,LoadgcNull; good global frame or null
!1,2,LoadgcIn,LoadgcSwap; in-core or swapped out
!1,2,LoadgcDiv2,LoadgcDiv4; first/second shift
!1,2,LoadgcNoXM,LoadgcIsXM; short/long codebase
XM1046> Loadgc: L<-lpoffset+T; diddle (presumed) lp
XM1060> lp<-L; (only correct if frame ptr)
XM1061> T<-MD; global frame address
XM1062> L<-MD; 2nd word (PC or EV offset)
XM1063> MAR<-cpoffset+T; read code pointer
XM1064> mpc<-L, L<-T; copy g to L for null test
XM1065> L<-cpoffset+T+1, SH=0; test gf=0
XM1066> taskhole<-L, :LoadgcOK; taskhole:addr of hi code base
XM1050> LoadgcOK: L<-MD, BUSODD, TASK; L: low bits of code base
XM1067> cp<-L, :LoadgcIn; stash low bits, branch if odd
XM1052> LoadgcIn: MAR<-BankReg; access bank register
XM1070> T<-14; mask to save primary bank
XM1071> L<-MD AND T; L: primary bank *4
XM1072> temp2<-L, :LoadgcShift; temp2: primary bank *4
XM1073> LoadgcShift: newfield<-L RSH 1, L<-0-T, :LoadgcDiv2; newfield: bank*2, L: negative
XM1054> LoadgcDiv2: L<-newfield, SH<0, TASK, :LoadgcShift; SH<0 forces branch, TASK safe
XM1055> LoadgcDiv4: MAR<-T<-taskhole; fetch high bits of code base
XM1074> L<-gpcpoffset+T; diddle gp
XM1075> gp<-L;
XM1076> T<-177400; mask for high bits
XM1077> L<-MD AND T, T<-MD;
XM1100> T<-3.T, SH=0; T: bank if long codebase
XM1101> MAR<-BankReg, :LoadgcNoXM; initiate store
XM1056> LoadgcNoXM: T<-newfield, :LoadgcIsXM; T: MDS bank
XM1057> LoadgcIsXM: L<-temp2 OR T, TASK; L: new bank registers
XM1102> MD<-M; stash bank
XM1103> XMAR<-cp; access first cseg word
XM1104> IDISP, TASK; dispatch return
XM1105> MD<-ONE, :Xfer0r;
;
; picked up global frame of zero somewhere, call it unbound
;
!1,1,Stashmx;
XM1051> LoadgcNull: T<-sUnbound, :Stashmx; BUSODD may be pending
;
; swapped code segment, trap to software
;
XM1053> LoadgcSwap: T<-sSwapTrap, :Stashmx;
;
; destination link = 0
;
XM1047> LoadgcTrap: T<-sControlFault, :Mtrap;
;-----------------------------------------------------------------
; CheckXferTrap subroutine:
; Handles Xfer trapping
; Entry conditions:
; IR: return number in DISP
; T: parameter to be passed to trap routine
; Exit conditions:
; if trapping enabled, initiates trap and doesn't return.
;------------------------------------------------------------------
!3,4,Xfers,XferG,RETxr,; returns from CheckXferTrap
!1,2,NoXferTrap,DoXferTrap;
!3,1,DoXferTrapx;
XM1106> CheckXferTrap: L<-XTSreg, BUSODD; XTSreg[15]=1 => trap
XM1116> SINK<-DISP, BUS, :NoXferTrap; dispatch (possible) return
XM1114> NoXferTrap: XTSreg<-L RSH 1, :Xfers; reset XTSreg[15] to 0 or 1
XM1115> DoXferTrap: L<-DISP, :DoXferTrapx; tell trap handler which case
XM1113> DoXferTrapx: XTSreg<-L LCY 8, L<-T; L:trap parameter
XM1117> XTPreg<-L;
XM1120> T<-sXferTrap, :Mtrap; off to trap sequence
;-----------------------------------------------------------------
; Xfer open subroutine:
; decodes general destination link for Xfer
; Entry conditions:
; source link in my
; destination link in mx
; Exit conditions:
; if destination is frame pointer, does complete xfer and exits to Ifetch.
; if destination is procedure descriptor, locates global frame and entry
; number, then exits to 'XferG'.
;------------------------------------------------------------------
!3,4,Xfer0,Xfer1,Xfer2,Xfer3; destination link type
XM0431> Xfer: T<-mx; mx[14:15] is dest link type
XM1121> IR<-0, :CheckXferTrap;
XM1110> Xfers: L<-3 AND T; extract type bits
XM1122> SINK<-M, L<-T, BUS; L:dest link, branch on type
XM1123> SH=0, MAR<-T, :Xfer0; check for link = 0. Memory
; data is used only if link
; is frame pointer or indirect
;-----------------------------------------------------------------
; mx[14-15] = 00
; Destination link is frame pointer
;-----------------------------------------------------------------
XM1124> Xfer0: IR<-msr0, :Loadgc; to LoadgcNull if dest link = 0
XM1044> Xfer0r: L<-T<-mpc; offset from cp: - odd, + even
;
; If 'brkbyte' ~= 0, we are proceeding from a breakpoint.
; pc points to the BRK instruction:
; even pc => fetch word, stash left byte in ib, and execute brkbyte
; odd pc => clear ib, execute brkbyte
;
!1,2,Xdobreak,Xnobreak;
!1,2,Xfer0B,Xfer0A;
!1,2,XbrkB,XbrkA;
!1,2,XbrkBgo,XbrkAgo;
XM1140> SINK<-brkbyte, BUS=0; set up by Loadstate
XM1141> SH<0, L<-0, :Xdobreak; dispatch even/odd pc
;
; Not proceeding from a breakpoint - simply pick up next instruction
;
XM1131> Xnobreak: :Xfer0B;
XM1132> Xfer0B: L<-XMAR<-cp+T, :nextAdeafa; fetch word, pc even
XM1133> Xfer0A: L<-XMAR<-cp-T; fetch word, pc odd
XM1142> mpc<-L, :nextXBni;
;
; Proceeding from a breakpoint - dispatch brkbyte and clear it
;
XM1130> Xdobreak: ib<-L, :XbrkB; clear ib for XbrkA
XM1134> XbrkB: IR<-sr20; here if BRK at even byte
XM1143> L<-XMAR<-cp+T, :GetalphaAx; set up ib (return to XbrkBr)
XM1135> XbrkA: L<-cp-T; here if BRK at odd byte
XM1144> mpc<-L, L<-0, BUS=0, :XbrkBr; ib already zero (to XbrkAgo)
XM0060> XbrkBr: SINK<-brkbyte, BUS, :XbrkBgo; dispatch brkbyte
XM1136> XbrkBgo: brkbyte<-L RSH 1, T<-0+1, :NOOP; clear brkbyte, act like nextA
XM1137> XbrkAgo: brkbyte<-L, T<-0+1, BUS=0, :NOOP; clear brkbyte, act like next
;-----------------------------------------------------------------
; mx[14-15] = 01
; Destination link is procedure descriptor:
; mx[0-8]: GFT index (gfi)
; mx[9-13]: EV bias, or entry number (en)
;-----------------------------------------------------------------
XM1125> Xfer1: temp<-L RSH 1; temp:ep*2+garbage
XM1145> count<-L MLSH 1; since L=T, count<-L LCY 1;
XM1146> L<-count, TASK; gfi now in 0-7 and 15
XM1147> count<-L LCY 8; count:gfi w/high bits garbage
XM1150> L<-count, TASK;
XM1151> count<-L LSH 1; count:gfi*2 w/high garbage
XM1152> T<-count;
XM1153> T<-1777.T; T:gfi*2
XM1154> MAR<-gftm1+T+1; fetch GFT[T]
XM1155> IR<-sr1, :Loadgc; pick up two word entry into
; gp and mpc
XM0145> Xfer1r: L<-temp, TASK; L:en*2+high bits of garbage
XM1156> count<-L RSH 1; count:en+high garbage
XM1157> T<-count;
XM1160> T<-enmask.T; T:en
XM1161> L<-mpc+T+1, TASK; (mpc has EV base in code seg)
XM1162> count<-L LSH 1, :XferG; count:ep*2
;-----------------------------------------------------------------
; mx[14-15] = 10
; Destination link is indirect:
; mx[0-15]: address of location holding destination link
;-----------------------------------------------------------------
XM1126> Xfer2: NOP; wait for memory
XM1163> T<-MD, :Xfers;
;-----------------------------------------------------------------
; mx[14-15] = 11
; Destination link is unbound:
; mx[0-15]: passed to trap handler
;-----------------------------------------------------------------
XM1127> Xfer3: T<-sUnbound, :Stashmx;
;-----------------------------------------------------------------
; XferG open subroutine:
; allocates new frame and patches links
; Entry conditions:
; 'count' holds index into code segment entry vector
; assumes lp is undiddled (in case of AllocTrap)
; assumes gp (undiddled) and cp set up
; Exit conditions:
; exits to instruction fetch (or AllocTrap)
;-----------------------------------------------------------------
;
; Pick up new pc from specified entry in entry vector
;
XM0430> XferGT: T<-count; parameter to CheckXferTrap
XM1164> IR<-ONE, :CheckXferTrap;
XM1111> XferG: T<-count; index into entry vector
XM1165> XMAR<-cp+T; fetch of new pc and fsi
XM1166> T<-cp-1; point just before bytes
; (main loop increments mpc)
XM1167> IR<-sr1; note: does not cause branch
XM1170> L<-MD+T; relocate pc from cseg base
XM1171> T<-MD; second word contains fsi
XM1172> mpc<-L; new pc setup, ib already 0
XM1173> T<-377.T, :AllocSub; mask for size index
;
; Stash source link in new frame, establishing dynamic link
;
XM0717> XferGr: MAR<-retlinkoffset+T; T has new frame base
XM1174> L<-lpoffset+T; diddle new lp
XM1175> lp<-L; install diddled lp
XM1176> MD<-my; source link to new frame
;
; Stash new global pointer in new frame (same for local call)
;
XM1177> MAR<-T; write gp to word 0 of frame
XM1200> T<-gpoffset; offset to point at gf base
XM1201> L<-gp-T, TASK; subtract off offset
XM1202> MD<-M, :nextAdeaf; global pointer stashed, GO!
;
; Frame allocation failed - push destination link, then trap
;
; !1,2,doAllocTrap,XferGfz; (appears with ALLOC)
XM0721> XferGrf: L<-mx, BUS=0; pick up destination, test = 0
XM1203> T<-count-1, :doAllocTrap; T:2*ep+1
; if destination link is zero (i.e. local procedure call), we must first
; fabricate the destination link
XM0767> XferGfz: L<-T, T<-ngfioffset; offset from gp to gfi word
XM1204> MAR<-gp-T; start fetch of gfi word
XM1205> count<-L LSH 1; count:4*ep+2
XM1206> L<-count-1; L:4*ep+1
XM1207> T<-gfimask; mask to save gfi only
XM1210> T<-MD.T; T:gfi
XM1211> L<-M+T, :doAllocTrap; L:gfi+4*ep+1 (descriptor)
;-----------------------------------------------------------------
; Getlink subroutine:
; fetches control link from either global frame or code segment
; Entry conditions:
; temp: - (index of desired link + 1)
; IR: DISP field zero/non-zero to select return point (2 callers only)
; Exit conditions:
; L,T: desired control link
;-----------------------------------------------------------------
!1,2,EFCgetr,LLKBr; return points
!1,2,framelink,codelink;
!7,1,Fetchlink; shake IR<- in KFCB
XM1216> Getlink: T<-gp; diddled frame address
XM1220> MAR<-T<-ngpoffset+T+1; fetch word 0 of global frame
XM1221> L<-temp+T, T<-temp; L:address of link in frame
XM1222> taskhole<-L; stash it
XM1223> L<-cp+T; L:address of link in code
XM1224> SINK<-MD, BUSODD, TASK; test bit 15 of word zero
XM1225> temp2<-L, :framelink; stash code link address
XM1214> framelink: MAR<-taskhole, :Fetchlink; fetch link from frame
XM1215> codelink: XMAR<-temp2, :Fetchlink; fetch link from code
XM1217> Fetchlink: SINK<-DISP, BUS=0; dispatch to caller
XM1226> L<-T<-MD, :EFCgetr;
;-----------------------------------------------------------------
; EFCn - perform XFER to destination specified by external link n
;-----------------------------------------------------------------
; !1,1,EFCr; implicit in EFCr's return number (23B)
XM1700> EFC0: IR<-ONE, T<-ONE-1, :EFCr; 0th control link
XM1701> EFC1: IR<-T<-ONE, :EFCr; 1st control link
XM1702> EFC2: IR<-T<-2, :EFCr; . . .
XM1703> EFC3: IR<-T<-3, :EFCr;
XM1704> EFC4: IR<-T<-4, :EFCr;
XM1705> EFC5: IR<-T<-5, :EFCr;
XM1706> EFC6: IR<-T<-6, :EFCr;
XM1707> EFC7: IR<-T<-7, :EFCr;
XM1710> EFC8: IR<-T<-10, :EFCr;
XM1711> EFC9: IR<-T<-11, :EFCr;
XM1712> EFC10: IR<-T<-12, :EFCr;
XM1713> EFC11: IR<-T<-13, :EFCr;
XM1714> EFC12: IR<-T<-14, :EFCr;
XM1715> EFC13: IR<-T<-15, :EFCr;
XM1716> EFC14: IR<-T<-16, :EFCr;
XM1717> EFC15: IR<-T<-17, :EFCr;
;-----------------------------------------------------------------
; EFCB - perform XFER to destination specified by external link 'alpha'
;-----------------------------------------------------------------
!1,1,EFCdoGetlink; shake B/A dispatch (Getalpha)
XM1720> EFCB: IR<-sr23, :Getalpha; fetch link number
XM0063> EFCr: L<-0-T-1, TASK, :EFCdoGetlink; L:-(link number+1)
XM1227> EFCdoGetlink: temp<-L, :Getlink; stash index for Getlink
XM1212> EFCgetr: IR<-sr1, :SFCr; for Savpcinframe; no branch
;-----------------------------------------------------------------
; SFC - Stack Function Call (using descriptor on top of stack)
;-----------------------------------------------------------------
XM1742> SFC: IR<-sr1, :Popsub; get dest link for xfer
; now assume IR still has sr1
XM0041> SFCr: mx<-L, :Savpcinframe; set dest link, return to Xfer
;-----------------------------------------------------------------
; KFCB - Xfer using destination <+alpha>
;-----------------------------------------------------------------
; !1,1,KFCr; implicit in KFCr's return number (21B)
!1,1,KFCx; shake B/A dispatch (Getalpha)
; !7,1,Fetchlink; appears with Getlink
XM1747> KFCB: IR<-sr21, :Getalpha; fetch alpha
XM0061> KFCr: IR<-avm1, T<-avm1+T+1, :KFCx; DISP must be non zero
XM1231> KFCx: MAR<-sdoffset+T, :Fetchlink; Fetchlink shakes IR<- dispatch
;-----------------------------------------------------------------
; BRK - Breakpoint (equivalent to KFC 0)
;-----------------------------------------------------------------
XM1776> BRK: ib<-L, T<-sBRK, :KFCr; ib = 0 <=> BRK B-aligned
;-----------------------------------------------------------------
; Trap sequence:
; used to report various faults during Xfer
; Entry conditions:
; T: index in SD through which to trap
; Savepcinframe has already been called
; entry at Stashmx puts destination link in OTPreg before trapping
;-----------------------------------------------------------------
; !1,1,Stashmx; above with Loadgc code
XM1107> Stashmx: L<-mx; can't TASK, T has trap index
XM1230> OTPreg<-L, :Mtrap;
XM1232> Mtrap: T<-avm1+T+1;
XM1233> MAR<-sdoffset+T; fetch dest link for trap
XM1234> NOP;
XM1235> Mtrapa: L<-MD, TASK; (enter here from PORTO)
XM1236> mx<-L, :Xfer;
;-----------------------------------------------------------------
; LFCn - call local procedure n (i.e. within same global frame)
;-----------------------------------------------------------------
!1,1,LFCx; shake B/A dispatch
XM1721> LFC1: L<-2, :LFCx;
XM1722> LFC2: L<-3, :LFCx;
XM1723> LFC3: L<-4, :LFCx;
XM1724> LFC4: L<-5, :LFCx;
XM1725> LFC5: L<-6, :LFCx;
XM1726> LFC6: L<-7, :LFCx;
XM1727> LFC7: L<-10, :LFCx;
XM1730> LFC8: L<-11, :LFCx;
XM1237> LFCx: count<-L LSH 1, L<-0, IR<-msr0, :SFCr; stash index of proc. (*2)
; dest link = 0 for local call
; will return to XferG
;-----------------------------------------------------------------
; LFCB - call local procedure number 'alpha' (i.e. within same global frame)
;-----------------------------------------------------------------
XM1741> LFCB: IR<-sr22, :Getalpha;
XM0062> LFCr: L<-0+T+1, :LFCx;
;-----------------------------------------------------------------
; RET - Return from function call.
;-----------------------------------------------------------------
!1,1,RETx; shake B/A branch
XM1743> RET: T<-lp, :RETx; local pointer
XM1241> RETx: IR<-2, :CheckXferTrap;
XM1112> RETxr: MAR<-nretlinkoffset+T; get previous local frame
XM1240> L<-nlpoffset+T+1;
XM1242> frame<-L; stash for 'Free'
XM1243> L<-MD; pick up prev frame pointer
XM1244> mx<-L, L<-0, IR<-msr0, TASK; mx points to caller
XM1245> my<-L, :FreeSub; clear my and go free frame
XM0750> RETr: T<-mx, :Xfers; xfer back to caller
;-----------------------------------------------------------------
; LINKB - store back link to enclosing context into local 0
; LINKB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1567> LINKB: MAR<-lp-T-1; address of local 0
XM1246> T<-ib;
XM1247> L<-mx-T, TASK; L: mx-alpha
XM1250> MD<-M, :nextA; local 0 <- mx-alpha
;-----------------------------------------------------------------
; LLKB - push external link 'alpha'
; LLKB is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1744> LLKB: T<-ib; T:alpha
XM1251> L<-0-T-1, IR<-0, :EFCdoGetlink; L:-(alpha+1), go call Getlink
XM1213> LLKBr: :pushTA; alignment requires pushTA
;-----------------------------------------------------------------
; P o r t O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; PORTO - PORT Out (XFER thru PORT addressed by TOS)
;-----------------------------------------------------------------
XM1745> PORTO: IR<-sr3, :Savpcinframe; undiddle lp into my
XM0433> PORTOpc: L<-ret5, TASK, :Xpopsub; returns to PORTOr
XM0105> PORTOr: MAR<-T; fetch from TOS
XM1252> L<-T;
XM1253> MD<-my; frame addr to word 0 of PORT
XM1254> MAR<-M+1; second word of PORT
XM1255> my<-L, :Mtrapa; source link to PORT address
;-----------------------------------------------------------------
; PORTI - PORT In (Fix up PORT return, always immediately after PORTO)
; assumes that my and mx remain from previous xfer
;-----------------------------------------------------------------
!1,1,PORTIx;
!1,2,PORTInz,PORTIz;
XM1746> PORTI: MAR<-mx, :PORTIx; first word of PORT
XM1257> PORTIx: SINK<-my, BUS=0;
XM1256> TASK, :PORTInz;
XM1260> PORTInz: MD<-0;
XM1262> MAR<-mx+1; store it as second word
XM1263> TASK, :PORTIz;
XM1261> PORTIz: MD<-my, :next; store my or zero
;-----------------------------------------------------------------
; S t a t e S w i t c h i n g
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Savestate subroutine:
; saves state of pre-empted emulation
; Entry conditions:
; L holds address where state is to be saved
; assumes undiddled lp
; Exit conditions:
; lp, stkp, and stack (from base to min[depth+2,8]) saved
;-----------------------------------------------------------------
; !1,2,DSTr1,Mstopc; actually appears as %1,1777,776,DSTr1,Mstopc; and is located
; in the front of the main file (Mesa.mu).
!17,20,Sav0r,Sav1r,Sav2r,Sav3r,Sav4r,Sav5r,Sav6r,Sav7r,Sav10r,Sav11r,DSTr,,,,,;
!1,2,Savok,Savmax;
XM1266> Savestate: temp<-L;
XM1267> Savestatea: T<--12+1; i.e. T<--11
XM1270> L<-lp, :Savsuba;
XM1311> Sav11r: L<-stkp, :Savsub;
XM1310> Sav10r: T<-stkp+1;
XM1271> L<--7+T; check if stkp > 5 or negative
XM1272> L<-0+T+1, ALUCY; L:stkp+2
XM1273> temp2<-L, L<-0-T, :Savok; L:-stkp-1
XM1265> Savmax: T<--7; stkp > 5 => save all
XM1274> L<-stk7, :Savsuba;
XM1264> Savok: SINK<-temp2, BUS; stkp < 6 => save to stkp+2
XM1275> count<-L, :Sav0r;
XM1307> Sav7r: L<-stk6, :Savsub;
XM1306> Sav6r: L<-stk5, :Savsub;
XM1305> Sav5r: L<-stk4, :Savsub;
XM1304> Sav4r: L<-stk3, :Savsub;
XM1303> Sav3r: L<-stk2, :Savsub;
XM1302> Sav2r: L<-stk1, :Savsub;
XM1301> Sav1r: L<-stk0, :Savsub;
XM1300> Sav0r: SINK<-DISP, BUS; return to caller
XM1276> T<--12, :DSTr1; (for DST's benefit)
; Remember, T is negative
XM1277> Savsub: T<-count;
XM1313> Savsuba: temp2<-L, L<-0+T+1;
XM1314> MAR<-temp-T;
XM1315> count<-L, L<-0-T; dispatch on pos. value
XM1316> SINK<-M, BUS, TASK;
XM1317> MD<-temp2, :Sav0r;
;-----------------------------------------------------------------
; Loadstate subroutine:
; load state for emulation
; Entry conditions:
; L points to block from which state is to be loaded
; Exit conditions:
; stkp, mx, my, and stack (from base to min[stkp+2,8]) loaded
; (i.e. two words past TOS are saved, if they exist)
; Note: if stkp underflows but an interrupt is taken before we detect
; it, the subsequent Loadstate (invoked by Mgo) will see 377B in the
; high byte of stkp. Thinking this a breakpoint resumption, we will
; load the state, then dispatch the 377 (via brkbyte) in Xfer0, causing
; a branch to StkUf (!) This is not a fool-proof check against a bad
; stkp value at entry, but it does protect against the most common
; kinds of stack errors.
;-----------------------------------------------------------------
!17,20,Lsr0,Lsr1,Lsr2,Lsr3,Lsr4,Lsr5,Lsr6,Lsr7,Lsr10,Lsr11,Lsr12,,,,,;
!1,2,Lsmax,Ldsuba;
!1,2,Lsr,BITBLTdoner;
XM1333> Loadstate: temp<-L, IR<-msr0, :NovaIntrOn; stash pointer
XM1336> Lsr: T<-12, :Ldsuba;
XM1332> Lsr12: my<-L, :Ldsub;
XM1331> Lsr11: mx<-L, :Ldsub;
XM1330> Lsr10: stkp<-L;
XM1340> T<-stkp; check for BRK resumption
XM1341> L<-177400 AND T; (i.e. bytecode in stkp)
XM1342> brkbyte<-L LCY 8; stash for Xfer
XM1343> L<-T<-17.T; mask to 4 bits
XM1344> L<--7+T; check stkp > 6
XM1345> L<-T, SH<0;
XM1346> stkp<-L, T<-0+T+1, :Lsmax; T:stkp+1
XM1334> Lsmax: T<-7, :Ldsuba;
XM1327> Lsr7: stk7<-L, :Ldsub;
XM1326> Lsr6: stk6<-L, :Ldsub;
XM1325> Lsr5: stk5<-L, :Ldsub;
XM1324> Lsr4: stk4<-L, :Ldsub;
XM1323> Lsr3: stk3<-L, :Ldsub;
XM1322> Lsr2: stk2<-L, :Ldsub;
XM1321> Lsr1: stk1<-L, :Ldsub;
XM1320> Lsr0: stk0<-L, :Xfer;
XM1347> Ldsub: T<-count;
XM1335> Ldsuba: MAR<-temp+T;
XM1350> L<-ALLONES+T; decr count for next time
XM1351> count<-L, L<-T; use old value for dispatch
XM1352> SINK<-M, BUS;
XM1353> L<-MD, TASK, :Lsr0;
;-----------------------------------------------------------------
; DST - dump state at block starting at +alpha, reset stack pointer
; assumes DST is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1770> DST: T<-ib; get alpha
XM1354> T<-lp+T+1;
XM1355> L<-nlpoffset1+T+1, TASK; L:lp-lpoffset+alpha
XM1356> temp<-L, IR<-ret0, :Savestatea;
XM0776> DSTr1: L<-my, :Savsuba; save my too!
XM1312> DSTr: temp<-L, L<-0, TASK, BUS=0, :Setstkp; zap stkp, return to 'nextA'
;-----------------------------------------------------------------
; LST - load state from block starting at +alpha
; assumes LST is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1771> LST: L<-ib;
XM1357> temp<-L, L<-0, TASK;
XM1360> ib<-L; make Savpcinframe happy
XM1361> IR<-sr4, :Savpcinframe; returns to LSTr
XM0434> LSTr: T<-temp; get alpha back
XM1362> L<-lp+T, TASK, :Loadstate; lp already undiddled
;-----------------------------------------------------------------
; LSTF - load state from block starting at +alpha, then free frame
; assumes LSTF is A-aligned (also ensures no pending branch at entry)
;-----------------------------------------------------------------
XM1772> LSTF: T<-lpoffset;
XM1363> L<-lp-T, TASK; compute frame base
XM1364> frame<-L;
XM1365> IR<-sr2, :FreeSub;
XM0752> LSTFr: T<-frame; set up by FreeSub
XM1366> L<-ib+T, TASK, :Loadstate; get state from dead frame
;-----------------------------------------------------------------
; E m u l a t o r A c c e s s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; RR - push , where:
; RR is A-aligned (also ensures no pending branch at entry)
; alpha: 1 => wdc, 2 => XTSreg, 3 => XTPreg, 4 => ATPreg,
; 5 => OTPreg
;-----------------------------------------------------------------
!1,1,DoRamRWB; shake B/A dispatch (BLTL)
XM1775> RR: L<-0, SWMODE, :DoRamRWB;
XM1367> DoRamRWB: SINK<-M, BUS, L<-T, :ramOverflow; L<-T for WR
;-----------------------------------------------------------------
; WR - emulator register alpha <- (popped), where:
; WR is A-aligned (also ensures no pending branch at entry)
; alpha: 1 => wdc, 2 => XTSreg
;-----------------------------------------------------------------
XM1774> WR: L<-ret3, TASK, :Xpopsub;
XM0103> WRr: L<-2, SWMODE, :DoRamRWB;
;-----------------------------------------------------------------
; JRAM - JMPRAM for Mesa programs (when emulator is in ROM1)
;-----------------------------------------------------------------
XM1767> JRAM: L<-ret2, TASK, :Xpopsub;
XM0102> JRAMr: SINK<-M, BUS, SWMODE, :next; BUS applied to 'nextBa' (=0)
;-----------------------------------------------------------------
; P r o c e s s / M o n i t o r S u p p o r t
;-----------------------------------------------------------------
!1,1,MoveParms1; shake B/A dispatch
!1,1,MoveParms2; shake B/A dispatch
!1,1,MoveParms3; shake B/A dispatch
;!1,1,MoveParms4; shake B/A dispatch
;-----------------------------------------------------------------
; ME,MRE - Monitor Entry and Re-entry
; MXD - Monitor Exit and Depart
;-----------------------------------------------------------------
!1,1,FastMREx; drop ball 1
!1,1,FastEEx; drop ball 1
!7,1,FastEExx; shake IR<-isME/isMXD
!1,2,MXDr,MEr;
!7,1,FastEExxx; shake IR<-isMRE
%3,17,14,MXDrr,MErr,MRErr;
!1,2,FastEEtrap1,MEXDdone;
!1,2,FastEEtrap2,MREdone;
; The following constants are carefully chosen to agree with the above pre-defs
$isME $6001; IDISP:1, DISP:1, mACSOURCE:1
$isMRE $65403; IDISP:13, DISP:3, mACSOURCE:16
$isMXD $402; IDISP:0, DISP:2, mACSOURCE:0
XM1401> ME: IR<-isME, :FastEEx; indicate ME instruction
XM1404> MXD: IR<-isMXD, :FastEEx; indicate MXD instruction
XM1402> MRE: MAR<-HardMRE, :FastMREx; ~= 0 => do Nova code
XM1377> FastMREx: IR<-isMRE, :MXDr; indicate MRE instruction
XM1475> FastEEx: MAR<-stk0, IDISP, :FastEExx; fetch monitor lock
XM1477> FastEExx: T<-100000, :MXDr; value of unlocked monitor lock
XM1542> MXDr: L<-MD, mACSOURCE, :FastEExxx; L:0 if locked (or queue empty)
XM1543> MEr: L<-MD-T, mACSOURCE, :FastEExxx; L:0 if unlocked
XM1547> FastEExxx: MAR<-stk0, SH=0, :MXDrr; start store, test lock state
; Note: if control goes to FastEEtrap1 or FastEEtrap2, AC1 or AC2 will be smashed,
; but their contents aren't guaranteed anyway.
; Note also that MErr and MXDrr cannot TASK.
XM1554> MXDrr: L<-T, T<-0, :FastEEtrap1; L:100000, T:0 (stkp value)
XM1555> MErr: T<-0+1, :FastEEtrap1; L:0, T:1 (stkp value)
XM1556> MRErr: L<-0+1, TASK, :FastEEtrap2; L:1 (stkp value)
XM1545> MEXDdone: MD<-M, L<-T, TASK, :Setstkp;
XM1551> MREdone: stkp<-L, :ME; queue empty, treat as ME
;-----------------------------------------------------------------
; MXW - Monitor Exit and Wait
;-----------------------------------------------------------------
XM1403> MXW: IR<-4, :MoveParms3; 3 parameters
;-----------------------------------------------------------------
; NOTIFY,BCAST - Awaken process(es) from condition variable
;-----------------------------------------------------------------
XM1405> NOTIFY: IR<-5, :MoveParms1; 1 parameter
XM1406> BCAST: IR<-6, :MoveParms1; 1 parameter
;-----------------------------------------------------------------
; REQUEUE - Move process from queue to queue
;-----------------------------------------------------------------
XM1407> REQUEUE: IR<-7, :MoveParms3; 3 parameter
;-----------------------------------------------------------------
; Parameter Transfer for Nova code linkages
; Entry Conditions:
; T: 1
; IR: dispatch vector index of Nova code to execute
;-----------------------------------------------------------------
;MoveParms4: L<-stk3, TASK; if you uncomment this, don't
; AC3<-L; forget the pre-def above!
XM1375> MoveParms3: L<-stk2, TASK;
XM1550> FastEEtrap2: AC2<-L; (enter here from MRE)
XM1373> MoveParms2: L<-stk1, TASK;
XM1544> FastEEtrap1: AC1<-L; (enter here from ME/MXD)
XM1371> MoveParms1: L<-stk0, TASK;
XM1370> AC0<-L;
XM1372> L<-0, TASK; indicate stack empty
XM1374> stkp<-L;
XM1376> T<-DISP+1, :STOP;
;-----------------------------------------------------------------
; M i s c e l l a n e o u s O p e r a t i o n s
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; CATCH - an emulator no-op of length 2.
; CATCH is assumed to be A-aligned (no pending branch at entry)
;-----------------------------------------------------------------
XM1763> CATCH: L<-mpc+1, TASK, :nextAput; duplicate of 'nextA'
;-----------------------------------------------------------------
; STOP - return to Nova at 'NovaDVloc+1'
; control also comes here from process opcodes with T set appropriately
;-----------------------------------------------------------------
!1,1,GotoNova; shake B/A dispatch
XM1762> STOP: L<-NovaDVloc+T, :GotoNova;
;-----------------------------------------------------------------
; STARTIO - perform Nova-like I/O function
;-----------------------------------------------------------------
XM1766> STARTIO: L<-ret4, TASK, :Xpopsub; get argument in L
XM0104> STARTIOr: SINK<-M, STARTF, :next;
;-----------------------------------------------------------------
; MISC - escape hatch for more than 256 opcodes
;-----------------------------------------------------------------
; !5,2,Dpushx,RCLKr; appears with Dpush
XM1764> MISC: IR<-sr36, :Getalpha; get argument in L
; throws away alpha for now
XM0076> MISCr: L<-CLOCKLOC-1, IR<-CLOCKLOC, :Dpushb; IR<- causes branch 1!
; (and mACSOURCE of 0)
; Dpushb shakes B/A dispatch
XM0205> RCLKr: L<-clockreg, :Dpushc; don't TASK here!
;-----------------------------------------------------------------
; BLT - block transfer
; assumes stack has precisely three elements:
; stk0 - address of first word to read
; stk1 - count of words to move
; stk2 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
!1,1,BLTx; shakes entry B/A branch
XM1752> BLT: stk7<-L, SWMODE, :BLTx; stk7=0 <=> branch pending
XM1553> BLTx: IR<-msr0, :ramBLTloop; IR<- is harmless
;-----------------------------------------------------------------
; BLTL - block transfer (long pointers)
; assumes stack has precisely three elements:
; stk0, stk1 - address of first word to read
; stk2 - count of words to move
; stk3, stk4 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
XM1753> BLTL: stk7<-L, L<-T, SWMODE, :DoRamRWB; stk7=0 <=> branch pending, L:1
;-----------------------------------------------------------------
; BLTC - block transfer from code segment
; assumes stack has precisely three elements:
; stk0 - offset from code base of first word to read
; stk1 - count of words to move
; stk2 - address of first word to write
; the instruction is interruptible and leaves a state suitable
; for re-execution if an interrupt must be honored.
;-----------------------------------------------------------------
!1,1,BLTCx; shake B/A dispatch
XM1754> BLTC: stk7<-L, SWMODE, :BLTCx;
XM1557> BLTCx: IR<-sr1, :ramBLTloop;
;-----------------------------------------------------------------
; BITBLT - do BITBLT using ROM subroutine
; If BITBLT A-aligned, B byte will be ignored
;-----------------------------------------------------------------
!1,1,BITBLTx; shake B/A dispatch
!7,1,DoBITBLTx; shake IR<- dispatch
!3,4,Mstop,,NovaIntrOff,DoBITBLT; includes NovaIntrOff returns
XM1765> BITBLT: stk7<-L, :BITBLTx; save even/odd across ROM call
XM1561> BITBLTx: L<-stk0, TASK;
XM1474> AC2<-L; stash descriptor table
XM1476> L<-stk1, TASK;
XM1546> AC1<-L;
XM1552> SINK<-wdc, BUS=0; check if Mesa interrupts off
XM1560> IR<-sr3, :NovaIntrOff; if so, shut off Nova's
XM1677> DoBITBLT: L<-BITBLTret, SWMODE, :DoBITBLTx; get return address
XM1577> DoBITBLTx: PC<-L, L<-0, :ROMBITBLT; L<-0 for Alto II ROM0 "feature"
XM0714> BITBLTdone: IR<-sr1, :NovaIntrOn; ensure Nova interrupts are on
XM1337> BITBLTdoner: brkbyte<-L, BUS=0, TASK, :Setstkp; don't bother to validate stkp
XM0713> BITBLTintr: L<-AC1, SWMODE; pick up intermediate state
XM1572> stk1<-L, :ramBLTint; stash instruction state
;-----------------------------------------------------------------
; M e s a / N o v a C o m m u n i c a t i o n
;-----------------------------------------------------------------
;-----------------------------------------------------------------
; Subroutines to Enable/Disable Nova Interrupts
;-----------------------------------------------------------------
; !3,4,Mstop,,NovaIntrOff,DoBITBLT; appears with BITBLT
; !1,2,Lsr,BITBLTdoner; appears with LoadState
!7,1,NovaIntrOffx; shake IR<- dispatch
XM1676> NovaIntrOff: T<-100000; disable bit
XM1737> NovaIntrOffx: L<-NWW OR T, TASK, IDISP; turn it on, dispatch return
XM1574> NWW<-L, :Mstop;
XM01575> NovaIntrOn: T<-100000; disable bit
XM01576> L<-NWW AND NOT T, IDISP; turn it off, dispatch return
XM01646> NWW<-L, L<-0, :Lsr;
;-----------------------------------------------------------------
; IWDC - Increment Wakeup Disable Counter (disable interrupts)
;-----------------------------------------------------------------
!1,2,IDnz,IDz;
XM1760> IWDC: L<-wdc+1, TASK, :IDnz; skip check for interrupts
;-----------------------------------------------------------------
; DWDC - Decrement Wakeup Disable Counter (enable interrupts)
;-----------------------------------------------------------------
!1,1,DWDCx;
XM1761> DWDC: MAR<-WWLOC, :DWDCx; OR WW into NWW
XM1671> DWDCx: T<-NWW;
XM1675> L<-MD OR T, TASK;
XM1731> NWW<-L;
XM1732> SINK<-ib, BUS=0;
XM1733> L<-wdc-1, TASK, :IDnz;
; Ensure that one instruction will execute before an interrupt is taken
XM1672> IDnz: wdc<-L, :next;
XM1673> IDz: wdc<-L, :nextAdeaf;
;-----------------------------------------------------------------
; Entry to Mesa Emulation
; AC0 holds address of current process state block
; Location 'PSBloc' is assumed to hold the same value
;-----------------------------------------------------------------
XM00420> Mgo: L<-AC0, :Loadstate;
;-----------------------------------------------------------------
; N o v a I n t e r f a c e
;-----------------------------------------------------------------
$START $L004020,0,0; Nova emulator return address
;-----------------------------------------------------------------
; Transfer to Nova code
; Entry conditions:
; L contains Nova PC to use
; Exit conditions:
; Control transfers to ROM0 at location 'START' to do Nova emulation
; Nova PC points to code to be executed
; Except for parameters expected by the target code, all Nova ACs
; contain garbage
; Nova interrupts are disabled
;-----------------------------------------------------------------
XM1541> GotoNova: PC<-L, IR<-msr0, :NovaIntrOff; stash Nova PC, return to Mstop
;-----------------------------------------------------------------
; Control comes here when an interrupt must be taken. Control will
; pass to the Nova emulator with interrupts enabled.
;-----------------------------------------------------------------
XM0406> Intstop: L<-NovaDVloc, TASK; resume at Nova loc. 30B
XM1734> PC<-L, :Mstop;
;-----------------------------------------------------------------
; Stash the Mesa pc and dump the current process state,
; then start fetching Nova instructions.
;-----------------------------------------------------------------
XM1674> Mstop: IR<-sr2, :Savpcinframe; save mpc for Nova code
XM0432> Mstopr: MAR<-CurrentState; get current state address
XM1735> IR<-ret1; will return to 'Mstopc'
XM1736> L<-MD, :Savestate; dump the state
; The following instruction must be at location 'SWRET', by convention.
; Strictly speaking, the following two lines should read:
;Mstopc: L<-T<-uCodeVersion; stash ucode version number
; L<-100000 OR T, SWMODE; version 1, XM
; However, under the assumption that uCodeVersion=1 (which it does, for Mesa 5.0), we can
; save an instruction as follows:
XM0777> Mstopc: L<-100000+1, SWMODE; version 1, XM
XM1740> cp<-L, :START; off to the Nova ...
; *** 11/23/15 - END OF MESADROM.MU ***
\ No newline at end of file
diff --git a/Contralto/Disassembly/altoIIcode3.mu b/Contralto/Disassembly/altoIIcode3.mu
index e2f99f7..9b8d381 100644
--- a/Contralto/Disassembly/altoIIcode3.mu
+++ b/Contralto/Disassembly/altoIIcode3.mu
@@ -74,92 +74,92 @@ $DDR $L026010,000000,124100; F2 = 10 DWT
;Display Vertical Task
-DV00014> DVT: MAR<- L<- DASTART+1;
-DV00001> CBA<- L, L<- 0;
-DV00005> CURDATA<- L;
-DV00006> SLC<- L;
-DV00017> T<- MD; CAUSE A VERTICAL FIELD INTERRUPT
-DV00023> L<- NWW OR T;
-DV00036> MAR<- CURLOC; SET UP THE CURSOR
-DV00046> NWW<- L, T<- 0-1;
-DV00047> L<- MD XOR T; HARDWARE EXPECTS X COMPLEMENTED
-DV00050> T<- MD, EVENFIELD;
-DV00051> CURX<- L, :DVT1;
+DV0014> DVT: MAR<- L<- DASTART+1;
+DV0001> CBA<- L, L<- 0;
+DV0005> CURDATA<- L;
+DV0006> SLC<- L;
+DV0017> T<- MD; CAUSE A VERTICAL FIELD INTERRUPT
+DV0023> L<- NWW OR T;
+DV0036> MAR<- CURLOC; SET UP THE CURSOR
+DV0046> NWW<- L, T<- 0-1;
+DV0047> L<- MD XOR T; HARDWARE EXPECTS X COMPLEMENTED
+DV0050> T<- MD, EVENFIELD;
+DV0051> CURX<- L, :DVT1;
-DV00002> DVT1: L<- BIAS-T-1, TASK, :DVT2; BIAS THE Y COORDINATE
-DV00003> DVT11: L<- BIAS-T, TASK;
+DV0002> DVT1: L<- BIAS-T-1, TASK, :DVT2; BIAS THE Y COORDINATE
+DV0003> DVT11: L<- BIAS-T, TASK;
-DV00052> DVT2: YPOS<- L, :DVT;
+DV0052> DVT2: YPOS<- L, :DVT;
;Display Horizontal Task.
;11 cycles if no block change, 17 if new control block.
-DH00013> DHT: MAR<- CBA-1;
-DH00053> L<- SLC -1, BUS=0;
-DH00054> SLC<- L, :DHT0;
+DH0013> DHT: MAR<- CBA-1;
+DH0053> L<- SLC -1, BUS=0;
+DH0054> SLC<- L, :DHT0;
-DH00032> DHT0: T<- 37400; MORE TO DO IN THIS BLOCK
-DH00055> SINK<- MD;
-DH00056> L<- T<- MD AND T, SETMODE;
-DH00057> HTAB<- L LCY 8, :NORMODE;
+DH0032> DHT0: T<- 37400; MORE TO DO IN THIS BLOCK
+DH0055> SINK<- MD;
+DH0056> L<- T<- MD AND T, SETMODE;
+DH0057> HTAB<- L LCY 8, :NORMODE;
-DH00034> NORMODE:L<- T<- 377 . T;
-DH00070> AECL<- L, :REST;
+DH0034> NORMODE:L<- T<- 377 . T;
+DH0070> AECL<- L, :REST;
-DH00035> HALFMODE: L<- T<- 377 . T;
-DH00071> AECL<- L, :REST, T<- 0;
+DH0035> HALFMODE: L<- T<- 377 . T;
+DH0071> AECL<- L, :REST, T<- 0;
-DH00072> REST: L<- DWA + T,TASK; INCREMENT DWA BY 0 OR NWRDS
-DH00073> NDNX: DWA<- L, :DHT;
+DH0072> REST: L<- DWA + T,TASK; INCREMENT DWA BY 0 OR NWRDS
+DH0073> NDNX: DWA<- L, :DHT;
-DH00033> DHT1: L<- T<- MD+1, BUS=0;
-DH00074> CBA<- L, MAR<- T, :MOREB;
+DH0033> DHT1: L<- T<- MD+1, BUS=0;
+DH0074> CBA<- L, MAR<- T, :MOREB;
-DH00025> NOMORE: BLOCK, :DNX;
-DH00024> MOREB: T<- 37400;
-DH00075> L<- T<- MD AND T, SETMODE;
-DH00127> MAR<- CBA+1, :NORMX, EVENFIELD;
+DH0025> NOMORE: BLOCK, :DNX;
+DH0024> MOREB: T<- 37400;
+DH0075> L<- T<- MD AND T, SETMODE;
+DH0127> MAR<- CBA+1, :NORMX, EVENFIELD;
-DH00026> NORMX: HTAB<- L LCY 8, :NODD;
-DH00027> HALFX: HTAB<- L LCY 8, :NEVEN;
+DH0026> NORMX: HTAB<- L LCY 8, :NODD;
+DH0027> HALFX: HTAB<- L LCY 8, :NEVEN;
-DH00030> NODD: L<-T<- 377 . T;
-DH00130> AECL<- L, :XREST; ODD FIELD, FULL RESOLUTION
+DH0030> NODD: L<-T<- 377 . T;
+DH0130> AECL<- L, :XREST; ODD FIELD, FULL RESOLUTION
-DH00031> NEVEN: L<- 377 AND T; EVEN FIELD OR HALF RESOLUTION
-DH00131> AECL<-L, T<-0;
+DH0031> NEVEN: L<- 377 AND T; EVEN FIELD OR HALF RESOLUTION
+DH0131> AECL<-L, T<-0;
-DH00132> XREST: L<- MD+T;
-DH00133> T<-MD-1;
-DH00134> DNX: DWA<-L, L<-T, TASK;
-DH00135> SLC<-L, :DHT;
+DH0132> XREST: L<- MD+T;
+DH0133> T<-MD-1;
+DH0134> DNX: DWA<-L, L<-T, TASK;
+DH0135> SLC<-L, :DHT;
;Display Word Task
-DW00011> DWT: T<- DWA;
-DW00136> T<- -3+T+1;
-DW00137> L<- AECL+T,BUS=0,TASK; AECL CONTAINS NWRDS AT THIS TIME
-DW00140> AECL<-L, :DWTZ;
+DW0011> DWT: T<- DWA;
+DW0136> T<- -3+T+1;
+DW0137> L<- AECL+T,BUS=0,TASK; AECL CONTAINS NWRDS AT THIS TIME
+DW0140> AECL<-L, :DWTZ;
-DW00041> DWTY: BLOCK;
-DW00141> TASK, :DWTF;
+DW0041> DWTY: BLOCK;
+DW0141> TASK, :DWTF;
-DW00040> DWTZ: L<-HTAB-1, BUS=0,TASK;
-DW00142> HTAB<-L, :DOTAB;
+DW0040> DWTZ: L<-HTAB-1, BUS=0,TASK;
+DW0142> HTAB<-L, :DOTAB;
-DW00042> DOTAB: DDR<-0, :DWTZ;
-DW00043> NOTAB: MAR<-T<-DWA;
-DW00143> L<-AECL-T-1;
-DW00144> ALUCY, L<-2+T;
-DW00145> DWA<-L, :XNOMORE;
+DW0042> DOTAB: DDR<-0, :DWTZ;
+DW0043> NOTAB: MAR<-T<-DWA;
+DW0143> L<-AECL-T-1;
+DW0144> ALUCY, L<-2+T;
+DW0145> DWA<-L, :XNOMORE;
-DW00045> DOMORE: DDR<-MD, TASK;
-DW00146> DDR<-MD, :NOTAB;
+DW0045> DOMORE: DDR<-MD, TASK;
+DW0146> DDR<-MD, :NOTAB;
-DW00144> XNOMORE:DDR<- MD, BLOCK;
-DW00147> DDR<- MD, TASK;
+DW0144> XNOMORE:DDR<- MD, BLOCK;
+DW0147> DDR<- MD, TASK;
-DW00150> DWTF: :DWT;
+DW0150> DWTF: :DWT;
;Alto Ethernet Microcode, Version III, Boggs and Metcalfe
@@ -171,7 +171,7 @@ DW00150> DWTF: :DWT;
!7,10,,EIFOK,,EOCDW1,,EIFBAD,EOCDWX,EIGO;
;Miscellaneous address constraints
-!7,10,,EOCDW0,EODATA,EIDFUL,EIDZ4,EOCDRS,EIDATA,EPOST;
+!7,10,,EOCDW,EODATA,EIDFUL,EIDZ4,EOCDRS,EIDATA,EPOST;
!7,10,,EIDOK,,,EIDMOR,EIDPST;
!1,1,EIFB1;
!1,1,EIFRST;
@@ -250,11 +250,11 @@ $EISFCT $L024016,000000,000000; F2 = 16, Start input
;in preparation for a hack at EIREST, zero EPNTR
-EN00007> EREST: L<- 0,ERBFCT; What's happening ?
-EN00152> EPNTR<- L,:ENOCMD; [ENOCMD,EOREST,EIREST,ERBRES]
+EN0007> EREST: L<- 0,ERBFCT; What's happening ?
+EN0152> EPNTR<- L,:ENOCMD; [ENOCMD,EOREST,EIREST,ERBRES]
-EN00203> ENOCMD: L<- ESNEVR,:EPOST; Shouldn't happen
-EN00217> ERBRES: L<- ESABRT,:EPOST; Reset Command
+EN0203> ENOCMD: L<- ESNEVR,:EPOST; Shouldn't happen
+EN0217> ERBRES: L<- ESABRT,:EPOST; Reset Command
;Post status and halt. Microcode status in L.
;Put microstatus,,hardstatus in EPLOC, merge c(EBLOC) into NWW.
@@ -263,39 +263,39 @@ EN00217> ERBRES: L<- ESABRT,:EPOST; Reset Command
;Ether Post Function - EPFCT. Gate the hardware status
;(LOW TRUE) to Bus [10:15], reset interface.
-EN00237> EPOST: MAR<- EELOC;
-EN00220> EPNTR<- L,TASK; Save microcode status in EPNTR
-EN00222> MD<- ECNTR; Save ending count
+EN0237> EPOST: MAR<- EELOC;
+EN0220> EPNTR<- L,TASK; Save microcode status in EPNTR
+EN0222> MD<- ECNTR; Save ending count
-EN00224> MAR<- EPLOC; double word reference
-EN00230> T<- NWW;
-EN00240> MD<- EPNTR,EPFCT; BUS AND EPNTR with Status
-EN00260> L<- MD OR T,TASK; NWW OR c(EBLOC)
-EN00261> NWW<- L,:EREST; Done. Wait for next command
+EN0224> MAR<- EPLOC; double word reference
+EN0230> T<- NWW;
+EN0240> MD<- EPNTR,EPFCT; BUS AND EPNTR with Status
+EN0260> L<- MD OR T,TASK; NWW OR c(EBLOC)
+EN0261> NWW<- L,:EREST; Done. Wait for next command
;This is a subroutine called from both input and output (EOCDGO
;and EISET). The return address is determined by testing ECBFCT,
;which will branch if the buffer has any words in it, which can
;only happen during input.
-EN00262> ESETUP: NOP;
-EN00263> L<- MD,BUS=0; check for zero length
-EN00264> T<- MD-1,:ECNTOK; [ECNTOK,ECNTZR] start-1
+EN0262> ESETUP: NOP;
+EN0263> L<- MD,BUS=0; check for zero length
+EN0264> T<- MD-1,:ECNTOK; [ECNTOK,ECNTZR] start-1
-EN00253> ECNTZR: L<- ESCZER,:EPOST; Zero word count. Abort
+EN0253> ECNTZR: L<- ESCZER,:EPOST; Zero word count. Abort
;Ether Countdown Branch Function - ECBFCT.
;NEXT7 = Interface buffer not empty.
-EN00252> ECNTOK: ECNTR<- L,L<- T,ECBFCT,TASK;
-EN00265> EPNTR<- L,:EODATA; [EODATA,EIDATA]
+EN0252> ECNTOK: ECNTR<- L,L<- T,ECBFCT,TASK;
+EN0265> EPNTR<- L,:EODATA; [EODATA,EIDATA]
;Ethernet Input
;It turns out that starting the receiver for the first time and
;restarting it after ignoring a packet do the same things.
-EN00213> EIREST: :EIFIGN; Hack
+EN0213> EIREST: :EIFIGN; Hack
;Address filtering code.
@@ -316,43 +316,43 @@ EN00213> EIREST: :EIFIGN; Hack
;NEXT7 = IDL % OCMD % ICMD % OUTGONE % INGONE (also known as POST)
;NEXT6 = COLLision - Can't happen during input
-EN00153> EIFRST: MAR<- EHLOC; Get Ethernet address
-EN00266> T<- 377,EBFCT; What's happening?
-EN00267> L<- MD AND T,BUS=0,:EIFOK;[EIFOK,EIFBAD] promiscuous?
+EN0153> EIFRST: MAR<- EHLOC; Get Ethernet address
+EN0266> T<- 377,EBFCT; What's happening?
+EN0267> L<- MD AND T,BUS=0,:EIFOK;[EIFOK,EIFBAD] promiscuous?
-EN00221> EIFOK: MTEMP<- LLCY8,:EIFCHK; [EIFCHK,EIFPRM] Data wakeup
+EN0221> EIFOK: MTEMP<- LLCY8,:EIFCHK; [EIFCHK,EIFPRM] Data wakeup
-EN00225> EIFBAD: ERBFCT,TASK,:EIFB1; [EIFB1] POST wakeup; xCMD FF set?
-EN00151> EIFB1: :EIFB00; [EIFB00,EIFB01,EIFB10,EIFB11]
+EN0225> EIFBAD: ERBFCT,TASK,:EIFB1; [EIFB1] POST wakeup; xCMD FF set?
+EN0151> EIFB1: :EIFB00; [EIFB00,EIFB01,EIFB10,EIFB11]
-EN00200> EIFB00: :EIFIGN; IDL or INGONE, restart rcvr
-EN00204> EIFB01: L<- ESABRT,:EPOST; OCMD, abort
-EN00210> EIFB10: L<- ESABRT,:EPOST; ICMD, abort
-EN00214> EIFB11: L<- ESABRT,:EPOST; ICMD and OCMD, abort
+EN0200> EIFB00: :EIFIGN; IDL or INGONE, restart rcvr
+EN0204> EIFB01: L<- ESABRT,:EPOST; OCMD, abort
+EN0210> EIFB10: L<- ESABRT,:EPOST; ICMD, abort
+EN0214> EIFB11: L<- ESABRT,:EPOST; ICMD and OCMD, abort
-EN00247> EIFPRM: TASK,:EIFBC; Promiscuous. Accept
+EN0247> EIFPRM: TASK,:EIFBC; Promiscuous. Accept
;Ether Look Function - EILFCT. Gate the first word of the
;data buffer to the bus, but do not increment the read pointer.
-EN00246> EIFCHK: L<- T<- 177400,EILFCT; Mask off src addr byte (BUS AND)
-EN00270> L<- MTEMP-T,SH=0; Broadcast?
-EN00271> SH=0,TASK,:EIFNBC; [EIFNBC,EIFBC] Our Address?
+EN0246> EIFCHK: L<- T<- 177400,EILFCT; Mask off src addr byte (BUS AND)
+EN0270> L<- MTEMP-T,SH=0; Broadcast?
+EN0271> SH=0,TASK,:EIFNBC; [EIFNBC,EIFBC] Our Address?
-EN00256> EIFNBC: :EIFIGN; [EIFIGN,EISET]
+EN0256> EIFNBC: :EIFIGN; [EIFIGN,EISET]
-EN00257> EIFBC: :EISET; [EISET] Enter input main loop
+EN0257> EIFBC: :EISET; [EISET] Enter input main loop
;Ether Input Start Function - EISFCT. Start receiver. Interface
;will generate a data wakeup when the first word of the next
;packet arrives, ignoring any packet currently passing.
-EN00254> EIFIGN: SINK<- EPNTR,BUS=0,EPFCT;Reset; Called from output?
-EN00272> EISFCT,TASK,:EOCDWX; [EOCDWX,EIGO] Restart rcvr
+EN0254> EIFIGN: SINK<- EPNTR,BUS=0,EPFCT;Reset; Called from output?
+EN0272> EISFCT,TASK,:EOCDWX; [EOCDWX,EIGO] Restart rcvr
-EN00226> EOCDWX: EWFCT,:EOCDWT; Return to countdown wait loop
+EN0226> EOCDWX: EWFCT,:EOCDWT; Return to countdown wait loop
-EN00255> EISET: MAR<- EICLOC,:ESETUP; Double word reference
+EN0255> EISET: MAR<- EICLOC,:ESETUP; Double word reference
;Input Main Loop
@@ -373,11 +373,11 @@ EN00255> EISET: MAR<- EICLOC,:ESETUP; Double word reference
;xxx1 xxx4 xxx5
;ECBFCT is used to force an unconditional branch on NEXT7
-EN00236> EIDATA: T<- ECNTR-1, BUS=0;
-EN00273> MAR<- L<- EPNTR+1, EBFCT; [EIDMOR,EIDPST] What's happening
-EN00244> EIDMOR: EPNTR<- L, L<- T, ECBFCT; [EIDOK,EIDPST] Guaranteed to branch
-EN00241> EIDOK: MD<- EIDFCT, TASK; [EIDZ4] Read a word from the interface
-EN00234> EIDZ4: ECNTR<- L, :EIDATA;
+EN0236> EIDATA: T<- ECNTR-1, BUS=0;
+EN0273> MAR<- L<- EPNTR+1, EBFCT; [EIDMOR,EIDPST] What's happening
+EN0244> EIDMOR: EPNTR<- L, L<- T, ECBFCT; [EIDOK,EIDPST] Guaranteed to branch
+EN0241> EIDOK: MD<- EIDFCT, TASK; [EIDZ4] Read a word from the interface
+EN0234> EIDZ4: ECNTR<- L, :EIDATA;
; We get to EIDPST for one of two reasons:
; (1) The buffer is full. In this case, an EBFCT (NEXT[7]) is pending.
@@ -386,8 +386,8 @@ EN00234> EIDZ4: ECNTR<- L, :EIDATA;
; (2) Hardware input terminated while the buffer was not full.
; In this case, an unconditional branch on NEXT[7] is pending, so
; we always terminate with "input done".
-EN00245> EIDPST: L<- ESIDON, :EIDFUL; [EIDFUL,EPOST] Presumed to be INGONE
-EN00233> EIDFUL: L<- ESIFUL, :EPOST; Input buffer overrun
+EN0245> EIDPST: L<- ESIDON, :EIDFUL; [EIDFUL,EPOST] Presumed to be INGONE
+EN0233> EIDFUL: L<- ESIFUL, :EPOST; Input buffer overrun
;Ethernet output
@@ -397,37 +397,37 @@ EN00233> EIDFUL: L<- ESIFUL, :EPOST; Input buffer overrun
;generating the countdown. When this is done, the interface is
;again reset, without really doing an output.
-EN00207> EOREST: MAR<- ELLOC; Get load
-EN00274> L<- R37; Use clock as random # gen
-EN00275> EPNTR<- LLSH1; Use bits [2:9]
-EN00276> L<- MD,EOSFCT; L<- current load
-EN00277> SH<0,ECNTR<- L; Overflowed?
-EN00300> MTEMP<- LLSH1,:EOLDOK; [EOLDOK,EOLDBD]
+EN0207> EOREST: MAR<- ELLOC; Get load
+EN0274> L<- R37; Use clock as random # gen
+EN0275> EPNTR<- LLSH1; Use bits [2:9]
+EN0276> L<- MD,EOSFCT; L<- current load
+EN0277> SH<0,ECNTR<- L; Overflowed?
+EN0300> MTEMP<- LLSH1,:EOLDOK; [EOLDOK,EOLDBD]
-EN00243> EOLDBD: L<- ESLOAD,:EPOST; Load overlow
+EN0243> EOLDBD: L<- ESLOAD,:EPOST; Load overlow
-EN00242> EOLDOK: L<- MTEMP+1; Write updated load
-EN00301> MAR<- ELLOC;
-EN00302> MTEMP<- L,TASK;
-EN00303> MD<- MTEMP,:EORST1; New load = (old lshift 1) + 1
+EN0242> EOLDOK: L<- MTEMP+1; Write updated load
+EN0301> MAR<- ELLOC;
+EN0302> MTEMP<- L,TASK;
+EN0303> MD<- MTEMP,:EORST1; New load = (old lshift 1) + 1
-EN00304> EORST1: L<- EPNTR; Continue making random #
-EN00305> EPNTR<- LRSH1;
-EN00306> T<- 377;
-EN00307> L<- EPNTR AND T,TASK;
-EN00310> EPNTR<- L,:EORST2;
+EN0304> EORST1: L<- EPNTR; Continue making random #
+EN0305> EPNTR<- LRSH1;
+EN0306> T<- 377;
+EN0307> L<- EPNTR AND T,TASK;
+EN0310> EPNTR<- L,:EORST2;
;At this point, EPNTR has 0,,random number, ENCTR has old load.
-EN00311> EORST2: MAR<- EICLOC; Has an input buffer been set up?
-EN00312> T<- ECNTR;
-EN00313> L<- EPNTR AND T; L<- Random & Load
-EN00314> SINK<- MD,BUS=0;
-EN00315> ECNTR<- L,SH=0,EPFCT,:EOINPR;[EOINPR,EOINPN]
+EN0311> EORST2: MAR<- EICLOC; Has an input buffer been set up?
+EN0312> T<- ECNTR;
+EN0313> L<- EPNTR AND T; L<- Random & Load
+EN0314> SINK<- MD,BUS=0;
+EN0315> ECNTR<- L,SH=0,EPFCT,:EOINPR;[EOINPR,EOINPN]
-EN00154> EOINPR: EISFCT,:EOCDWT; [EOCDWT,EOCDGO] Enable in under out
+EN0154> EOINPR: EISFCT,:EOCDWT; [EOCDWT,EOCDGO] Enable in under out
-EN00155> EOINPN: :EOCDWT; [EOCDWT,EOCDGO] No input.
+EN0155> EOINPN: :EOCDWT; [EOCDWT,EOCDGO] No input.
;Countdown wait loop. MRT will generate a wakeup every
;37 usec which will decrement ECNTR. When it is zero, start
@@ -438,20 +438,20 @@ EN00155> EOINPN: :EOCDWT; [EOCDWT,EOCDGO] No input.
;Wakeup is cleared when Ether task next runs. EWFCT must be
;issued in the instruction AFTER a task.
-EN00250> EOCDWT: L<- 177400,EBFCT; What's happening?
-EN00316> EPNTR<- L,ECBFCT,:EOCDW0;[EOCDW0,EOCDRS] Packet coming in?
-EN00231> EOCDW0: L<- ECNTR-1,BUS=0,TASK,:EOCDW1; [EOCDW1,EIGO]
-EN00223> EOCDW1: ECNTR<- L,EWFCT,:EOCDWT; [EOCDWT,EOCDGO]
+EN0250> EOCDWT: L<- 177400,EBFCT; What's happening?
+EN0316> EPNTR<- L,ECBFCT,:EOCDW;[EOCDW,EOCDRS] Packet coming in?
+EN0231> EOCDW: L<- ECNTR-1,BUS=0,TASK,:EOCDW1; [EOCDW1,EIGO]
+EN0223> EOCDW1: ECNTR<- L,EWFCT,:EOCDWT; [EOCDWT,EOCDGO]
-EN00235> EOCDRS: L<- ESABRT,:EPOST; [EPOST] POST event
+EN0235> EOCDRS: L<- ESABRT,:EPOST; [EPOST] POST event
-EN0227> EIGO: :EIFRST; [EIFRST] Input under output
+EN227> EIGO: :EIFRST; [EIFRST] Input under output
;Output main loop setup
-EN00251> EOCDGO: MAR<- EOCLOC; Double word reference
-EN00317> EPFCT; Reset interface
-EN00320> EOSFCT,:ESETUP; Start Transmitter
+EN0251> EOCDGO: MAR<- EOCLOC; Double word reference
+EN0317> EPFCT; Reset interface
+EN0320> EOSFCT,:ESETUP; Start Transmitter
;Ether Output Start Function - EOSFCT. The interface will generate
;a burst of data requests until the interface buffer is full or the
@@ -464,40 +464,40 @@ EN00320> EOSFCT,:ESETUP; Start Transmitter
;Output main loop
-EN00232> EODATA: L<- MAR<- EPNTR+1,EBFCT; What's happening?
-EN00321> T<- ECNTR-1,BUS=0,:EODOK; [EODOK,EODPST,EODCOL,EODUGH]
-EN00201> EODOK: EPNTR<- L,L<- T,:EODMOR; [EODMOR,EODEND]
-EN00156> EODMOR: ECNTR<- L,TASK;
-EN00322> EODFCT<- MD,:EODATA; Output word to transmitter
+EN0232> EODATA: L<- MAR<- EPNTR+1,EBFCT; What's happening?
+EN0321> T<- ECNTR-1,BUS=0,:EODOK; [EODOK,EODPST,EODCOL,EODUGH]
+EN0201> EODOK: EPNTR<- L,L<- T,:EODMOR; [EODMOR,EODEND]
+EN0156> EODMOR: ECNTR<- L,TASK;
+EN0322> EODFCT<- MD,:EODATA; Output word to transmitter
-EN00205> EODPST: L<- ESABRT,:EPOST; [EPOST] POST event
+EN0205> EODPST: L<- ESABRT,:EPOST; [EPOST] POST event
-EN00211> EODCOL: EPFCT,:EOREST; [EOREST] Collision
+EN0211> EODCOL: EPFCT,:EOREST; [EOREST] Collision
-EN00215> EODUGH: L<- ESABRT,:EPOST; [EPOST] POST + Collision
+EN0215> EODUGH: L<- ESABRT,:EPOST; [EPOST] POST + Collision
;Ether EOT Function - EEFCT. Stop generating output data wakeups,
;the interface has all of the packet. When the data buffer runs
;dry, the interface will append the CRC and then generate an
;OUTGONE post wakeup.
-EN00157> EODEND: EEFCT; Disable data wakeups
-EN00323> TASK; Wait for EEFCT to take
-EN00324> :EOEOT; Wait for Outgone
+EN0157> EODEND: EEFCT; Disable data wakeups
+EN0323> TASK; Wait for EEFCT to take
+EN0324> :EOEOT; Wait for Outgone
;Output completion. We are waiting for the interface buffer to
;empty, and the interface to generate an OUTGONE Post wakeup.
-EN00325> EOEOT: EBFCT; What's happening?
-EN00326> :EOEOK; [EOEOK,EOEPST,EOECOL,EOEUGH]
+EN0325> EOEOT: EBFCT; What's happening?
+EN0326> :EOEOK; [EOEOK,EOEPST,EOECOL,EOEUGH]
-EN00202> EOEOK: L<- ESNEVR,:EPOST; Runaway Transmitter. Never Never.
+EN0202> EOEOK: L<- ESNEVR,:EPOST; Runaway Transmitter. Never Never.
-EN00206> EOEPST: L<- ESODON,:EPOST; POST event. Output done
+EN0206> EOEPST: L<- ESODON,:EPOST; POST event. Output done
-EN00212> EOECOL: EPFCT,:EOREST; Collision
+EN0212> EOECOL: EPFCT,:EOREST; Collision
-EN00216> EOEUGH: L<- ESABRT,:EPOST; POST + Collision
+EN0216> EOEUGH: L<- ESABRT,:EPOST; POST + Collision
;Memory Refresh Task,
@@ -532,48 +532,48 @@ $REFIIMSK $7777;
#AltoIIMRT.mu;
-MR00355> CLOCK: MAR<- CLOCKLOC; R37 OVERFLOWED.
-MR00412> NOP;
-MR00413> L<- MD+1; INCREMENT CLOCK IM MEMORY
-MR00414> MAR<- CLOCKLOC;
-MR00415> MTEMP<- L, TASK;
-MR00416> MD<- MTEMP, :NOCLK;
+MR0355> CLOCK: MAR<- CLOCKLOC; R37 OVERFLOWED.
+MR0412> NOP;
+MR0413> L<- MD+1; INCREMENT CLOCK IM MEMORY
+MR0414> MAR<- CLOCKLOC;
+MR0415> MTEMP<- L, TASK;
+MR0416> MD<- MTEMP, :NOCLK;
-MR00334> DOCUR: L<- T<- YPOS; CHECK FOR VISIBLE CURSOR ON THIS SCAN
-MR00417> SH<0, L<- 20-T-1; ***x13 change: the constant 20 was 17
-MR00420> SH<0, L<- 2+T, :SHOWC; [SHOWC,WAITC]
+MR0334> DOCUR: L<- T<- YPOS; CHECK FOR VISIBLE CURSOR ON THIS SCAN
+MR0417> SH<0, L<- 20-T-1; ***x13 change: the constant 20 was 17
+MR0420> SH<0, L<- 2+T, :SHOWC; [SHOWC,WAITC]
-MR00337> WAITC: YPOS<- L, L<- 0, TASK, :MRTLAST; SQUASHES PENDING BRANCH
-MR00336> SHOWC: MAR<- CLOCKLOC+T+1, :CNOTLAST;
+MR0337> WAITC: YPOS<- L, L<- 0, TASK, :MRTLAST; SQUASHES PENDING BRANCH
+MR0336> SHOWC: MAR<- CLOCKLOC+T+1, :CNOTLAST;
-MR00356> CNOTLAST: T<- CURX, :CURF;
-MR00357> CLAST: T<- 0;
-MR00421> CURF: YPOS<- L, L<- T;
-MR00422> CURX< L;
-MR00423> L<- MD, TASK;
-MR00424> CURDATA<- L, :MRT;
+MR0356> CNOTLAST: T<- CURX, :CURF;
+MR0357> CLAST: T<- 0;
+MR0421> CURF: YPOS<- L, L<- T;
+MR0422> CURX< L;
+MR0423> L<- MD, TASK;
+MR0424> CURDATA<- L, :MRT;
;AFTER THIS DISPATCH, T WILL CONTAIN XCHANGE, L WILL CONTAIN YCHANGE-1
-MR00346> TX1: L<- T<- ONE +T, :M00; Y=0, X=1
-MR00343> TX2: L<- T<- ALLONES, :M00; Y=0, X=-1
-MR00342> TX3: L<- T<- 0, :M00; Y=1, X=0
-MR00350> TX4: L<- T<- ONE AND T, :M00; Y=1, X=1
-MR00345> TX5: L<- T<- ALLONES XOR T, :M00; Y=1, X=-1
-MR00341> TX6: T<- 0, :M00; Y=-1, X=0
-MR00347> TX7: T<- ONE, :M00; Y=-1, X=1
-MR00344> TX8: T<- ALLONES, :M00; Y=-1, X=-1
+MR0346> TX1: L<- T<- ONE +T, :M00; Y=0, X=1
+MR0343> TX2: L<- T<- ALLONES, :M00; Y=0, X=-1
+MR0342> TX3: L<- T<- 0, :M00; Y=1, X=0
+MR0350> TX4: L<- T<- ONE AND T, :M00; Y=1, X=1
+MR0345> TX5: L<- T<- ALLONES XOR T, :M00; Y=1, X=-1
+MR0341> TX6: T<- 0, :M00; Y=-1, X=0
+MR0347> TX7: T<- ONE, :M00; Y=-1, X=1
+MR0344> TX8: T<- ALLONES, :M00; Y=-1, X=-1
-MR00425> M00: MAR<- MOUSELOC; START THE FETCH OF THE COORDINATES
-MR00426> MTEMP<- L; YCHANGE -1
-MR00427> L<- MD+ T; X+ XCHANGE
-MR00430> T<- MD; Y
-MR00431> T<- MTEMP+ T+1; Y+ (YCHANGE-1) + 1
-MR00432> MTEMP<- L, L<- T;
-MR00433> MAR<- MOUSELOC; NOW RESTORE THE UPDATED COORDINATES
-MR00434> CLOCKTEMP<- L;
-MR00435> MD<- MTEMP, TASK;
-MR00436> MD<- CLOCKTEMP, :MRTA;
+MR0425> M00: MAR<- MOUSELOC; START THE FETCH OF THE COORDINATES
+MR0426> MTEMP<- L; YCHANGE -1
+MR0427> L<- MD+ T; X+ XCHANGE
+MR0430> T<- MD; Y
+MR0431> T<- MTEMP+ T+1; Y+ (YCHANGE-1) + 1
+MR0432> MTEMP<- L, L<- T;
+MR0433> MAR<- MOUSELOC; NOW RESTORE THE UPDATED COORDINATES
+MR0434> CLOCKTEMP<- L;
+MR0435> MD<- MTEMP, TASK;
+MR0436> MD<- CLOCKTEMP, :MRTA;
;CURSOR TASK
@@ -582,8 +582,8 @@ MR00436> MD<- CLOCKTEMP, :MRTA;
$XPREG $L026010,000000,124000; F2 = 10
$CSR $L026011,000000,124000; F2 = 11
-CU00012> CURT: XPREG<- CURX, TASK;
-CU00437> CSR<- CURDATA, :CURT;
+CU0012> CURT: XPREG<- CURX, TASK;
+CU0437> CSR<- CURDATA, :CURT;
;PREDEFINITION FOR PARITY TASK.
@@ -602,66 +602,66 @@ $PC $R6; USED BY MEMORY INIT
!1,2,EReadDone,EContRead; ***X21 addition.
!1,2,EtherBoot,DiskBoot; ***X21 addition.
-EM00000> NOVEM: IR<-L<-MAR<-0, :INXB,SAD<- L; LOAD SAD TO ZERO THE BUS. STORE PC AT 0
-EM00460> Q0: L<- ONE, :INXA; EXECUTED TWICE
-EM00461> Q1: L<- TOTUWC, :INXA;
-EM00462> Q2: L<-402, :INXA; FIRST READ HEADER INTO 402, THEN
-EM00463> Q3: L<- 402, :INXA; STORE LABEL AT 402
-EM00464> Q4: L<- ONE, :INXA; STORE DATA PAGE STARTING AT 1
-EM00465> Q5: L<-377+1, :INXE; Store Ethernet Input Buffer Length ***X21.
-EM00466> Q6: L<-ONE, :INXE; Store Ethernet Input Buffer Pointer ***X21.
-EM00467> Q7: MAR<- DASTART; CLEAR THE DISPLAY POINTER
-EM00441> L<- 0;
-EM00451> R37<- L;
-EM00472> MD<- 0;
-EM00473> MAR<- 177034; FETCH KEYBOARD
-EM00474> L<- 100000;
-EM00475> NWW<- L, T<- 0-1;
-EM00476> L<- MD XOR T, BUSODD; *** X21 change.
-EM00477> MAR<- BDAD, :EtherBoot; [EtherBoot, DiskBoot] *** X21 change.
+EM0000> NOVEM: IR<-L<-MAR<-0, :INXB,SAD<- L; LOAD SAD TO ZERO THE BUS. STORE PC AT 0
+EM0460> Q0: L<- ONE, :INXA; EXECUTED TWICE
+EM0461> Q1: L<- TOTUWC, :INXA;
+EM0462> Q2: L<-402, :INXA; FIRST READ HEADER INTO 402, THEN
+EM0463> Q3: L<- 402, :INXA; STORE LABEL AT 402
+EM0464> Q4: L<- ONE, :INXA; STORE DATA PAGE STARTING AT 1
+EM0465> Q5: L<-377+1, :INXE; Store Ethernet Input Buffer Length ***X21.
+EM0466> Q6: L<-ONE, :INXE; Store Ethernet Input Buffer Pointer ***X21.
+EM0467> Q7: MAR<- DASTART; CLEAR THE DISPLAY POINTER
+EM0441> L<- 0;
+EM0451> R37<- L;
+EM0472> MD<- 0;
+EM0473> MAR<- 177034; FETCH KEYBOARD
+EM0474> L<- 100000;
+EM0475> NWW<- L, T<- 0-1;
+EM0476> L<- MD XOR T, BUSODD; *** X21 change.
+EM0477> MAR<- BDAD, :EtherBoot; [EtherBoot, DiskBoot] *** X21 change.
; BOOT DISK ADDRESS GOES IN LOCATION 12
-EM00471> DiskBoot: SAD<- L, L<- 0+1;
-EM00500> MD<- SAD;
-EM00501> MAR<- KBLKADR, :FINSTO;
+EM0471> DiskBoot: SAD<- L, L<- 0+1;
+EM0500> MD<- SAD;
+EM0501> MAR<- KBLKADR, :FINSTO;
; Ethernet boot section added in X21.
$NegBreathM1 $177175;
$EthNovaGo $3; First data location of incoming packet
-EM00470> EtherBoot: L<-EthNovaGo, :EReRead; [EReRead, FINJMP]
+EM0470> EtherBoot: L<-EthNovaGo, :EReRead; [EReRead, FINJMP]
-EM00454> EReRead:MAR<- EHLOC; Set the host address to 377 for breath packets
-EM00502> TASK;
-EM00503> MD<- 377;
+EM0454> EReRead:MAR<- EHLOC; Set the host address to 377 for breath packets
+EM0502> TASK;
+EM0503> MD<- 377;
-EM00504> MAR<- EPLOC; Zero the status word and start 'er up
-EM00505> SINK<- 2, STARTF;
-EM00506> MD <- 0;
+EM0504> MAR<- EPLOC; Zero the status word and start 'er up
+EM0505> SINK<- 2, STARTF;
+EM0506> MD <- 0;
-EM00457> EContRead: MAR<- EPLOC; See if status is still 0
-EM00507> T<- 377; Status for correct read
-EM00510> L<- MD XOR T, TASK, BUS=0;
-EM00511> SAD<- L, :EReadDone; [EReadDone, EContRead]
+EM0457> EContRead: MAR<- EPLOC; See if status is still 0
+EM0507> T<- 377; Status for correct read
+EM0510> L<- MD XOR T, TASK, BUS=0;
+EM0511> SAD<- L, :EReadDone; [EReadDone, EContRead]
-EM00456> EReadDone: MAR<- 2; Check the packet type
-EM00512> T<- NegBreathM1; -(Breath-of-life)-1
-EM00513> T<-MD+T+1;
-EM00514> L<-SAD OR T;
-EM00515> SH=0, :EtherBoot;
+EM0456> EReadDone: MAR<- 2; Check the packet type
+EM0512> T<- NegBreathM1; -(Breath-of-life)-1
+EM0513> T<-MD+T+1;
+EM0514> L<-SAD OR T;
+EM0515> SH=0, :EtherBoot;
; SUBROUTINE USED BY INITIALIZATION TO SET UP BLOCKS OF MEMORY
$EIOffset $576;
-EM00516> INXA: T<-ONE, :INXCom; ***X21 change.
-EM00517> INXE: T<-EIOffset, :INXCom; ***X21 addition.
+EM0516> INXA: T<-ONE, :INXCom; ***X21 change.
+EM0517> INXE: T<-EIOffset, :INXCom; ***X21 addition.
-EM00520> INXCom: MAR<-T<-IR<- SAD+T; *** X21 addition.
-EM00521> PC<- L, L<- 0+T+1; *** X21 change.
-EM00522> INXB: SAD<- L; **NB (JDersch 9/14 -- this is actually MD<-PC !)
-EM00523> SINK<- DISP, BUS,TASK;
-EM00524> SAD<- L, :Q0;
+EM0520> INXCom: MAR<-T<-IR<- SAD+T; *** X21 addition.
+EM0521> PC<- L, L<- 0+T+1; *** X21 change.
+EM0522> INXB: SAD<- L; **NB (JDersch 9/14 -- this is actually MD<-PC !)
+EM0523> SINK<- DISP, BUS,TASK;
+EM0524> SAD<- L, :Q0;
;REGISTERS USED BY NOVA EMULATOR
@@ -691,138 +691,138 @@ $XREG $R7;
; ALL INSTRUCTIONS RETURN TO START WHEN DONE
-EM00020> START: T<- MAR<-PC+SKIP;
-EM00525> START1: L<- NWW, BUS=0; BUS# 0 MEANS DISABLED OR SOMETHING TO DO
-EM00576> :MAYBE, SH<0, L<- 0+T+1; SH<0 MEANS DISABLED
-EM00526> MAYBE: PC<- L, L<- T, :DOINT;
-EM00527> NOINT: PC<- L, :DIS0;
+EM0020> START: T<- MAR<-PC+SKIP;
+EM0525> START1: L<- NWW, BUS=0; BUS# 0 MEANS DISABLED OR SOMETHING TO DO
+EM0576> :MAYBE, SH<0, L<- 0+T+1; SH<0 MEANS DISABLED
+EM0526> MAYBE: PC<- L, L<- T, :DOINT;
+EM0527> NOINT: PC<- L, :DIS0;
-EM00534> DOINT: MAR<- WWLOC, :INTCODE; TRY TO CAUSE AN INTERRUPT
+EM0534> DOINT: MAR<- WWLOC, :INTCODE; TRY TO CAUSE AN INTERRUPT
;DISPATCH ON FUNCTION FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON INDIRECT BIT AND INDEX FIELD
-EM00535> DIS0: L<- T<- IR<- MD; SKIP CLEARED HERE
+EM0535> DIS0: L<- T<- IR<- MD; SKIP CLEARED HERE
;DISPATCH ON SHIFT FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON THE INDIRECT BIT OR IR[3-7]
-EM00612> DIS1: T<- ACSOURCE, :GETAD;
+EM0612> DIS1: T<- ACSOURCE, :GETAD;
;GETAD MUST BE 0 MOD 20
-EM00540> GETAD: T<- 0, :DOINS; PAGE 0
-EM00541> G1: T<- PC -1, :DOINS; RELATIVE
-EM00542> G2: T<- AC2, :DOINS; AC2 RELATIVE
-EM00543> G3: T<- AC3, :DOINS; AC3 RELATIVE
-EM00544> G4: T<- 0, :DOINS; PAGE 0 INDIRECT
-EM00545> G5: T<- PC -1, :DOINS; RELATIVE INDIRECT
-EM00546> G6: T<- AC2, :DOINS; AC2 RELATIVE INDIRECT
-EM00547> G7: T<- AC3, :DOINS; AC3 RELATIVE INDIRECT
-EM00550> G10: L<- 0-T-1, TASK, :SHIFT; COMPLEMENT
-EM00551> G11: L<- 0-T, TASK, :SHIFT; NEGATE
-EM00552> G12: L<- 0+T, TASK, :SHIFT; MOVE
-EM00553> G13: L<- 0+T+1, TASK, :SHIFT; INCREMENT
-EM00554> G14: L<- ACDEST-T-1, TASK, :SHIFT; ADD COMPLEMENT
-EM00555> G15: L<- ACDEST-T, TASK, :SHIFT; SUBTRACT
-EM00556> G16: L<- ACDEST+T, TASK, :SHIFT; ADD
-EM00557> G17: L<- ACDEST AND T, TASK, :SHIFT;
+EM0540> GETAD: T<- 0, :DOINS; PAGE 0
+EM0541> G1: T<- PC -1, :DOINS; RELATIVE
+EM0542> G2: T<- AC2, :DOINS; AC2 RELATIVE
+EM0543> G3: T<- AC3, :DOINS; AC3 RELATIVE
+EM0544> G4: T<- 0, :DOINS; PAGE 0 INDIRECT
+EM0545> G5: T<- PC -1, :DOINS; RELATIVE INDIRECT
+EM0546> G6: T<- AC2, :DOINS; AC2 RELATIVE INDIRECT
+EM0547> G7: T<- AC3, :DOINS; AC3 RELATIVE INDIRECT
+EM0550> G10: L<- 0-T-1, TASK, :SHIFT; COMPLEMENT
+EM0551> G11: L<- 0-T, TASK, :SHIFT; NEGATE
+EM0552> G12: L<- 0+T, TASK, :SHIFT; MOVE
+EM0553> G13: L<- 0+T+1, TASK, :SHIFT; INCREMENT
+EM0554> G14: L<- ACDEST-T-1, TASK, :SHIFT; ADD COMPLEMENT
+EM0555> G15: L<- ACDEST-T, TASK, :SHIFT; SUBTRACT
+EM0556> G16: L<- ACDEST+T, TASK, :SHIFT; ADD
+EM0557> G17: L<- ACDEST AND T, TASK, :SHIFT;
-EM00530> SHIFT: DNS<- L LCY 8, :START; SWAP BYTES
-EM00531> SH1: DNS<- L RSH 1, :START; RIGHT 1
-EM00532> SH2: DNS<- L LSH 1, :START; LEFT 1
-EM00533> SH3: DNS<- L, :START; NO SHIFT
+EM0530> SHIFT: DNS<- L LCY 8, :START; SWAP BYTES
+EM0531> SH1: DNS<- L RSH 1, :START; RIGHT 1
+EM0532> SH2: DNS<- L LSH 1, :START; LEFT 1
+EM0533> SH3: DNS<- L, :START; NO SHIFT
-EM00060> DOINS: L<- DISP + T, TASK, :SAVAD, IDISP; DIRECT INSTRUCTIONS
-EM00061> DOIND: L<- MAR<- DISP+T; INDIRECT INSTRUCTIONS
-EM00613> XREG<- L;
-EM00614> L<- MD, TASK, IDISP, :SAVAD;
+EM0060> DOINS: L<- DISP + T, TASK, :SAVAD, IDISP; DIRECT INSTRUCTIONS
+EM0061> DOIND: L<- MAR<- DISP+T; INDIRECT INSTRUCTIONS
+EM0613> XREG<- L;
+EM0614> L<- MD, TASK, IDISP, :SAVAD;
-EM00102> BRI: L<- MAR<- PCLOC ;INTERRUPT RETURN BRANCH
-EM00615> BRI0: T<- 77777;
-EM00616> L<- NWW AND T, SH < 0;
-EM00617> NWW<- L, :EIR0; BOTH EIR AND BRI MUST CHECK FOR INTERRUPT
+EM0102> BRI: L<- MAR<- PCLOC ;INTERRUPT RETURN BRANCH
+EM0615> BRI0: T<- 77777;
+EM0616> L<- NWW AND T, SH < 0;
+EM0617> NWW<- L, :EIR0; BOTH EIR AND BRI MUST CHECK FOR INTERRUPT
; REQUESTS WHICH MAY HAVE COME IN WHILE
; INTERRUPTS WERE OFF
-EM00572> EIR0: L<- MD, :DOINT;
-EM00573> EIR1: L<- PC, :DOINT;
+EM0572> EIR0: L<- MD, :DOINT;
+EM0573> EIR1: L<- PC, :DOINT;
;***X21 addition
; DIRS - 61013 - Disable Interrupts and Skip if they were On
-EM00113> DIRS: T<-100000;
-EM00620> L<-NWW AND T;
-EM00621> L<-PC+1, SH=0;
+EM0113> DIRS: T<-100000;
+EM0620> L<-NWW AND T;
+EM0621> L<-PC+1, SH=0;
; DIR - 61000 - Disable Interrupts
-EM00100> DIR: T<- 100000, :INTSOFF;
-EM00574> INTSOFF: L<- NWW OR T, TASK, :INTZ;
+EM0100> DIR: T<- 100000, :INTSOFF;
+EM0574> INTSOFF: L<- NWW OR T, TASK, :INTZ;
-EM00575> INTSON: PC<-L, :INTSOFF;
+EM0575> INTSON: PC<-L, :INTSOFF;
;EIR - 61001 - Enable Interrupts
-EM00101> EIR: L<- 100000, :BRI0;
+EM0101> EIR: L<- 100000, :BRI0;
;SIT - 61007 - Start Interval Timer
-EM00107> SIT: T<- AC0;
-EM00622> L<- R37 OR T, TASK;
-EM00623> R37<- L, :START;
+EM0107> SIT: T<- AC0;
+EM0622> L<- R37 OR T, TASK;
+EM0623> R37<- L, :START;
-EM00624> FINJSR: L<- PC;
-EM00625> AC3<- L, L<- T, TASK;
-EM00455> FINJMP: PC<- L, :START;
-EM00626> SAVAD: SAD<- L, :XCTAB;
+EM0624> FINJSR: L<- PC;
+EM0625> AC3<- L, L<- T, TASK;
+EM0455> FINJMP: PC<- L, :START;
+EM0626> SAVAD: SAD<- L, :XCTAB;
;JSRII - 64400 - JSR double indirect, PC relative. Must have X=1 in opcode
;JSRIS - 65000 - JSR double indirect, AC2 relative. Must have X=2 in opcode
-EM00064> JSRII: MAR<- DISP+T; FIRST LEVEL
-EM00627> IR<- JSRCX;
-EM00630> T<- MD, :DOIND; THE IR<- INSTRUCTION WILL NOT BRANCH
+EM0064> JSRII: MAR<- DISP+T; FIRST LEVEL
+EM0627> IR<- JSRCX;
+EM0630> T<- MD, :DOIND; THE IR<- INSTRUCTION WILL NOT BRANCH
;TRAP ON UNIMPLEMENTED OPCODES. SAVES PC AT
;TRAPPC, AND DOES A JMP@ TRAPVEC ! OPCODE.
-EM00077> TRAP: XREG<- L LCY 8; THE INSTRUCTION
-EM00037> TRAP1: MAR<- TRAPPC;***X13 CHANGE: TAG 'TRAP1' ADDED
-EM00631> IR<- T<- 37;
-EM00632> MD<- PC;
-EM00633> T<- XREG.T;
-EM00634> T<- TRAPCON+T+1, :DOIND; T NOW CONTAINS 471+OPCODE
+EM0077> TRAP: XREG<- L LCY 8; THE INSTRUCTION
+EM0037> TRAP1: MAR<- TRAPPC;***X13 CHANGE: TAG 'TRAP1' ADDED
+EM0631> IR<- T<- 37;
+EM0632> MD<- PC;
+EM0633> T<- XREG.T;
+EM0634> T<- TRAPCON+T+1, :DOIND; T NOW CONTAINS 471+OPCODE
; THIS WILL DO JMP@ 530+OPCODE
;***X21 CHANGE: ADDED TAG RAMTRAP
-EM00076> RAMTRAP: SWMODE, :TRAP;
+EM0076> RAMTRAP: SWMODE, :TRAP;
; Parameterless operations come here for dispatch.
!1,2,NPNOTRAP,NPTRAP;
-EM00063> NOPAR: XREG<-L LCY 8; ***X21 change. Checks < 27.
-EM00635> T<-27; ***IIX3. Greatest defined op is 26.
-EM00640> L<-DISP-T;
-EM00641> ALUCY;
-EM00642> SINK<-DISP, SINK<-X37, BUS, TASK, :NPNOTRAP;
+EM0063> NOPAR: XREG<-L LCY 8; ***X21 change. Checks < 27.
+EM0635> T<-27; ***IIX3. Greatest defined op is 26.
+EM0640> L<-DISP-T;
+EM0641> ALUCY;
+EM0642> SINK<-DISP, SINK<-X37, BUS, TASK, :NPNOTRAP;
-EM00636> NPNOTRAP: :DIR;
+EM0636> NPNOTRAP: :DIR;
-EM00637> NPTRAP: :TRAP1;
+EM0637> NPTRAP: :TRAP1;
;***X21 addition for debugging w/ expanded DISP Prom
-EM00065> U5: :RAMTRAP;
-EM00066> U6: :RAMTRAP;
-EM00067> U7: :RAMTRAP;
+EM0065> U5: :RAMTRAP;
+EM0066> U6: :RAMTRAP;
+EM0067> U7: :RAMTRAP;
;MAIN INSTRUCTION TABLE. GET HERE:
; (1) AFTER AN INDIRECTION
; (2) ON DIRECT INSTRUCTIONS
-EM00560> XCTAB: L<- SAD, TASK, :FINJMP; JMP
-EM00561> XJSR: T<- SAD, :FINJSR; JSR
-EM00562> XISZ: MAR<- SAD, :ISZ1; ISZ
-EM00563> XDSZ: MAR<- SAD, :DSZ1; DSZ
-EM00564> XLDA: MAR<- SAD, :FINLOAD; LDA 0-3
-EM00565> XSTA: MAR<- SAD; /*NORMAL
-EM00643> XSTA1: L<- ACDEST, :FINSTO; /*NORMAL
+EM0560> XCTAB: L<- SAD, TASK, :FINJMP; JMP
+EM0561> XJSR: T<- SAD, :FINJSR; JSR
+EM0562> XISZ: MAR<- SAD, :ISZ1; ISZ
+EM0563> XDSZ: MAR<- SAD, :DSZ1; DSZ
+EM0564> XLDA: MAR<- SAD, :FINLOAD; LDA 0-3
+EM0565> XSTA: MAR<- SAD; /*NORMAL
+EM0643> XSTA1: L<- ACDEST, :FINSTO; /*NORMAL
; BOUNDS-CHECKING VERSION OF STORE
; SUBST ";**" TO ";**" TO ENABLE THIS CODE:
@@ -841,23 +841,23 @@ EM00643> XSTA1: L<- ACDEST, :FINSTO; /*NORMAL
;** L<- ACDEST, :FINSTO;
;**
-EM00644> DSZ1: T<- ALLONES, :FINISZ;
-EM00645> ISZ1: T<- ONE, :FINISZ;
+EM0644> DSZ1: T<- ALLONES, :FINISZ;
+EM0645> ISZ1: T<- ONE, :FINISZ;
-EM00452> FINSTO: SAD<- L,TASK;
-EM00646> FINST1: MD<-SAD, :START;
+EM0452> FINSTO: SAD<- L,TASK;
+EM0646> FINST1: MD<-SAD, :START;
-EM00647> FINLOAD: NOP;
-EM00650> LOADX: L<- MD, TASK;
-EM00651> LOADD: ACDEST<- L, :START;
+EM0647> FINLOAD: NOP;
+EM0650> LOADX: L<- MD, TASK;
+EM0651> LOADD: ACDEST<- L, :START;
-EM00652> FINISZ: L<- MD+T;
-EM00653> MAR<- SAD, SH=0;
-EM00654> SAD<- L, :FINSTO;
+EM0652> FINISZ: L<- MD+T;
+EM0653> MAR<- SAD, SH=0;
+EM0654> SAD<- L, :FINSTO;
-EM00453> INCPC: MD<- SAD;
-EM00655> L<- PC+1, TASK;
-EM00656> PC<- L, :START;
+EM0453> INCPC: MD<- SAD;
+EM0655> L<- PC+1, TASK;
+EM0656> PC<- L, :START;
;DIVIDE. THIS DIVIDE IS IDENTICAL TO THE NOVA DIVIDE EXCEPT THAT
;IF THE DIVIDE CANNOT BE DONE, THE INSTRUCTION FAILS TO SKIP, OTHERWISE
@@ -869,38 +869,38 @@ EM00656> PC<- L, :START;
!1,2,DX0,DX1;
!1,2,NOSUB,DOSUB;
-EM00121> DIV: T<- AC2;
-EM00657> DIVX: L<- AC0 - T; DO THE DIVIDE ONLY IF AC2>AC0
-EM00672> ALUCY, TASK, SAD<- L, L<- 0+1;
-EM00673> :DODIV, SAD<- L LSH 1; SAD<- 2. COUNT THE LOOP BY SHIFTING
+EM0121> DIV: T<- AC2;
+EM0657> DIVX: L<- AC0 - T; DO THE DIVIDE ONLY IF AC2>AC0
+EM0672> ALUCY, TASK, SAD<- L, L<- 0+1;
+EM0673> :DODIV, SAD<- L LSH 1; SAD<- 2. COUNT THE LOOP BY SHIFTING
-EM00661> NODIV: :FINBLT; ***X21 change.
-EM00660> DODIV: L<- AC0, :DIV1;
+EM0661> NODIV: :FINBLT; ***X21 change.
+EM0660> DODIV: L<- AC0, :DIV1;
-EM00662> DIVL: L<- AC0;
-EM00674> DIV1: SH<0, T<- AC1; WILL THE LEFT SHIFT OF THE DIVIDEND OVERFLOW?
-EM00675> :NOOVF, AC0<- L MLSH 1, L<- T<- 0+T; L<- AC1, T<- 0
+EM0662> DIVL: L<- AC0;
+EM0674> DIV1: SH<0, T<- AC1; WILL THE LEFT SHIFT OF THE DIVIDEND OVERFLOW?
+EM0675> :NOOVF, AC0<- L MLSH 1, L<- T<- 0+T; L<- AC1, T<- 0
-EM00665> OVF: AC1<- L LSH 1, L<- 0+INCT, :NOV1; L<- 1. SHIFT OVERFLOWED
-EM00664> NOOVF: AC1<- L LSH 1 , L<- T; L<- 0. SHIFT OK
+EM0665> OVF: AC1<- L LSH 1, L<- 0+INCT, :NOV1; L<- 1. SHIFT OVERFLOWED
+EM0664> NOOVF: AC1<- L LSH 1 , L<- T; L<- 0. SHIFT OK
-EM00676> NOV1: T<- AC2, SH=0;
-EM00677> L<- AC0-T, :DX0;
+EM0676> NOV1: T<- AC2, SH=0;
+EM0677> L<- AC0-T, :DX0;
-EM00667> DX1: ALUCY; DO THE TEST ONLY IF THE SHIFT DIDN'T OVERFLOW. IF
+EM0667> DX1: ALUCY; DO THE TEST ONLY IF THE SHIFT DIDN'T OVERFLOW. IF
; IT DID, L IS STILL CORRECT, BUT THE TEST WOULD GO
; THE WRONG WAY.
-EM00700> :NOSUB, T<- AC1;
+EM0700> :NOSUB, T<- AC1;
-EM00666> DX0: :DOSUB, T<- AC1;
+EM0666> DX0: :DOSUB, T<- AC1;
-EM00671> DOSUB: AC0<- L, L<- 0+INCT; DO THE SUBTRACT
-EM00701> AC1<- L; AND PUT A 1 IN THE QUOTIENT
+EM0671> DOSUB: AC0<- L, L<- 0+INCT; DO THE SUBTRACT
+EM0701> AC1<- L; AND PUT A 1 IN THE QUOTIENT
-EM00670> NOSUB: L<- SAD, BUS=0, TASK;
-EM00702> SAD<- L LSH 1, :DIVL;
+EM0670> NOSUB: L<- SAD, BUS=0, TASK;
+EM0702> SAD<- L LSH 1, :DIVL;
-EM00663> ENDDIV: L<- PC+1, TASK, :DOIT; ***X21 change. Skip if divide was done.
+EM0663> ENDDIV: L<- PC+1, TASK, :DOIT; ***X21 change. Skip if divide was done.
;MULTIPLY. THIS IS AN EXACT EMULATION OF NOVA HARDWARE MULTIPLY.
@@ -916,36 +916,36 @@ EM00663> ENDDIV: L<- PC+1, TASK, :DOIT; ***X21 change. Skip if divide was done.
!1,2,NOSPILLX,SPILLX;
-EM00120> MUL: L<- AC2-1, BUS=0;
-EM00703> MPYX: XREG<-L,L<- 0, :DOMUL; GET HERE WITH AC2-1 IN L. DON'T MUL IF AC2=0
-EM00704> DOMUL: TASK, L<- -10+1;
-EM00720> SAD<- L; COUNT THE LOOP IN SAD
+EM0120> MUL: L<- AC2-1, BUS=0;
+EM0703> MPYX: XREG<-L,L<- 0, :DOMUL; GET HERE WITH AC2-1 IN L. DON'T MUL IF AC2=0
+EM0704> DOMUL: TASK, L<- -10+1;
+EM0720> SAD<- L; COUNT THE LOOP IN SAD
-EM00706> MPYL: L<- AC1, BUSODD;
-EM00721> T<- AC0, :NOADDIER;
+EM0706> MPYL: L<- AC1, BUSODD;
+EM0721> T<- AC0, :NOADDIER;
-EM00710> NOADDIER: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILL;
-EM00711> ADDIER: L<- T<- XREG+INCT;
-EM00722> L<- AC1, ALUCY, :NOADDIER;
+EM0710> NOADDIER: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILL;
+EM0711> ADDIER: L<- T<- XREG+INCT;
+EM0722> L<- AC1, ALUCY, :NOADDIER;
-EM00713> SPILL: T<- ONE;
-EM00712> NOSPILL: AC0<- L MRSH 1;
-EM00723> L<- AC1, BUSODD;
-EM00724> T<- AC0, :NOADDX;
+EM0713> SPILL: T<- ONE;
+EM0712> NOSPILL: AC0<- L MRSH 1;
+EM0723> L<- AC1, BUSODD;
+EM0724> T<- AC0, :NOADDX;
-EM00714> NOADDX: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILLX;
-EM00715> ADDX: L<- T<- XREG+ INCT;
-EM00725> L<- AC1,ALUCY, :NOADDX;
+EM0714> NOADDX: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILLX;
+EM0715> ADDX: L<- T<- XREG+ INCT;
+EM0725> L<- AC1,ALUCY, :NOADDX;
-EM00717> SPILLX: T<- ONE;
-EM00716> NOSPILLX: AC0<- L MRSH 1;
-EM00726> L<- SAD+1, BUS=0, TASK;
-EM00727> SAD<- L, :MPYL;
+EM0717> SPILLX: T<- ONE;
+EM0716> NOSPILLX: AC0<- L MRSH 1;
+EM0726> L<- SAD+1, BUS=0, TASK;
+EM0727> SAD<- L, :MPYL;
-EM00705> NOMUL: T<- AC0;
-EM00730> AC0<- L, L<- T, TASK; CLEAR AC0
-EM00731> AC1<- L; AND REPLACE AC1 WITH AC0
-EM00707> MPYA: :FINBLT; ***X21 change.
+EM0705> NOMUL: T<- AC0;
+EM0730> AC0<- L, L<- T, TASK; CLEAR AC0
+EM0731> AC1<- L; AND REPLACE AC1 WITH AC0
+EM0707> MPYA: :FINBLT; ***X21 change.
;CYCLE AC0 LEFT BY DISP MOD 20B, UNLESS DISP=0, IN WHICH
;CASE CYCLE BY AC1 MOD 20B
@@ -962,53 +962,53 @@ $CYCOUT $R7; Shares space with XREG.
!1,1,Z2;
!1,1,Z3;
-EM00062> EMCYCLE: L<- DISP, SINK<- X17, BUS=0; CONSTANT WITH BS=7
-EM00734> CYCP: T<- AC0, :EMCYCX;
+EM0062> EMCYCLE: L<- DISP, SINK<- X17, BUS=0; CONSTANT WITH BS=7
+EM0734> CYCP: T<- AC0, :EMCYCX;
-EM00733> ACCYCLE: T<- AC1;
-EM00736> L<- 17 AND T, :CYCP;
+EM0733> ACCYCLE: T<- AC1;
+EM0736> L<- 17 AND T, :CYCP;
-EM00732> EMCYCX: CYCOUT<-L, L<-0, :RETCYCX;
+EM0732> EMCYCX: CYCOUT<-L, L<-0, :RETCYCX;
-EM00022> RAMCYCX: CYCOUT<-L, L<-0+1;
+EM0022> RAMCYCX: CYCOUT<-L, L<-0+1;
-EM00740> RETCYCX: CYRET<-L, L<-0+T;
-EM00742> SINK<-CYCOUT, BUS;
-EM00744> TASK, :L0;
+EM0740> RETCYCX: CYRET<-L, L<-0+T;
+EM0742> SINK<-CYCOUT, BUS;
+EM0744> TASK, :L0;
;TABLE FOR CYCLE
-EM00174> R4: CYCOUT<- L MRSH 1;
-EM00741> Y3: L<- T<- CYCOUT, TASK;
-EM00175> R3X: CYCOUT<- L MRSH 1;
-EM00737> Y2: L<- T<- CYCOUT, TASK;
-EM00176> R2X: CYCOUT<- L MRSH 1;
-EM00735> Y1: L<- T<- CYCOUT, TASK;
-EM00177> R1X: CYCOUT<- L MRSH 1, :ENDCYCLE;
+EM0174> R4: CYCOUT<- L MRSH 1;
+EM0741> Y3: L<- T<- CYCOUT, TASK;
+EM0175> R3X: CYCOUT<- L MRSH 1;
+EM0737> Y2: L<- T<- CYCOUT, TASK;
+EM0176> R2X: CYCOUT<- L MRSH 1;
+EM0735> Y1: L<- T<- CYCOUT, TASK;
+EM0177> R1X: CYCOUT<- L MRSH 1, :ENDCYCLE;
-EM00164> L4: CYCOUT<- L MLSH 1;
-EM00747> Z3: L<- T<- CYCOUT, TASK;
-EM00163> L3: CYCOUT<- L MLSH 1;
-EM00745> Z2: L<- T<- CYCOUT, TASK;
-EM00162> L2: CYCOUT<- L MLSH 1;
-EM00743> Z1: L<- T<- CYCOUT, TASK;
-EM00161> L1: CYCOUT<- L MLSH 1, :ENDCYCLE;
-EM00160> L0: CYCOUT<- L, :ENDCYCLE;
+EM0164> L4: CYCOUT<- L MLSH 1;
+EM0747> Z3: L<- T<- CYCOUT, TASK;
+EM0163> L3: CYCOUT<- L MLSH 1;
+EM0745> Z2: L<- T<- CYCOUT, TASK;
+EM0162> L2: CYCOUT<- L MLSH 1;
+EM0743> Z1: L<- T<- CYCOUT, TASK;
+EM0161> L1: CYCOUT<- L MLSH 1, :ENDCYCLE;
+EM0160> L0: CYCOUT<- L, :ENDCYCLE;
-EM00164> L8: CYCOUT<- L LCY 8, :ENDCYCLE;
-EM00165> L7: CYCOUT<- L LCY 8, :Y1;
-EM00166> L6: CYCOUT<- L LCY 8, :Y2;
-EM00165> L5: CYCOUT<- L LCY 8, :Y3;
+EM0164> L8: CYCOUT<- L LCY 8, :ENDCYCLE;
+EM0165> L7: CYCOUT<- L LCY 8, :Y1;
+EM0166> L6: CYCOUT<- L LCY 8, :Y2;
+EM0165> L5: CYCOUT<- L LCY 8, :Y3;
-EM00171> R7: CYCOUT<- L LCY 8, :Z1;
-EM00172> R6: CYCOUT<- L LCY 8, :Z2;
-EM00173> R5: CYCOUT<- L LCY 8, :Z3;
+EM0171> R7: CYCOUT<- L LCY 8, :Z1;
+EM0172> R6: CYCOUT<- L LCY 8, :Z2;
+EM0173> R5: CYCOUT<- L LCY 8, :Z3;
-EM00746> ENDCYCLE: SINK<- CYRET, BUS, TASK;
-EM00750> :EMCYCRET;
+EM0746> ENDCYCLE: SINK<- CYRET, BUS, TASK;
+EM0750> :EMCYCRET;
-EM00600> EMCYCRET: L<-YCOUT, TASK, :LOADD;
+EM0600> EMCYCRET: L<-YCOUT, TASK, :LOADD;
-EM00601> RAMCYCRET: T<-PC, BUS, SWMODE, :TORAM;
+EM0601> RAMCYCRET: T<-PC, BUS, SWMODE, :TORAM;
; Scan convert instruction for characters. Takes DWAX (Destination
; word address)-NWRDS in AC0, and a pointer to a .AL-format font
@@ -1024,85 +1024,85 @@ $MASK $R36;
!1,2,NFIN,FIN;
!17,2,DOBOTH,MOVELOOP;
-EM00566> CONVERT: MAR<-XREG+1; Got here via indirect mechanism which
+EM0566> CONVERT: MAR<-XREG+1; Got here via indirect mechanism which
; left first arg in SAD, its address in XREG.
-EM00751> T<-17;
-EM00760> L<-MD AND T;
+EM0751> T<-17;
+EM0760> L<-MD AND T;
-EM00761> T<-MAR<-AC3;
-EM00762> AC1<-L; AC1<-DBA
-EM00763> L<-MD+T, TASK;
-EM00764> AC3<-L; AC3<-Character descriptor block address(Char)
+EM0761> T<-MAR<-AC3;
+EM0762> AC1<-L; AC1<-DBA
+EM0763> L<-MD+T, TASK;
+EM0764> AC3<-L; AC3<-Character descriptor block address(Char)
-EM00765> MAR<-AC3+1;
-EM00766> T<-177400;
-EM00767> IR<-L<-MD AND T; IR<-XH
-EM00770> XH<-L LCY 8, :ODDCX; XH register temporarily contains HD
-EM00577> ODDCX: L<-AC0, :HDENTER;
+EM0765> MAR<-AC3+1;
+EM0766> T<-177400;
+EM0767> IR<-L<-MD AND T; IR<-XH
+EM0770> XH<-L LCY 8, :ODDCX; XH register temporarily contains HD
+EM0577> ODDCX: L<-AC0, :HDENTER;
-EM00752> HDLOOP: T<-SAD; (really NWRDS)
-EM00771> L<-DWAX+T;
+EM0752> HDLOOP: T<-SAD; (really NWRDS)
+EM0771> L<-DWAX+T;
-EM00772> HDENTER: DWAX<-L; DWAX <- AC0+HD*NWRDS
-EM00773> L<-XH-1, BUS=0, TASK;
-EM00774> XH<-L, :HDLOOP;
+EM0772> HDENTER: DWAX<-L; DWAX <- AC0+HD*NWRDS
+EM0773> L<-XH-1, BUS=0, TASK;
+EM0774> XH<-L, :HDLOOP;
-EM00753> HDEXIT: T<-MASKTAB;
-EM00775> MAR<-T<-AC1+T; Fetch the mask.
-EM01000> L<-DISP;
-EM01001> XH<-L; XH register now contains XH
-EM01002> L<-MD;
-EM01003> MASK<-L, L<-0+T+1, TASK;
-EM01004> AC1<-L; ***X21. AC1 <- (DBA)+1
+EM0753> HDEXIT: T<-MASKTAB;
+EM0775> MAR<-T<-AC1+T; Fetch the mask.
+EM1000> L<-DISP;
+EM1001> XH<-L; XH register now contains XH
+EM1002> L<-MD;
+EM1003> MASK<-L, L<-0+T+1, TASK;
+EM1004> AC1<-L; ***X21. AC1 <- (DBA)+1
-EM01005> L<-5; ***X21. Calling conventions changed.
-EM01006> IR<-SAD, TASK;
-EM01007> CYRET<-L, :MOVELOOP; CYRET<-CALL5
+EM1005> L<-5; ***X21. Calling conventions changed.
+EM1006> IR<-SAD, TASK;
+EM1007> CYRET<-L, :MOVELOOP; CYRET<-CALL5
-EM00777> MOVELOOP: L<-T<-XH-1, BUS=0;
-EM01010> MAR<-AC3-T-1, :NFIN; Fetch next source word
-EM00756> NFIN: XH<-L;
-EM01011> T<-DISP; (really NWRDS)
-EM01012> L<-DWAX+T; Update destination address
-EM01013> T<-MD;
-EM01014> SINK<-AC1, BUS;
-EM01015> DWAX<-L, L<-T, TASK, :L0; Call Cycle subroutine
+EM0777> MOVELOOP: L<-T<-XH-1, BUS=0;
+EM1010> MAR<-AC3-T-1, :NFIN; Fetch next source word
+EM0756> NFIN: XH<-L;
+EM1011> T<-DISP; (really NWRDS)
+EM1012> L<-DWAX+T; Update destination address
+EM1013> T<-MD;
+EM1014> SINK<-AC1, BUS;
+EM1015> DWAX<-L, L<-T, TASK, :L0; Call Cycle subroutine
-EM00605> CONVCYCRET: MAR<-DWAX;
-EM01016> T<-MASK, BUS=0;
-EM01017> T<-CYCOUT.T, :MERGE; Data for first word. If MASK=0
+EM0605> CONVCYCRET: MAR<-DWAX;
+EM1016> T<-MASK, BUS=0;
+EM1017> T<-CYCOUT.T, :MERGE; Data for first word. If MASK=0
; then store the word rather than
; merging, and do not disturb the
; second word.
-EM00754> MERGE: L<-XREG AND NOT T; Data for second word.
-EM01020> T<-MD OR T; First word now merged,
-EM01021> XREG<-L, L<-T;
-EM01022> MTEMP<-L;
-EM01023> MAR<-DWAX; restore it.
-EM01024> SINK<-XREG, BUS=0, TASK;
-EM01025> MD<-MTEMP, :DOBOTH; XREG=0 means only one word
+EM0754> MERGE: L<-XREG AND NOT T; Data for second word.
+EM1020> T<-MD OR T; First word now merged,
+EM1021> XREG<-L, L<-T;
+EM1022> MTEMP<-L;
+EM1023> MAR<-DWAX; restore it.
+EM1024> SINK<-XREG, BUS=0, TASK;
+EM1025> MD<-MTEMP, :DOBOTH; XREG=0 means only one word
; is involved.
-EM00776> DOBOTH: MAR<-DWAX+1;
-EM01026> T<-XREG;
-EM01027> L<-MD OR T;
-EM01030> MAR<-DWAX+1;
-EM01031> XREG<-L, TASK; ***X21. TASK added.
-EM00755> STORE: MD<-XREG, :MOVELOOP;
+EM0776> DOBOTH: MAR<-DWAX+1;
+EM1026> T<-XREG;
+EM1027> L<-MD OR T;
+EM1030> MAR<-DWAX+1;
+EM1031> XREG<-L, TASK; ***X21. TASK added.
+EM0755> STORE: MD<-XREG, :MOVELOOP;
-EM00757> FIN: L<-AC1-1; ***X21. Return AC1 to DBA.
-EM01032> AC1<-L; *** ... bletch ...
-EM01033> IR<-SH3CONST;
-EM01034> L<-MD, TASK, :SH1;
+EM0757> FIN: L<-AC1-1; ***X21. Return AC1 to DBA.
+EM1032> AC1<-L; *** ... bletch ...
+EM1033> IR<-SH3CONST;
+EM1034> L<-MD, TASK, :SH1;
;RCLK - 61003 - Read the Real Time Clock into AC0,AC1
-EM00103> RCLK: MAR<- CLOCKLOC;
-EM01035> L<- R37;
-EM01036> AC1<- L, :LOADX;
+EM0103> RCLK: MAR<- CLOCKLOC;
+EM1035> L<- R37;
+EM1036> AC1<- L, :LOADX;
;SIO - 61004 - Put AC0 on the bus, issue STARTF to get device attention,
;Read Host address from Ethernet interface into AC0.
-EM0104> SIO: L<- AC0, STARTF;
+EM104> SIO: L<- AC0, STARTF;
EM1037> T<- 77777; ***X21 sets AC0[0] to 0
EM1040> L<- RSNF AND T;
EM1041> LTOAC0: AC0<- L, TASK, :TOSTART;
@@ -1115,16 +1115,16 @@ EM1041> LTOAC0: AC0<- L, TASK, :TOSTART;
;Use of the Alto Build number has been abandoned.
;the engineering number (EngNumber) is in the MRT files because it
; it different for Altos with and without Extended memory.
-EM00114> VERS: T<- EngNumber; ***V3 change
-EM01042> L<- 3+T, :LTOAC0; ***V3 change
+EM0114> VERS: T<- EngNumber; ***V3 change
+EM1042> L<- 3+T, :LTOAC0; ***V3 change
;XMLDA - Extended Memory Load Accumulator.
; AC0 <- @AC1 in the alternate bank
-EM00125> XMLDA: XMAR<- AC1, :FINLOAD; ***V3 change
+EM0125> XMLDA: XMAR<- AC1, :FINLOAD; ***V3 change
;XMSTA - Extended Memory Store Accumulator
; @AC1 <- AC0 in the alternate bank
-EM00126> XMSTA: XMAR<- AC1, :XSTA1; ***V3 change
+EM0126> XMSTA: XMAR<- AC1, :XSTA1; ***V3 change
;BLT - 61005 - Block Transfer
;BLKS - 61006 - Block Store
@@ -1145,82 +1145,82 @@ EM00126> XMSTA: XMAR<- AC1, :XSTA1; ***V3 change
!1,2,PERHAPS, NO;
-EM00105> BLT: L<- MAR<- AC0+1;
-EM01043> AC0<- L;
-EM01046> L<- MD, :BLKSA;
+EM0105> BLT: L<- MAR<- AC0+1;
+EM1043> AC0<- L;
+EM1046> L<- MD, :BLKSA;
-EM00106> BLKS: L<- AC0;
-EM01047> BLKSA: T<- AC3+1, BUS=0;
-EM01050> MAR<- AC1+T, :MOREBLT;
+EM0106> BLKS: L<- AC0;
+EM1047> BLKSA: T<- AC3+1, BUS=0;
+EM1050> MAR<- AC1+T, :MOREBLT;
-EM00606> MOREBLT: XREG<- L, L<- T;
-EM01051> AC3<- L, TASK;
-EM01052> MD<- XREG; STORE
-EM01053> L<- NWW, BUS=0; CHECK FOR INTERRUPT
-EM01054> SH<0, :PERHAPS, L<- PC-1; Prepare to back up PC.
+EM0606> MOREBLT: XREG<- L, L<- T;
+EM1051> AC3<- L, TASK;
+EM1052> MD<- XREG; STORE
+EM1053> L<- NWW, BUS=0; CHECK FOR INTERRUPT
+EM1054> SH<0, :PERHAPS, L<- PC-1; Prepare to back up PC.
-EM01045> NO: SINK<- DISP, SINK<- M7, BUS, :DISABLED;
+EM1045> NO: SINK<- DISP, SINK<- M7, BUS, :DISABLED;
-EM01044> PERHAPS: SINK<- DISP, SINK<- M7, BUS, :DOIT;
+EM1044> PERHAPS: SINK<- DISP, SINK<- M7, BUS, :DOIT;
-EM00610> DOIT: PC<-L, :FINBLT; ***X21. Reset PC, terminate instruction.
+EM0610> DOIT: PC<-L, :FINBLT; ***X21. Reset PC, terminate instruction.
-EM00611> DISABLED: :DIR; GOES TO BLT OR BLKS
+EM0611> DISABLED: :DIR; GOES TO BLT OR BLKS
-EM00607> FINBLT: T<-777; ***X21. PC in [177000-177777] means Ram return
-EM01055> L<-PC+T+1;
-EM01056> L<-PC AND T, TASK, ALUCY;
-EM01057> TOSTART: XREG<-L, :START;
+EM0607> FINBLT: T<-777; ***X21. PC in [177000-177777] means Ram return
+EM1055> L<-PC+T+1;
+EM1056> L<-PC AND T, TASK, ALUCY;
+EM1057> TOSTART: XREG<-L, :START;
-EM00021> RAMRET: T<-XREG, BUS, SWMODE;
-EM01060> TORAM: :NOVEM;
+EM0021> RAMRET: T<-XREG, BUS, SWMODE;
+EM1060> TORAM: :NOVEM;
;PARAMETERLESS INSTRUCTIONS FOR DIDDLING THE WCS.
;JMPRAM - 61010 - JUMP TO THE RAM ADDRESS SPECIFIED BY AC1
-EM00110> JMPR: T<-AC1, BUS, SWMODE, :TORAM;
+EM0110> JMPR: T<-AC1, BUS, SWMODE, :TORAM;
;RDRAM - 61011 - READ THE RAM WORD ADDRESSED BY AC1 INTO AC0
-EM00111> RDRM: T<- AC1, RDRAM;
-EM01061> L<- ALLONES, TASK, :LOADD;
+EM0111> RDRM: T<- AC1, RDRAM;
+EM1061> L<- ALLONES, TASK, :LOADD;
;WRTRAM - 61012 - WRITE AC0,AC3 INTO THE RAM LOCATION ADDRESSED BY AC1
-EM00112> WTRM: T<- AC1;
-EM01062> L<- AC0, WRTRAM;
-EM01063> L<- AC3, :FINBLT;
+EM0112> WTRM: T<- AC1;
+EM1062> L<- AC0, WRTRAM;
+EM1063> L<- AC3, :FINBLT;
;DOUBLE WORD INSTRUCTIONS
;DREAD - 61015
; AC0<- rv(AC3); AC1<- rv(AC3 xor 1)
-EM00115> DREAD: MAR<- AC3; START MEMORY CYCLE
-EM01064> NOP; DELAY
-EM01065> DREAD1: L<- MD; FIRST READ
-EM01066> T<-MD; SECOND READ
-EM01067> AC0<- L, L<-T, TASK; STORE MSW
-EM01070> AC1<- L, :START; STORE LSW
+EM0115> DREAD: MAR<- AC3; START MEMORY CYCLE
+EM1064> NOP; DELAY
+EM1065> DREAD1: L<- MD; FIRST READ
+EM1066> T<-MD; SECOND READ
+EM1067> AC0<- L, L<-T, TASK; STORE MSW
+EM1070> AC1<- L, :START; STORE LSW
;DWRITE - 61016
; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1
-EM00116> DWRITE: MAR<- AC3; START MEMORY CYCLE
-EM01071> NOP; DELAY
-EM01072> MD<- AC0, TASK; FIRST WRITE
-EM01073> MD<- AC1, :START; SECOND WRITE
+EM0116> DWRITE: MAR<- AC3; START MEMORY CYCLE
+EM1071> NOP; DELAY
+EM1072> MD<- AC0, TASK; FIRST WRITE
+EM1073> MD<- AC1, :START; SECOND WRITE
;DEXCH - 61017
; t<- rv(AC3); rv(AC3)<- AC0; AC0<- t
; t<- rv(AC3 xor 1); rv(AC3 xor 1)<- AC1; AC1<- t
-EM00117> DEXCH: MAR<- AC3; START MEMORY CYCLE
-EM01074> NOP; DELAY
-EM01075> MD<- AC0; FIRST WRITE
-EM01076> MD<- AC1,:DREAD1; SECOND WRITE, GO TO READ
+EM0117> DEXCH: MAR<- AC3; START MEMORY CYCLE
+EM1074> NOP; DELAY
+EM1075> MD<- AC0; FIRST WRITE
+EM1076> MD<- AC1,:DREAD1; SECOND WRITE, GO TO READ
;DIOGNOSE INSTRUCTIONS
@@ -1229,58 +1229,58 @@ EM01076> MD<- AC1,:DREAD1; SECOND WRITE, GO TO READ
; Hamming Code<- AC2
; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1
-EM00122> DIOG1: MAR<- ERRCTRL; START WRITE TO ERROR CONTROL
-EM01077> NOP; DELAY
-EM01100> MD<- AC2,:DWRITE; WRITE HAMMING CODE, GO TO DWRITE
+EM0122> DIOG1: MAR<- ERRCTRL; START WRITE TO ERROR CONTROL
+EM1077> NOP; DELAY
+EM1100> MD<- AC2,:DWRITE; WRITE HAMMING CODE, GO TO DWRITE
;DIOG2 - 61023
; rv(AC3)<- AC0
; rv(AC3)<- AC0 xor AC1
-EM00123> DIOG2: MAR<- AC3; START MEMORY CYCLE
-EM01101> T<- AC0; SETUP FOR XOR
-EM01102> L<- AC1 XORT; DO XOR
-EM01103> MD<- AC0; FIRST WRITE
-EM01104> MAR<- AC3; START MEMORY CYCLE
-EM01105> AC0<- L, TASK; STORE XOR WORD
-EM01106> MD<- AC0, :START; SECOND WRITE
+EM0123> DIOG2: MAR<- AC3; START MEMORY CYCLE
+EM1101> T<- AC0; SETUP FOR XOR
+EM1102> L<- AC1 XORT; DO XOR
+EM1103> MD<- AC0; FIRST WRITE
+EM1104> MAR<- AC3; START MEMORY CYCLE
+EM1105> AC0<- L, TASK; STORE XOR WORD
+EM1106> MD<- AC0, :START; SECOND WRITE
;INTERRUPT SYSTEM. TIMING IS 0 CYCLES IF DISABLED, 18 CYCLES
;IF THE INTERRUPTING CHANEL IS INACTIVE, AND 36+6N CYCLES TO CAUSE
;AN INTERRUPT ON CHANNEL N
-EM00567> INTCODE:PC<- L, IR<- 0;
-EM01107> T<- NWW;
-EM01110> T<- MD OR T;
-EM01111> L<- MD AND T;
-EM01112> SAD<- L, L<- T, SH=0; SAD HAD POTENTIAL INTERRUPTS
-EM01113> NWW<- L, L<- 0+1, :SOMEACTIVE; NWW HAS NEW WW
+EM0567> INTCODE:PC<- L, IR<- 0;
+EM1107> T<- NWW;
+EM1110> T<- MD OR T;
+EM1111> L<- MD AND T;
+EM1112> SAD<- L, L<- T, SH=0; SAD HAD POTENTIAL INTERRUPTS
+EM1113> NWW<- L, L<- 0+1, :SOMEACTIVE; NWW HAS NEW WW
-EM00537> NOACTIVE: MAR<- WWLOC; RESTORE WW TO CORE
-EM01114> L<- SAD; AND REPLACE IT WITH SAD IN NWW
-EM01115> MD<- NWW, TASK;
-EM01116> INTZ: NWW<- L, :START;
+EM0537> NOACTIVE: MAR<- WWLOC; RESTORE WW TO CORE
+EM1114> L<- SAD; AND REPLACE IT WITH SAD IN NWW
+EM1115> MD<- NWW, TASK;
+EM1116> INTZ: NWW<- L, :START;
-EM00536> SOMEACTIVE: MAR<- PCLOC; STORE PC AND SET UP TO FIND HIGHEST PRIORITY REQUEST
-EM01117> XREG<- L, L<- 0;
-EM01120> MD<- PC, TASK;
+EM0536> SOMEACTIVE: MAR<- PCLOC; STORE PC AND SET UP TO FIND HIGHEST PRIORITY REQUEST
+EM1117> XREG<- L, L<- 0;
+EM1120> MD<- PC, TASK;
-EM01121> ILPA: PC<- L;
-EM01122> ILP: T<- SAD;
-EM01123> L<- T<- XREG AND T;
-EM01124> SH=0, L<- T, T<- PC;
-EM01125> :IEXIT, XREG<- L LSH 1;
+EM1121> ILPA: PC<- L;
+EM1122> ILP: T<- SAD;
+EM1123> L<- T<- XREG AND T;
+EM1124> SH=0, L<- T, T<- PC;
+EM1125> :IEXIT, XREG<- L LSH 1;
-EM00571> NIEXIT: L<- 0+T+1, TASK, :ILPA;
-EM00570> IEXIT: MAR<- PCLOC+T+1; FETCH NEW PC. T HAS CHANNEL #, L HAS MASK
+EM0571> NIEXIT: L<- 0+T+1, TASK, :ILPA;
+EM0570> IEXIT: MAR<- PCLOC+T+1; FETCH NEW PC. T HAS CHANNEL #, L HAS MASK
-EM01126> XREG<- L;
-EM01127> T<- XREG;
-EM01130> L<- NWW XOR T; TURN OFF BIT IN WW FOR INTERRUPT ABOUT TO HAPPEN
-EM01131> T<- MD;
-EM01132> NWW<- L, L<- T;
-EM01133> PC<- L, L<- T<- 0+1, TASK;
-EM01134> SAD<- L MRSH 1, :NOACTIVE; SAD<- 1B5 TO DISABLE INTERRUPTS
+EM1126> XREG<- L;
+EM1127> T<- XREG;
+EM1130> L<- NWW XOR T; TURN OFF BIT IN WW FOR INTERRUPT ABOUT TO HAPPEN
+EM1131> T<- MD;
+EM1132> NWW<- L, L<- T;
+EM1133> PC<- L, L<- T<- 0+1, TASK;
+EM1134> SAD<- L MRSH 1, :NOACTIVE; SAD<- 1B5 TO DISABLE INTERRUPTS
;
; ************************
@@ -1347,267 +1347,267 @@ $LASTMASK $477; MASKTABLE+020 **NOT IN EARLIER PROMS!
!1,2,FDBL,BBNORAM;
!17,20,FDBX,,,,FDX,,FDW,,,,FSX,,,,,; FDBL RETURNS (BASED ON OFFSET)
; (0) 4 6 12
-EM00124> BITBLT: L<- 0;
-EM01135> SINK<-LREG, BUSODD; SINK<- -1 IFF NO RAM
-EM01142> L<- T<- DWOFF, :FDBL;
-EM01141> BBNORAM: TASK, :NPTRAP; TRAP IF NO RAM
+EM0124> BITBLT: L<- 0;
+EM1135> SINK<-LREG, BUSODD; SINK<- -1 IFF NO RAM
+EM1142> L<- T<- DWOFF, :FDBL;
+EM1141> BBNORAM: TASK, :NPTRAP; TRAP IF NO RAM
;
-EM01166> FDW: T<- MD; PICK UP WIDTH, HEIGHT
-EM01143> WIDTH<- L, L<- T, TASK, :NZWID;
-EM01144> NZWID: NLINES<- L;
-EM01145> T<- AC1;
-EM01146> L<- NLINES-T;
-EM01147> NLINES<- L, SH<0, TASK;
-EM01150> :FDDX;
+EM1166> FDW: T<- MD; PICK UP WIDTH, HEIGHT
+EM1143> WIDTH<- L, L<- T, TASK, :NZWID;
+EM1144> NZWID: NLINES<- L;
+EM1145> T<- AC1;
+EM1146> L<- NLINES-T;
+EM1147> NLINES<- L, SH<0, TASK;
+EM1150> :FDDX;
;
-EM01136> FDDX: L<- T<- DXOFF, :FDBL; PICK UP DEST X AND Y
-EM01164> FDX: T<- MD;
-EM01151> DESTX<- L, L<- T, TASK;
-EM01152> DESTY<- L;
+EM1136> FDDX: L<- T<- DXOFF, :FDBL; PICK UP DEST X AND Y
+EM1164> FDX: T<- MD;
+EM1151> DESTX<- L, L<- T, TASK;
+EM1152> DESTY<- L;
;
-EM01153> L<- T<- SXOFF, :FDBL; PICK UP SOURCE X AND Y
-EM01172> FSX: T<- MD;
-EM01154> SRCX<- L, L<- T, TASK;
-EM01155> SRCY<- L, :CSHI;
+EM1153> L<- T<- SXOFF, :FDBL; PICK UP SOURCE X AND Y
+EM1172> FSX: T<- MD;
+EM1154> SRCX<- L, L<- T, TASK;
+EM1155> SRCY<- L, :CSHI;
;
; /* FETCH DOUBLEWORD FROM TABLE (L<- T<- OFFSET, :FDBL)
-EM01140> FDBL: MAR<- AC2+T;
-EM01156> SINK<- LREG, BUS;
-EM01160> FDBX: L<- MD, :FDBX;
+EM1140> FDBL: MAR<- AC2+T;
+EM1156> SINK<- LREG, BUS;
+EM1160> FDBX: L<- MD, :FDBX;
;
; /* CALCULATE SKEW AND HINC
!1,2,LTOR,RTOL;
-EM01157> CSHI: T<- DESTX;
-EM01161> L<- SRCX-T-1;
-EM01165> T<- LREG+1, SH<0; TEST HORIZONTAL DIRECTION
-EM01167> L<- 17.T, :LTOR; SKEW <- (SRCX - DESTX) MOD 16
-EM01163> RTOL: SKEW<- L, L<- 0-1, :AH, TASK; HINC <- -1
-EM00162> LTOR: SKEW<- L, L<- 0+1, :AH, TASK; HINC <- +1
-EM01170> AH: HINC<- L;
+EM1157> CSHI: T<- DESTX;
+EM1161> L<- SRCX-T-1;
+EM1165> T<- LREG+1, SH<0; TEST HORIZONTAL DIRECTION
+EM1167> L<- 17.T, :LTOR; SKEW <- (SRCX - DESTX) MOD 16
+EM1163> RTOL: SKEW<- L, L<- 0-1, :AH, TASK; HINC <- -1
+EM0162> LTOR: SKEW<- L, L<- 0+1, :AH, TASK; HINC <- +1
+EM1170> AH: HINC<- L;
;
; CALCULATE MASK1 AND MASK2
!1,2,IFRTOL,LNWORDS;
!1,2,POSWID,NEGWID;
-EM01171> CMASKS: T<- DESTX;
-EM01173> T<- 17.T;
-EM01200> MAR<- LASTMASKP1-T-1;
-EM01201> L<- 17-T; STARTBITS <- 16 - (DESTX.17)
-EM01202> STARTBITSM1<- L;
-EM01203> L<- MD, TASK;
-EM01204> MASK1<- L; MASK1 <- @(MASKLOC+STARTBITS)
-EM01205> L<- WIDTH-1;
-EM01206> T<- LREG-1, SH<0;
-EM01207> T<- DESTX+T+1, :POSWID;
-EM01176> POSWID: T<- 17.T;
-EM01210> MAR<- LASTMASK-T-1;
-EM01211> T<- ALLONES; MASK2 <- NOT
-EM01212> L<- HINC-1;
-EM01213> L<- MD XOR T, SH=0, TASK; @(MASKLOC+(15-((DESTX+WIDTH-1).17)))
-EM01214> MASK2<- L, :IFRTOL;
+EM1171> CMASKS: T<- DESTX;
+EM1173> T<- 17.T;
+EM1200> MAR<- LASTMASKP1-T-1;
+EM1201> L<- 17-T; STARTBITS <- 16 - (DESTX.17)
+EM1202> STARTBITSM1<- L;
+EM1203> L<- MD, TASK;
+EM1204> MASK1<- L; MASK1 <- @(MASKLOC+STARTBITS)
+EM1205> L<- WIDTH-1;
+EM1206> T<- LREG-1, SH<0;
+EM1207> T<- DESTX+T+1, :POSWID;
+EM1176> POSWID: T<- 17.T;
+EM1210> MAR<- LASTMASK-T-1;
+EM1211> T<- ALLONES; MASK2 <- NOT
+EM1212> L<- HINC-1;
+EM1213> L<- MD XOR T, SH=0, TASK; @(MASKLOC+(15-((DESTX+WIDTH-1).17)))
+EM1214> MASK2<- L, :IFRTOL;
; /* IF RIGHT TO LEFT, ADD WIDTH TO X'S AND EXCH MASK1, MASK2
-EM01174> IFRTOL: T<- WIDTH-1; WIDTH-1
-EM01215> L<- SRCX+T;
-EM01216> SRCX<- L; SRCX <- SCRX + (WIDTH-1)
-EM01217> L<- DESTX+T;
-EM01220> DESTX<- L; DESTX <- DESTX + (WIDTH-1)
-EM01221> T<- DESTX;
-EM01222> L<- 17.T, TASK;
-EM01223> STARTBITSM1<- L; STARTBITS <- (DESTX.17) + 1
-EM01224> T<- MASK1;
-EM01225> L<- MASK2;
-EM01226> MASK1<- L, L<- T,TASK; EXCHANGE MASK1 AND MASK2
-EM01227> MASK2<-L;
+EM1174> IFRTOL: T<- WIDTH-1; WIDTH-1
+EM1215> L<- SRCX+T;
+EM1216> SRCX<- L; SRCX <- SCRX + (WIDTH-1)
+EM1217> L<- DESTX+T;
+EM1220> DESTX<- L; DESTX <- DESTX + (WIDTH-1)
+EM1221> T<- DESTX;
+EM1222> L<- 17.T, TASK;
+EM1223> STARTBITSM1<- L; STARTBITS <- (DESTX.17) + 1
+EM1224> T<- MASK1;
+EM1225> L<- MASK2;
+EM1226> MASK1<- L, L<- T,TASK; EXCHANGE MASK1 AND MASK2
+EM1227> MASK2<-L;
;
; /* CALCULATE NWORDS
!1,2,LNW1,THIN;
-EM01175> LNWORDS:T<- STARTBITSM1+1;
-EM01232> L<- WIDTH-T-1;
-EM01233> T<- 177760, SH<0;
-EM01234> T<- LREG.T, :LNW1;
-EM01230> LNW1: L<- CALL4; NWORDS <- (WIDTH-STARTBITS)/16
-EM01235> CYRET<- L, L<- T, :R4, TASK; CYRET<-CALL4
+EM1175> LNWORDS:T<- STARTBITSM1+1;
+EM1232> L<- WIDTH-T-1;
+EM1233> T<- 177760, SH<0;
+EM1234> T<- LREG.T, :LNW1;
+EM1230> LNW1: L<- CALL4; NWORDS <- (WIDTH-STARTBITS)/16
+EM1235> CYRET<- L, L<- T, :R4, TASK; CYRET<-CALL4
; **WIDTH REG NOW FREE**
-EM00604> CYX4: L<- CYCOUT, :LNW2;
-EM01231> THIN: T<- MASK1; SPECIAL CASE OF THIN SLICE
-EM01236> L<-MASK2.T;
-EM01237> MASK1<- L, L<- 0-1; MASK1 <- MASK1.MASK2, NWORDS <- -1
-EM01240> LNW2: NWORDS<- L; LOAD NWORDS
+EM0604> CYX4: L<- CYCOUT, :LNW2;
+EM1231> THIN: T<- MASK1; SPECIAL CASE OF THIN SLICE
+EM1236> L<-MASK2.T;
+EM1237> MASK1<- L, L<- 0-1; MASK1 <- MASK1.MASK2, NWORDS <- -1
+EM1240> LNW2: NWORDS<- L; LOAD NWORDS
; **STARTBITSM1 REG NOW FREE**
;
; /* DETERMINE VERTICAL DIRECTION
!1,2,BTOT,TTOB;
T<- SRCY;
-EM01244> L<- DESTY-T;
-EM01245> T<- NLINES-1, SH<0;
-EM01246> L<- 0, :BTOT; VINC <- 0 IFF TOP-TO-BOTTOM
-EM01242> BTOT: L<- ALLONES; ELSE -1
-EM01247> BTOT1: VINC<- L;
-EM01250> L<- SRCY+T; GOING BOTTOM TO TOP
-EM01251> SRCY<- L; ADD NLINES TO STARTING Y'S
-EM01252> L<- DESTY+T;
-EM01253> DESTY<- L, L<- 0+1, TASK;
-EM01254> TWICE<-L, :CWA;
+EM1244> L<- DESTY-T;
+EM1245> T<- NLINES-1, SH<0;
+EM1246> L<- 0, :BTOT; VINC <- 0 IFF TOP-TO-BOTTOM
+EM1242> BTOT: L<- ALLONES; ELSE -1
+EM1247> BTOT1: VINC<- L;
+EM1250> L<- SRCY+T; GOING BOTTOM TO TOP
+EM1251> SRCY<- L; ADD NLINES TO STARTING Y'S
+EM1252> L<- DESTY+T;
+EM1253> DESTY<- L, L<- 0+1, TASK;
+EM1254> TWICE<-L, :CWA;
;
-EM01243> TTOB: T<- AC1, :BTOT1; TOP TO BOT, ADD NDONE TO STARTING Y'S
+EM1243> TTOB: T<- AC1, :BTOT1; TOP TO BOT, ADD NDONE TO STARTING Y'S
; **AC1 REG NOW FREE**;
;
; /* CALCULATE WORD ADDRESSES - DO ONCE FOR SWA, THEN FOR DWAX
-EM01255> CWA: L<- SRCY; Y HAS TO GO INTO AN R-REG FOR SHIFTING
-EM01256> YMUL<- L;
-EM01257> T<- SWAOFF; FIRST TIME IS FOR SWA, SRCX
-EM01260> L<- SRCX;
+EM1255> CWA: L<- SRCY; Y HAS TO GO INTO AN R-REG FOR SHIFTING
+EM1256> YMUL<- L;
+EM1257> T<- SWAOFF; FIRST TIME IS FOR SWA, SRCX
+EM1260> L<- SRCX;
; **SRCX, SRCY REG NOW FREE**
-EM01261> DOSWA: MAR<- AC2+T; FETCH BITMAP ADDR AND RASTER
-EM01262> XREG<- L;
-EM01263> L<-CALL3;
-EM01264> CYRET<- L; CYRET<-CALL3
-EM01265> L<- MD;
-EM01266> T<- MD;
-EM01267> DWAX<- L, L<-T, TASK;
-EM01270> RAST2<- L;
-EM01271> T<- 177760;
-EM01272> L<- T<- XREG.T, :R4, TASK; SWA <- SWA + SRCX/16
-EM00603> CYX3: T<- CYCOUT;
-EM01273> L<- DWAX+T;
-EM01274> DWAX<- L;
+EM1261> DOSWA: MAR<- AC2+T; FETCH BITMAP ADDR AND RASTER
+EM1262> XREG<- L;
+EM1263> L<-CALL3;
+EM1264> CYRET<- L; CYRET<-CALL3
+EM1265> L<- MD;
+EM1266> T<- MD;
+EM1267> DWAX<- L, L<-T, TASK;
+EM1270> RAST2<- L;
+EM1271> T<- 177760;
+EM1272> L<- T<- XREG.T, :R4, TASK; SWA <- SWA + SRCX/16
+EM0603> CYX3: T<- CYCOUT;
+EM1273> L<- DWAX+T;
+EM1274> DWAX<- L;
;
!1,2,NOADD,DOADD;
!1,2,MULLP,CDELT; SWA <- SWA + SRCY*RAST1
-EM01275> L<- RAST2;
-EM01302> SINK<- YMUL, BUS=0, TASK; NO MULT IF STARTING Y=0
-EM01303> PLIER<- L, :MULLP;
-EM01300> MULLP: L<- PLIER, BUSODD; MULTIPLY RASTER BY Y
-EM01304> PLIER<- L RSH 1, :NOADD;
-EM01276> NOADD: L<- YMUL, SH=0, TASK; TEST NO MORE MULTIPLIER BITS
-EM01305> SHIFTB: YMUL<- L LSH 1, :MULLP;
-EM01277> DOADD: T<- YMUL;
-EM01306> L<- DWAX+T;
-EM01307> DWAX<- L, L<-T, :SHIFTB, TASK;
+EM1275> L<- RAST2;
+EM1302> SINK<- YMUL, BUS=0, TASK; NO MULT IF STARTING Y=0
+EM1303> PLIER<- L, :MULLP;
+EM1300> MULLP: L<- PLIER, BUSODD; MULTIPLY RASTER BY Y
+EM1304> PLIER<- L RSH 1, :NOADD;
+EM1276> NOADD: L<- YMUL, SH=0, TASK; TEST NO MORE MULTIPLIER BITS
+EM1305> SHIFTB: YMUL<- L LSH 1, :MULLP;
+EM1277> DOADD: T<- YMUL;
+EM1306> L<- DWAX+T;
+EM1307> DWAX<- L, L<-T, :SHIFTB, TASK;
; **PLIER, YMUL REG NOW FREE**
;
!1,2,HNEG,HPOS;
!1,2,VPOS,VNEG;
!1,1,CD1; CALCULATE DELTAS = +-(NWORDS+2)[HINC] +-RASTER[VINC]
-EM01301> CDELT: L<- T<- HINC-1; (NOTE T<- -2 OR 0)
-EM01314> L<- T<- NWORDS-T, SH=0; (L<-NWORDS+2 OR T<-NWORDS)
-EM01315> CD1: SINK<- VINC, BUSODD, :HNEG;
-EM01310> HNEG: T<- RAST2, :VPOS;
-EM01311> HPOS: L<- -2-T, :CD1; (MAKES L<- -(NWORDS+2))
-EM01312> VPOS: L<- LREG+T, :GDELT, TASK; BY NOW, LREG = +-(NWORDS+2)
-EM01313> VNEG: L<- LREG-T, :GDELT, TASK; AND T = RASTER
-EM01316> GDELT: RAST2<- L;
+EM1301> CDELT: L<- T<- HINC-1; (NOTE T<- -2 OR 0)
+EM1314> L<- T<- NWORDS-T, SH=0; (L<-NWORDS+2 OR T<-NWORDS)
+EM1315> CD1: SINK<- VINC, BUSODD, :HNEG;
+EM1310> HNEG: T<- RAST2, :VPOS;
+EM1311> HPOS: L<- -2-T, :CD1; (MAKES L<- -(NWORDS+2))
+EM1312> VPOS: L<- LREG+T, :GDELT, TASK; BY NOW, LREG = +-(NWORDS+2)
+EM1313> VNEG: L<- LREG-T, :GDELT, TASK; AND T = RASTER
+EM1316> GDELT: RAST2<- L;
;
; /* END WORD ADDR LOOP
!1,2,ONEMORE,CTOPL;
-EM01317> L<- TWICE-1;
-EM01322> TWICE<- L, SH<0;
-EM01323> L<- RAST2, :ONEMORE; USE RAST2 2ND TIME THRU
-EM01320> ONEMORE: RAST1<- L;
-EM01324> L<- DESTY, TASK; USE DESTY 2ND TIME THRU
-EM01325> YMUL<- L;
-EM01326> L<- DWAX; USE DWAX 2ND TIME THRU
-EM01327> T<- DESTX; CAREFUL - DESTX=SWA!!
-EM01330> SWA<- L, L<- T; USE DESTX 2ND TIME THRU
-EM01331> T<- DWAOFF, :DOSWA; AND DO IT AGAIN FOR DWAX, DESTX
+EM1317> L<- TWICE-1;
+EM1322> TWICE<- L, SH<0;
+EM1323> L<- RAST2, :ONEMORE; USE RAST2 2ND TIME THRU
+EM1320> ONEMORE: RAST1<- L;
+EM1324> L<- DESTY, TASK; USE DESTY 2ND TIME THRU
+EM1325> YMUL<- L;
+EM1326> L<- DWAX; USE DWAX 2ND TIME THRU
+EM1327> T<- DESTX; CAREFUL - DESTX=SWA!!
+EM1330> SWA<- L, L<- T; USE DESTX 2ND TIME THRU
+EM1331> T<- DWAOFF, :DOSWA; AND DO IT AGAIN FOR DWAX, DESTX
; **TWICE, VINC REGS NOW FREE**
;
; /* CALCULATE TOPLD
!1,2,CTOP1,CSKEW;
!1,2,HM1,H1;
!1,2,NOTOPL,TOPL;
-EM01321> CTOPL: L<- SKEW, BUS=0, TASK; IF SKEW=0 THEN 0, ELSE
-EM01340> CTX: IR<- 0, :CTOP1;
-EM01332> CTOP1: T<- SRCX; (SKEW GR SRCX.17) XOR (HINC EQ 0)
-EM01341> L<- HINC-1;
-EM01342> T<- 17.T, SH=0; TEST HINC
-EM01343> L<- SKEW-T-1, :HM1;
-EM01335> H1: T<- HINC, SH<0;
-EM01344> L<- SWA+T, :NOTOPL;
-EM01334> HM1: T<- LREG; IF HINC=-1, THEN FLIP
-EM01345> L<- 0-T-1, :H1; THE POLARITY OF THE TEST
-EM01336> NOTOPL: SINK<- HINC, BUSODD, TASK, :CTX; HINC FORCES BUSODD
-EM01337> TOPL: SWA<- L, TASK; (DISP <- 100 FOR TOPLD)
-EM01346> IR<- 100, :CSKEW;
+EM1321> CTOPL: L<- SKEW, BUS=0, TASK; IF SKEW=0 THEN 0, ELSE
+EM1340> CTX: IR<- 0, :CTOP1;
+EM1332> CTOP1: T<- SRCX; (SKEW GR SRCX.17) XOR (HINC EQ 0)
+EM1341> L<- HINC-1;
+EM1342> T<- 17.T, SH=0; TEST HINC
+EM1343> L<- SKEW-T-1, :HM1;
+EM1335> H1: T<- HINC, SH<0;
+EM1344> L<- SWA+T, :NOTOPL;
+EM1334> HM1: T<- LREG; IF HINC=-1, THEN FLIP
+EM1345> L<- 0-T-1, :H1; THE POLARITY OF THE TEST
+EM1336> NOTOPL: SINK<- HINC, BUSODD, TASK, :CTX; HINC FORCES BUSODD
+EM1337> TOPL: SWA<- L, TASK; (DISP <- 100 FOR TOPLD)
+EM1346> IR<- 100, :CSKEW;
; **HINC REG NOW FREE**
;
; /* CALCULATE SKEW MASK
!1,2,THINC,BCOM1;
!1,2,COMSK,NOCOM;
-EM01333> CSKEW: T<- SKEW, BUS=0; IF SKEW=0, THEN COMP
-EM01347> MAR<- LASTMASKP1-T-1, :THINC;
-EM01350> THINC: L<-HINC-1;
-EM01354> SH=0; IF HINC=-1, THEN COMP
-EM01351> BCOM1: T<- ALLONES, :COMSK;
-EM01352> COMSK: L<- MD XOR T, :GFN;
-EM01353> NOCOM: L<- MD, :GFN;
+EM1333> CSKEW: T<- SKEW, BUS=0; IF SKEW=0, THEN COMP
+EM1347> MAR<- LASTMASKP1-T-1, :THINC;
+EM1350> THINC: L<-HINC-1;
+EM1354> SH=0; IF HINC=-1, THEN COMP
+EM1351> BCOM1: T<- ALLONES, :COMSK;
+EM1352> COMSK: L<- MD XOR T, :GFN;
+EM1353> NOCOM: L<- MD, :GFN;
;
; /* GET FUNCTION
-EM01355> GFN: MAR<- AC2;
-EM01356> SKMSK<- L;
+EM1355> GFN: MAR<- AC2;
+EM1356> SKMSK<- L;
-EM01357> T- MD;
-EM01360> L<- DISP+T, TASK;
-EM01361> IR<- LREG, :BENTR; DISP <-DISP .OR. FUNCTION
+EM1357> T- MD;
+EM1360> L<- DISP+T, TASK;
+EM1361> IR<- LREG, :BENTR; DISP <-DISP .OR. FUNCTION
; BITBLT WORK - VERT AND HORIZ LOOPS WITH 4 SOURCES, 4 FUNCTIONS
;-----------------------------------------------------------------------
;
; /* VERTICAL LOOP: UPDATE SWA, DWAX
!1,2,DO0,VLOOP;
-EM01363> VLOOP: T<- SWA;
-EM01364> L<- RAST1<-T; INC SWA BY DELTA
-EM01365> SWA<- L;
-EM01366> T<- DWAX;
-EM01367> L<- RAST2+T, TASK; INC DWAX BY DELTA
-EM01370> DWAX<- L;
+EM1363> VLOOP: T<- SWA;
+EM1364> L<- RAST1<-T; INC SWA BY DELTA
+EM1365> SWA<- L;
+EM1366> T<- DWAX;
+EM1367> L<- RAST2+T, TASK; INC DWAX BY DELTA
+EM1370> DWAX<- L;
;
; /* TEST FOR DONE, OR NEED GRAY
!1,2,MOREV,DONEV;
!1,2,BMAYBE,BNOINT;
!1,2,BDOINT,BDIS0;
!1,2,DOGRAY,NOGRAY;
-EM01371> BENTR: L<- T<- NLINES-1; DECR NLINES AND CHECK IF DONE
-EM01402> NLINES<- L, SH<0;
-EM01403> L<- NWW, BUS=0, :MOREV; CHECK FOR INTERRUPTS
-EM01372> MOREV: L<- 3.T, :BMAYBE, SH<0; CHECK DISABLED ***V3 change
-EM01375> BNOINT: SINK<- DISP, SINK<- lgm10, BUS=0, :BDIS0, TASK;
-EM01374> BMAYBE: SINK<- DISP, SINK<- lgm10, BUS=0, :BDOINT, TASK; TEST IF NEED GRAY(FUNC=8,12)
-EM01377> BDIS0: CONST<- L, :DOGRAY; ***V3 change
+EM1371> BENTR: L<- T<- NLINES-1; DECR NLINES AND CHECK IF DONE
+EM1402> NLINES<- L, SH<0;
+EM1403> L<- NWW, BUS=0, :MOREV; CHECK FOR INTERRUPTS
+EM1372> MOREV: L<- 3.T, :BMAYBE, SH<0; CHECK DISABLED ***V3 change
+EM1375> BNOINT: SINK<- DISP, SINK<- lgm10, BUS=0, :BDIS0, TASK;
+EM1374> BMAYBE: SINK<- DISP, SINK<- lgm10, BUS=0, :BDOINT, TASK; TEST IF NEED GRAY(FUNC=8,12)
+EM1377> BDIS0: CONST<- L, :DOGRAY; ***V3 change
;
; /* INTERRUPT SUSPENSION (POSSIBLY)
!1,1,DOI1; MAY GET AN OR-1
-EM01376> BDOINT: :DOI1; TASK HERE
-EM01405> DOI1: T<- AC2;
-EM01404> MAR<- DHOFF+T; NLINES DONE = HT-NLINES-1
-EM01406> T<- NLINES;
-EM01407> L<- PC-1; BACK UP THE PC, SO WE GET RESTARTED
-EM01410> PC<- L;
-EM01411> L<- MD-T-1, :BLITX, TASK; ...WITH NO LINES DONE IN AC1
+EM1376> BDOINT: :DOI1; TASK HERE
+EM1405> DOI1: T<- AC2;
+EM1404> MAR<- DHOFF+T; NLINES DONE = HT-NLINES-1
+EM1406> T<- NLINES;
+EM1407> L<- PC-1; BACK UP THE PC, SO WE GET RESTARTED
+EM1410> PC<- L;
+EM1411> L<- MD-T-1, :BLITX, TASK; ...WITH NO LINES DONE IN AC1
;
; /* LOAD GRAY FOR THIS LINE (IF FUNCTION NEEDS IT)
!1,2,PRELD,NOPLD;
-EM01400> DOGRAY: T<- CONST-1;
-EM01414> T<- GRAYOFF+T+1;
-EM01415> MAR<- AC2+T;
-EM01416> NOP; UGH
-EM01417> L<- MD;
-EM01401> NOGRAY: SINK<- DISP, SINK<- lgm100, BUS=0, TASK; TEST TOPLD
-EM01420> CONST<- L, :PRELD;
+EM1400> DOGRAY: T<- CONST-1;
+EM1414> T<- GRAYOFF+T+1;
+EM1415> MAR<- AC2+T;
+EM1416> NOP; UGH
+EM1417> L<- MD;
+EM1401> NOGRAY: SINK<- DISP, SINK<- lgm100, BUS=0, TASK; TEST TOPLD
+EM1420> CONST<- L, :PRELD;
;
; /* NORMAL COMPLETION
-EM01177> NEGWID: L<- 0, :BLITX, TASK;
-EM01373> DONEV: L<- 0, :BLITX, TASK; MAY BE AN OR-1 HERE!
-EM01137> BLITX: AC1<- L, :FINBLT;
+EM1177> NEGWID: L<- 0, :BLITX, TASK;
+EM1373> DONEV: L<- 0, :BLITX, TASK; MAY BE AN OR-1 HERE!
+EM1137> BLITX: AC1<- L, :FINBLT;
;
; /* PRELOAD OF FIRST SOURCE WORD (DEPENDING ON ALIGNMENT)
!1,2,AB1,NB1;
-EM01412> PRELD: SINK<- DISP, SINK<- lgm40, BUS=0; WHICH BANK
-EM01421> T<- HINC, :AB1;
-EM01423> NB1: MAR<- SWA-T, :XB1; (NORMAL BANK)
-EM01422> AB1: XMAR<- SWA-T, :XB1; (ALTERNATE BANK)
-EM01424> XB1: NOP;
-EM01425> L<- MD, TASK;
-EM01426> WORD2<- L, :NOPLD;
+EM1412> PRELD: SINK<- DISP, SINK<- lgm40, BUS=0; WHICH BANK
+EM1421> T<- HINC, :AB1;
+EM1423> NB1: MAR<- SWA-T, :XB1; (NORMAL BANK)
+EM1422> AB1: XMAR<- SWA-T, :XB1; (ALTERNATE BANK)
+EM1424> XB1: NOP;
+EM1425> L<- MD, TASK;
+EM1426> WORD2<- L, :NOPLD;
;
;
; /* HORIZONTAL LOOP - 3 CALLS FOR 1ST, MIDDLE AND LAST WORDS
@@ -1615,16 +1615,16 @@ EM01426> WORD2<- L, :NOPLD;
%17,17,14,DON0,,DON2,DON3; CALLERS OF HORIZ LOOP
; NOTE THIS IGNORES 14-BITS, SO lgm14 WORKS LIKE L<-0 FOR RETN
!14,1,LH1; IGNORE RESULTING BUS
-EM01413> NOPLD: L<- 3, :FDISP; CALL #3 IS FIRST WORD
-EM01437> DON3: L<- NWORDS;
-EM01427> HCNT<- L, SH<0; HCNT COUNTS WHOLE WORDS
-EM01434> DON0: L<- HCNT-1, :DO0; IF NEG, THEN NO MIDDLE OR LAST
-EM01362> DO0: HCNT<- L, SH<0; CALL #0 (OR-14!) IS MIDDLE WORDS
+EM1413> NOPLD: L<- 3, :FDISP; CALL #3 IS FIRST WORD
+EM1437> DON3: L<- NWORDS;
+EM1427> HCNT<- L, SH<0; HCNT COUNTS WHOLE WORDS
+EM1434> DON0: L<- HCNT-1, :DO0; IF NEG, THEN NO MIDDLE OR LAST
+EM1362> DO0: HCNT<- L, SH<0; CALL #0 (OR-14!) IS MIDDLE WORDS
; UGLY HACK SQUEEZES 2 INSTRS OUT OF INNER LOOP:
-EM01432> L<- DISP, SINK<- lgm14, BUS, TASK, :FDISPA; (WORKS LIKE L<-0)
-EM01431> LASTH: :LH1; TASK AND BUS PENDING
-EM01435> LH1: L<- 2, :FDISP; CALL #2 IS LAST WORD
-EM01436> DON2: :VLOOP;
+EM1432> L<- DISP, SINK<- lgm14, BUS, TASK, :FDISPA; (WORKS LIKE L<-0)
+EM1431> LASTH: :LH1; TASK AND BUS PENDING
+EM1435> LH1: L<- 2, :FDISP; CALL #2 IS LAST WORD
+EM1436> DON2: :VLOOP;
;
;
; /* HERE ARE THE SOURCE FUNCTIONS
@@ -1632,74 +1632,74 @@ EM01436> DON2: :VLOOP;
!17,20,,,,F0A,,,,F1A,,,,F2A,,,, ; SAME FOR WINDOW RETURNS
!3,4,OP0,OP1,OP2,OP3;
!1,2,AB2,NB2;
-EM01433> FDISP: SINK<- DISP, SINK<-lgm14, BUS, TASK;
-EM01430> FDISPA: RETN<- L, :F0;
-EM01443> F0: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 0 - WINDOW
-EM01447> F1: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 1 - NOT WINDOW
-EM01467> F1A: T<- CYCOUT;
-EM01442> L<- ALLONES XOR T, TASK, :F3A;
-EM01453> F2: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 2 - WINDOW .AND. GRAY
-EM01473> F2A: T<- CYCOUT;
-EM01444> L<- ALLONES XOR T;
-EM01445> SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
-EM01446> TEMP<- L, :AB2; TEMP <- NOT WINDOW
-EM01441> NB2: MAR<- DWAX, :XB2; (NORMAL BANK)
-EM01440> AB2: XMAR<- DWAX, :XB2; (ALTERNATE BANK)
-EM01450> XB2: L<- CONST AND T; WINDOW .AND. GRAY
-EM01451> T<- TEMP;
-EM01452> T<- MD .T; DEST.AND.NOT WINDOW
-EM01454> L<- LREG OR T, TASK, :F3A; (TRANSPARENT)
-EM01457> F3: L<- CONST, TASK, :F3A; FUNC 3 - CONSTANT (COLOR)
+EM1433> FDISP: SINK<- DISP, SINK<-lgm14, BUS, TASK;
+EM1430> FDISPA: RETN<- L, :F0;
+EM1443> F0: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 0 - WINDOW
+EM1447> F1: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 1 - NOT WINDOW
+EM1467> F1A: T<- CYCOUT;
+EM1442> L<- ALLONES XOR T, TASK, :F3A;
+EM1453> F2: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 2 - WINDOW .AND. GRAY
+EM1473> F2A: T<- CYCOUT;
+EM1444> L<- ALLONES XOR T;
+EM1445> SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
+EM1446> TEMP<- L, :AB2; TEMP <- NOT WINDOW
+EM1441> NB2: MAR<- DWAX, :XB2; (NORMAL BANK)
+EM1440> AB2: XMAR<- DWAX, :XB2; (ALTERNATE BANK)
+EM1450> XB2: L<- CONST AND T; WINDOW .AND. GRAY
+EM1451> T<- TEMP;
+EM1452> T<- MD .T; DEST.AND.NOT WINDOW
+EM1454> L<- LREG OR T, TASK, :F3A; (TRANSPARENT)
+EM1457> F3: L<- CONST, TASK, :F3A; FUNC 3 - CONSTANT (COLOR)
;
;
; /* AFTER GETTING SOURCE, START MEMORY AND DISPATCH ON OP
!1,2,AB3,NB3;
-EM01455> F3A: CYCOUT<- L; (TASK HERE)
-EM01463> F0A: SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
-EM01456> SINK<- DISP, SINK<- lgm3, BUS, :AB3; DISPATCH ON OP
-EM01461> NB3: T<- MAR<- DWAX, :OP0; (NORMAL BANK)
-EM01460> AB3: T<- XMAR<- DWAX, :OP0; (ALTERNATE BANK)
+EM1455> F3A: CYCOUT<- L; (TASK HERE)
+EM1463> F0A: SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
+EM1456> SINK<- DISP, SINK<- lgm3, BUS, :AB3; DISPATCH ON OP
+EM1461> NB3: T<- MAR<- DWAX, :OP0; (NORMAL BANK)
+EM1460> AB3: T<- XMAR<- DWAX, :OP0; (ALTERNATE BANK)
;
;
; /* HERE ARE THE OPERATIONS - ENTER WITH SOURCE IN CYCOUT
%16,17,15,STFULL,STMSK; MASKED OR FULL STORE (LOOK AT 2-BIT)
; OP 0 - SOURCE
-EM01474> OP0: SINK<- RETN, BUS; TEST IF UNMASKED
-EM01462> OP0A: L<- HINC+T, :STFULL; ELSE :STMSK
-EM01475> OP1: T<- CYCOUT; OP 1 - SOURCE .OR. DEST
-EM01464> L<- MD OR T, :OPN;
-EM01476> OP2: T<- CYCOUT; OP 2 - SOURCE .XOR. DEST
-EM01465> L<- MD XOR T, :OPN;
-EM01477> OP3: T<- CYCOUT; OP 3 - (NOT SOURCE) .AND. DEST
-EM01466> L<- 0-T-1;
-EM01470> T<- LREG;
-EM01471> L<- MD AND T, :OPN;
-EM01472> OPN: SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
-EM01500> CYCOUT<- L, :AB3;
+EM1474> OP0: SINK<- RETN, BUS; TEST IF UNMASKED
+EM1462> OP0A: L<- HINC+T, :STFULL; ELSE :STMSK
+EM1475> OP1: T<- CYCOUT; OP 1 - SOURCE .OR. DEST
+EM1464> L<- MD OR T, :OPN;
+EM1476> OP2: T<- CYCOUT; OP 2 - SOURCE .XOR. DEST
+EM1465> L<- MD XOR T, :OPN;
+EM1477> OP3: T<- CYCOUT; OP 3 - (NOT SOURCE) .AND. DEST
+EM1466> L<- 0-T-1;
+EM1470> T<- LREG;
+EM1471> L<- MD AND T, :OPN;
+EM1472> OPN: SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
+EM1500> CYCOUT<- L, :AB3;
;
;
; /* STORE MASKED INTO DESTINATION
!1,2,STM2,STM1;
!1,2,AB4,NB4;
-EM01517> STMSK: L<- MD;
-EM01501> SINK<- RETN, BUSODD, TASK; DETERMINE MASK FROM CALL INDEX
-EM01506> TEMP<- L, :STM2; STACHE DEST WORD IN TEMP
-EM01503> STM1: T<-MASK1, :STM3;
-EM01502> STM2: T<-MASK2, :STM3;
-EM01507> STM3: L<- CYCOUT AND T; ***X24. Removed TASK clause.
-EM01510> CYCOUT<- L, L<- 0-T-1; AND INTO SOURCE
-EM01511> T<- LREG; T<- MASK COMPLEMENTED
-EM01512> T<- TEMP .T; AND INTO DEST
-EM01513> L<- CYCOUT OR T; OR TOGETHER THEN GO STORE
-EM01514> SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
-EM01516> CYCOUT<- L, :AB4;
-EM01505> NB4: T<- MAR<- DWAX, :OP0A; (NORMAL BANK)
-EM01504> AB4: T<- XMAR<- DWAX, :OP0A; (ALTERNATE BANK)
+EM1517> STMSK: L<- MD;
+EM1501> SINK<- RETN, BUSODD, TASK; DETERMINE MASK FROM CALL INDEX
+EM1506> TEMP<- L, :STM2; STACHE DEST WORD IN TEMP
+EM1503> STM1: T<-MASK1, :STM3;
+EM1502> STM2: T<-MASK2, :STM3;
+EM1507> STM3: L<- CYCOUT AND T; ***X24. Removed TASK clause.
+EM1510> CYCOUT<- L, L<- 0-T-1; AND INTO SOURCE
+EM1511> T<- LREG; T<- MASK COMPLEMENTED
+EM1512> T<- TEMP .T; AND INTO DEST
+EM1513> L<- CYCOUT OR T; OR TOGETHER THEN GO STORE
+EM1514> SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
+EM1516> CYCOUT<- L, :AB4;
+EM1505> NB4: T<- MAR<- DWAX, :OP0A; (NORMAL BANK)
+EM1504> AB4: T<- XMAR<- DWAX, :OP0A; (ALTERNATE BANK)
;
; /* STORE UNMASKED FROM CYCOUT (L=NEXT DWAX)
-EM01515> STFULL: MD<- CYCOUT;
-EM01520> STFUL1: SINK<- RETN, BUS, TASK;
-EM01521> DWAX<- L, :DON0;
+EM1515> STFULL: MD<- CYCOUT;
+EM1520> STFUL1: SINK<- RETN, BUS, TASK;
+EM1521> DWAX<- L, :DON0;
;
;
; /* WINDOW SOURCE FUNCTION
@@ -1708,27 +1708,27 @@ EM01521> DWAX<- L, :DON0;
!17,1,WIA;
!1,2,NZSK,ZESK;
!1,2,AB5,NB5;
-EM01530> WIND: L<- T<- SKMSK, :AB5; ENTER HERE (8 INST TO TASK)
-EM01527> NB5: MAR<- SWA, :XB5; (NORMAL BANK)
-EM01526> AB5: XMAR<- SWA, :XB5; (ALTERNATE BANK)
-EM01531> XB5: L<- WORD2.T, SH=0;
-EM01532> CYCOUT<- L, L<- 0-T-1, :NZSK; CYCOUT<- OLD WORD .AND. MSK
-EM01525> ZESK: L<- MD, TASK; ZERO SKEW BYPASSES LOTS
-EM01533> CYCOUT<- L, :NOCY;
-EM01524> NZSK: T<- MD;
-EM01534> L<- LREG.T;
-EM01535> TEMP<- L, L<-T, TASK; TEMP<- NEW WORD .AND. NOTMSK
-EM01536> WORD2<- L;
-EM01540> T<- TEMP;
-EM01541> L<- T<- CYCOUT OR T; OR THEM TOGETHER
-EM01542> CYCOUT<- L, L<- 0+1, SH=0; DONT CYCLE A ZERO ***X21.
-EM01543> SINK<- SKEW, BUS, :DOCY;
-EM01522> DOCY: CYRET<- L LSH 1, L<- T, :L0; CYCLE BY SKEW ***X21.
-EM01523> NOCY: T<- SWA, :WIA; (MAY HAVE OR-17 FROM BUS)
-EM00602> CYX2: T<- SWA;
-EM01537> WIA: L<- HINC+T;
-EM01544> SINK<- DISP, SINK<- lgm14, BUS, TASK; DISPATCH TO CALLER
-EM01545> SWA<- L, :F0A;
+EM1530> WIND: L<- T<- SKMSK, :AB5; ENTER HERE (8 INST TO TASK)
+EM1527> NB5: MAR<- SWA, :XB5; (NORMAL BANK)
+EM1526> AB5: XMAR<- SWA, :XB5; (ALTERNATE BANK)
+EM1531> XB5: L<- WORD2.T, SH=0;
+EM1532> CYCOUT<- L, L<- 0-T-1, :NZSK; CYCOUT<- OLD WORD .AND. MSK
+EM1525> ZESK: L<- MD, TASK; ZERO SKEW BYPASSES LOTS
+EM1533> CYCOUT<- L, :NOCY;
+EM1524> NZSK: T<- MD;
+EM1534> L<- LREG.T;
+EM1535> TEMP<- L, L<-T, TASK; TEMP<- NEW WORD .AND. NOTMSK
+EM1536> WORD2<- L;
+EM1540> T<- TEMP;
+EM1541> L<- T<- CYCOUT OR T; OR THEM TOGETHER
+EM1542> CYCOUT<- L, L<- 0+1, SH=0; DONT CYCLE A ZERO ***X21.
+EM1543> SINK<- SKEW, BUS, :DOCY;
+EM1522> DOCY: CYRET<- L LSH 1, L<- T, :L0; CYCLE BY SKEW ***X21.
+EM1523> NOCY: T<- SWA, :WIA; (MAY HAVE OR-17 FROM BUS)
+EM0602> CYX2: T<- SWA;
+EM1537> WIA: L<- HINC+T;
+EM1544> SINK<- DISP, SINK<- lgm14, BUS, TASK; DISPATCH TO CALLER
+EM1545> SWA<- L, :F0A;
; THE DISK CONTROLLER
@@ -1778,146 +1778,146 @@ $INCRECNO $L016013,000000,000000; NDF1 = 13
!1,2,STALL2,GASP;
!1,2,INVERT,NOINVERT;
-SE00004> KSEC: MAR<- KBLKADR2;
-SE01574> KPOQ: CLRSTAT; RESET THE STORED DISK ADDRESS
-SE01575> MD<-L<-ALLONES+1, :GCOM2; ALSO CLEAR DCB POINTER
+SE0004> KSEC: MAR<- KBLKADR2;
+SE1574> KPOQ: CLRSTAT; RESET THE STORED DISK ADDRESS
+SE1575> MD<-L<-ALLONES+1, :GCOM2; ALSO CLEAR DCB POINTER
-SE01576> GETCOM: MAR<-KBLKADR; GET FIRST DCB POINTER
-SE01577> GCOM1: NOP;
-SE01600> L<-MD;
-SE01601> GCOM2: DCBR<-L,TASK;
-SE01602> KCOMM<-TOWTT; IDLE ALL DATA TRANSFERS
+SE1576> GETCOM: MAR<-KBLKADR; GET FIRST DCB POINTER
+SE1577> GCOM1: NOP;
+SE1600> L<-MD;
+SE1601> GCOM2: DCBR<-L,TASK;
+SE1602> KCOMM<-TOWTT; IDLE ALL DATA TRANSFERS
-SE01603> MAR<-KBLKADR3; GENERATE A SECTOR INTERRUPT
-SE01604> T<-NWW;
-SE01605> L<-MD OR T;
+SE1603> MAR<-KBLKADR3; GENERATE A SECTOR INTERRUPT
+SE1604> T<-NWW;
+SE1605> L<-MD OR T;
-SE01606> MAR<-KBLKADR+1; STORE THE STATUS
-SE01607> NWW<-L, TASK;
-SE01610> MD<-KSTAT;
+SE1606> MAR<-KBLKADR+1; STORE THE STATUS
+SE1607> NWW<-L, TASK;
+SE1610> MD<-KSTAT;
-SE01611> MAR<-KBLKADR; WRITE THE CURRENT DCB POINTER
-SE01612> KSTAT<-5; INITIAL STATUS IS INCOMPLETE
-SE01613> L<-DCBR,TASK,BUS=0;
-SE01614> MD<-DCBR, :COMM;
+SE1611> MAR<-KBLKADR; WRITE THE CURRENT DCB POINTER
+SE1612> KSTAT<-5; INITIAL STATUS IS INCOMPLETE
+SE1613> L<-DCBR,TASK,BUS=0;
+SE1614> MD<-DCBR, :COMM;
; BUS=0 MAPS COMM TO NOCOMM
-SE01546> COMM: T<-2; GET THE DISK COMMAND
-SE01615> MAR<-DCBR+T;
-SE01616> T<-TOTUWC;
-SE01617> L<-MD XOR T, TASK, STROBON;
-SE01620> KWDCT<-L, :COMM2;
+SE1546> COMM: T<-2; GET THE DISK COMMAND
+SE1615> MAR<-DCBR+T;
+SE1616> T<-TOTUWC;
+SE1617> L<-MD XOR T, TASK, STROBON;
+SE1620> KWDCT<-L, :COMM2;
; STROBON MAPS COMM2 TO IDLE1
-SE01550> COMM2: T<-10; READ NEW DISK ADDRESS
-SE01621> MAR<-DCBR+T+1;
-SE01622> T<-KWDCT;
-SE01623> L<-ONE AND T;
-SE01624> L<- -400 AND T, SH=0;
-SE01625> T<-MD, SH=0, :INVERT;
+SE1550> COMM2: T<-10; READ NEW DISK ADDRESS
+SE1621> MAR<-DCBR+T+1;
+SE1622> T<-KWDCT;
+SE1623> L<-ONE AND T;
+SE1624> L<- -400 AND T, SH=0;
+SE1625> T<-MD, SH=0, :INVERT;
; SH=0 MAPS INVERT TO NOINVERT
-SE01572> INVERT: L<-2 XOR T, TASK, :BADCOMM;
-SE01573> NOINVERT: L<-T, TASK, :BADCOMM;
+SE1572> INVERT: L<-2 XOR T, TASK, :BADCOMM;
+SE1573> NOINVERT: L<-T, TASK, :BADCOMM;
; SH=0 MAPS BADCOMM TO COMM3
-SE01553> COMM3: KNMAR<-L;
+SE1553> COMM3: KNMAR<-L;
-SE01626> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
-SE01627> T<-SECT2CM; CHECK FOR SECTOR > 13
-SE01630> L<-T<-KDATA<-KNMAR+T; NEW DISK ADDRESS TO HARDWARE
-SE01631> KADR<-KWDCT,ALUCY; DISK COMMAND TO HARDWARE
-SE01632> L<-MD XOR T,TASK, :COMM4; COMPARE OLD AND NEW DISK ADDRESSES
+SE1626> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
+SE1627> T<-SECT2CM; CHECK FOR SECTOR > 13
+SE1630> L<-T<-KDATA<-KNMAR+T; NEW DISK ADDRESS TO HARDWARE
+SE1631> KADR<-KWDCT,ALUCY; DISK COMMAND TO HARDWARE
+SE1632> L<-MD XOR T,TASK, :COMM4; COMPARE OLD AND NEW DISK ADDRESSES
; ALUCY MAPS COMM4 TO ILLSEC
-SE01554> COMM4: CKSUMR<-L;
+SE1554> COMM4: CKSUMR<-L;
-SE01633> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
-SE01634> T<-CADM,SWRNRDY; SEE IF DISK IS READY
-SE01635> L<-CKSUMR AND T, :COMM5;
+SE1633> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
+SE1634> T<-CADM,SWRNRDY; SEE IF DISK IS READY
+SE1635> L<-CKSUMR AND T, :COMM5;
; SWRNRDY MAPS COMM5 TO WHYNRDY
-SE01556> COMM5: MD<-KNMAR; COMPLETE THE WRITE
-SE01636> SH=0,TASK;
-SE01637> :STROB;
+SE1556> COMM5: MD<-KNMAR; COMPLETE THE WRITE
+SE1636> SH=0,TASK;
+SE1637> :STROB;
; SH=0 MAPS STROB TO CKSECT
-SE01561> CKSECT: T<-KNMAR,NFER;
-SE01640> L<-KSTAT XOR T, :STALL;
+SE1561> CKSECT: T<-KNMAR,NFER;
+SE1640> L<-KSTAT XOR T, :STALL;
; NFER MAPS STALL TO CKSECT1
-SE01563> CKSECT1: CKSUMR<-L,XFRDAT;
-SE01641> T<-CKSUMR, :KSFINI;
+SE1563> CKSECT1: CKSUMR<-L,XFRDAT;
+SE1641> T<-CKSUMR, :KSFINI;
; XFRDAT MAPS KSFINI TO CKSECT2
-SE01565> CKSECT2: L<-SECTMSK AND T;
-SE01642> KSLAST: BLOCK,SH=0;
-SE01571> GASP: TASK, :IDLE2;
+SE1565> CKSECT2: L<-SECTMSK AND T;
+SE1642> KSLAST: BLOCK,SH=0;
+SE1571> GASP: TASK, :IDLE2;
; SH=0 MAPS IDLE2 TO TRANSFER
-SE01567> TRANSFER: KCOMM<-TOTUWC; TURN ON THE TRANSFER
+SE1567> TRANSFER: KCOMM<-TOTUWC; TURN ON THE TRANSFER
!1,2,ERRFND,NOERRFND;
!1,2,EF1,NEF1;
-SE01643> DMPSTAT: T<-COMERR1; SEE IF STATUS REPRESENTS ERROR
-SE01650> L<-KSTAT AND T;
-SE01651> MAR<-DCBR+1; WRITE FINAL STATUS
-SE01652> KWDCT<-L,TASK,SH=0;
-SE01653> MD<-KSTAT,:ERRFND;
+SE1643> DMPSTAT: T<-COMERR1; SEE IF STATUS REPRESENTS ERROR
+SE1650> L<-KSTAT AND T;
+SE1651> MAR<-DCBR+1; WRITE FINAL STATUS
+SE1652> KWDCT<-L,TASK,SH=0;
+SE1653> MD<-KSTAT,:ERRFND;
; SH=0 MAPS ERRFND TO NOERRFND
-SE01645> NOERRFND: T<-6; PICK UP NO-ERROR INTERRUPT WORD
+SE1645> NOERRFND: T<-6; PICK UP NO-ERROR INTERRUPT WORD
-SE01654> INTCOM: MAR<-DCBR+T;
-SE01655> T<-NWW;
-SE01656> L<-MD OR T;
-SE01657> SINK<-KWDCT,BUS=0,TASK;
-SE01660> NWW<-L,:EF1;
+SE1654> INTCOM: MAR<-DCBR+T;
+SE1655> T<-NWW;
+SE1656> L<-MD OR T;
+SE1657> SINK<-KWDCT,BUS=0,TASK;
+SE1660> NWW<-L,:EF1;
; BUS=0 MAPS EF1 TO NEF1
-SE01647> NEF1: MAR<-DCBR,:GCOM1; FETCH ADDRESS OF NEXT CONTROL BLOCK
+SE1647> NEF1: MAR<-DCBR,:GCOM1; FETCH ADDRESS OF NEXT CONTROL BLOCK
-SE01644> ERRFND: T<-7,:INTCOM; PICK UP ERROR INTERRUPT WORD
+SE1644> ERRFND: T<-7,:INTCOM; PICK UP ERROR INTERRUPT WORD
-SE01646> EF1: :KSEC;
+SE1646> EF1: :KSEC;
-SE01547> NOCOMM: L<-ALLONES,CLRSTAT,:KSLAST;
+SE1547> NOCOMM: L<-ALLONES,CLRSTAT,:KSLAST;
-SE01551> IDLE1: L<-ALLONES,:KSLAST;
+SE1551> IDLE1: L<-ALLONES,:KSLAST;
-SE01566> IDLE2: KSTAT<-LOW14, :GETCOM; NO ACTIVITY THIS SECTOR
+SE1566> IDLE2: KSTAT<-LOW14, :GETCOM; NO ACTIVITY THIS SECTOR
-SE01552> BADCOMM: KSTAT<-7; ILLEGAL COMMAND ONLY NOTED IN KBLK STAT
-SE01661> BLOCK;
-SE01662> TASK,:EF1;
+SE1552> BADCOMM: KSTAT<-7; ILLEGAL COMMAND ONLY NOTED IN KBLK STAT
+SE1661> BLOCK;
+SE1662> TASK,:EF1;
-SE01557> WHYNRDY: NFER;
-SE01562> STALL: BLOCK, :STALL2;
+SE1557> WHYNRDY: NFER;
+SE1562> STALL: BLOCK, :STALL2;
; NFER MAPS STALL2 TO GASP
-SE01570> STALL2: TASK;
-SE01663> :DMPSTAT;
+SE1570> STALL2: TASK;
+SE1663> :DMPSTAT;
-SE01555> ILLSEC: KSTAT<-7, :STALL; ILLEGAL SECTOR SPECIFIED
+SE1555> ILLSEC: KSTAT<-7, :STALL; ILLEGAL SECTOR SPECIFIED
-SE01560> STROB: CLRSTAT;
-SE01664> L<-ALLONES,STROBE,:CKSECT1;
+SE1560> STROB: CLRSTAT;
+SE1664> L<-ALLONES,STROBE,:CKSECT1;
-SE01564> KSFINI: KSTAT<-4, :STALL; COMMAND FINISHED CORRECTLY
+SE1564> KSFINI: KSTAT<-4, :STALL; COMMAND FINISHED CORRECTLY
;DISK WORD TASK
@@ -1932,154 +1932,154 @@ SE01564> KSFINI: KSTAT<-4, :STALL; COMMAND FINISHED CORRECTLY
!1,2,,CK6;
!1,2,CKSMERR,PXFLP0;
-KW01737> KWD: BLOCK,:REC0;
+KW1737> KWD: BLOCK,:REC0;
; SH<0 MAPS REC0 TO REC0
; ANYTHING=INIT MAPS REC0 TO KWD
-KW01735> REC0: L<-2, TASK; LENGTH OF RECORD 0 (ALLOW RELEASE IF BLOCKED)
-KW01665> KNMARW<-L;
+KW1735> REC0: L<-2, TASK; LENGTH OF RECORD 0 (ALLOW RELEASE IF BLOCKED)
+KW1665> KNMARW<-L;
-KW01702> T<-KNMARW, BLOCK, RWC; GET ADDR OF MEMORY BLOCK TO TRANSFER
-KW01710> MAR<-DCBR+T+1, :REC0RC;
+KW1702> T<-KNMARW, BLOCK, RWC; GET ADDR OF MEMORY BLOCK TO TRANSFER
+KW1710> MAR<-DCBR+T+1, :REC0RC;
; WRITE MAPS REC0RC TO REC0W
; INIT MAPS REC0RC TO KWD
-KW01722> REC0RC: T<-MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY
-KW01723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
+KW1722> REC0RC: T<-MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY
+KW1723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
-KW01714> REC1: L<-10, INCRECNO; LENGTH OF RECORD 1
-KW01715> T<-4, :REC12;
-KW01716> REC2: L<-PAGE1, INCRECNO; LENGTH OF RECORD 2
-KW01725> T<-5, :REC12;
-KW01730> REC12: MAR<-DCBR+T, RWC; MEM BLK ADDR FOR RECORD
-KW01732> KNMARW<-L, :RDCK0;
+KW1714> REC1: L<-10, INCRECNO; LENGTH OF RECORD 1
+KW1715> T<-4, :REC12;
+KW1716> REC2: L<-PAGE1, INCRECNO; LENGTH OF RECORD 2
+KW1725> T<-5, :REC12;
+KW1730> REC12: MAR<-DCBR+T, RWC; MEM BLK ADDR FOR RECORD
+KW1732> KNMARW<-L, :RDCK0;
; RWC=WRITE MAPS RDCK0 INTO WRT0
; RWC=INIT MAPS RDCK0 INTO KWD
-KW01712> RDCK0: T<-MIRRDL, :REC12A;
-KW01713> WRT0: T<-MIR0BL, :REC12A;
+KW1712> RDCK0: T<-MIRRDL, :REC12A;
+KW1713> WRT0: T<-MIR0BL, :REC12A;
-KW01734> REC12A: L<-MD;
-KW01736> KWDCTW<-L, L<-T;
-KW01740> COM1: KCOMM<- STUWC, :INPREF0;
+KW1734> REC12A: L<-MD;
+KW1736> KWDCTW<-L, L<-T;
+KW1740> COM1: KCOMM<- STUWC, :INPREF0;
-KW01701> INPREF: L<-CKSUMRW+1, INIT, BLOCK;
-KW01741> INPREF0: CKSUMRW<-L, SH<0, TASK, :INPREF1;
+KW1701> INPREF: L<-CKSUMRW+1, INIT, BLOCK;
+KW1741> INPREF0: CKSUMRW<-L, SH<0, TASK, :INPREF1;
; INIT MAPS INPREF1 TO KWD
-KW01705> INPREF1: KDATA<-0, :PREFDONE;
+KW1705> INPREF1: KDATA<-0, :PREFDONE;
; SH<0 MAPS PREFDONE TO INPREF
-KW01700> PREFDONE: T<-KNMARW; COMPUTE TOP OF BLOCK TO TRANSFER
-KW00016> KWDX: L<-KWDCTW+T,RWC; (ALSO USED FOR RESET)
-KW01742> KNMARW<-L,BLOCK,:RP0;
+KW1700> PREFDONE: T<-KNMARW; COMPUTE TOP OF BLOCK TO TRANSFER
+KW0016> KWDX: L<-KWDCTW+T,RWC; (ALSO USED FOR RESET)
+KW1742> KNMARW<-L,BLOCK,:RP0;
; RWC=CHECK MAPS RP0 TO CKP0
; RWC=WRITE MAPS RP0 AND CKP0 TO WP0
; RWC=INIT MAPS RP0, CKP0, AND WP0 TO KWD
-KW01704> RP0: KCOMM<-STRCWFS,:WP1;
+KW1704> RP0: KCOMM<-STRCWFS,:WP1;
-KW01706> CKP0: L<-KWDCTW-1; ADJUST FINISHING CONDITION BY 1 FOR CHECKING ONLY
-KW01743> KWDCTW<-L,:RP0;
+KW1706> CKP0: L<-KWDCTW-1; ADJUST FINISHING CONDITION BY 1 FOR CHECKING ONLY
+KW1743> KWDCTW<-L,:RP0;
-KW01707> WP0: KDATA<-ONE; WRITE THE SYNC PATTERN
-KW01744> WP1: L<-KBLKADR,TASK,:RW1; INITIALIZE THE CHECKSUM AND ENTER XFER LOOP
+KW1707> WP0: KDATA<-ONE; WRITE THE SYNC PATTERN
+KW1744> WP1: L<-KBLKADR,TASK,:RW1; INITIALIZE THE CHECKSUM AND ENTER XFER LOOP
-KW01745> XFLP: T<-L<-KNMARW-1; BEGINNING OF MAIN XFER LOOP
-KW01746> KNMARW<-L;
-KW01747> MAR<-KNMARW,RWC;
-KW01750> L<-KWDCTW-T,:R0;
+KW1745> XFLP: T<-L<-KNMARW-1; BEGINNING OF MAIN XFER LOOP
+KW1746> KNMARW<-L;
+KW1747> MAR<-KNMARW,RWC;
+KW1750> L<-KWDCTW-T,:R0;
; RWC=CHECK MAPS R0 TO CK0
; RWC=WRITE MAPS R0 AND CK0 TO W0
; RWC=INIT MAPS R0, CK0, AND W0 TO KWD
-KW01724> R0: T<-CKSUMRW,SH=0,BLOCK;
-KW01751> MD<-L<-KDATA XOR T,TASK,:RW1;
+KW1724> R0: T<-CKSUMRW,SH=0,BLOCK;
+KW1751> MD<-L<-KDATA XOR T,TASK,:RW1;
; SH=0 MAPS RW1 TO RW2
-KW01666> RW1: CKSUMRW<-L,:XFLP;
+KW1666> RW1: CKSUMRW<-L,:XFLP;
-KW01727> W0: T<-CKSUMRW,BLOCK;
-KW01752> KDATA<-L<-MD XOR T,SH=0;
-KW01753> TASK,:RW1;
+KW1727> W0: T<-CKSUMRW,BLOCK;
+KW1752> KDATA<-L<-MD XOR T,SH=0;
+KW1753> TASK,:RW1;
; AS ALREADY NOTED, SH=0 MAPS RW1 TO RW2
-KW01726> CK0: T<-KDATA,BLOCK,SH=0;
-KW01754> L<-MD XOR T,BUS=0,:CK1;
+KW1726> CK0: T<-KDATA,BLOCK,SH=0;
+KW1754> L<-MD XOR T,BUS=0,:CK1;
; SH=0 MAPS CK1 TO CK2
-KW01670> CK1: L<-CKSUMRW XOR T,SH=0,:CK3;
+KW1670> CK1: L<-CKSUMRW XOR T,SH=0,:CK3;
; BUS=0 MAPS CK3 TO CK4
-KW01672> CK3: TASK,:CKERR;
+KW1672> CK3: TASK,:CKERR;
; SH=0 MAPS CKERR TO CK5
-KW01675> CK5: CKSUMRW<-L,:XFLP;
+KW1675> CK5: CKSUMRW<-L,:XFLP;
-KW01673> CK4: MAR<-KNMARW, :CK6;
+KW1673> CK4: MAR<-KNMARW, :CK6;
; SH=0 MAPS CK6 TO CK6
-KW01703> CK6: CKSUMRW<-L,L<-0+T;
-KW01755> MTEMP<-L,TASK;
-KW01756> MD<-MTEMP,:XFLP;
+KW1703> CK6: CKSUMRW<-L,L<-0+T;
+KW1755> MTEMP<-L,TASK;
+KW1756> MD<-MTEMP,:XFLP;
-KW01671> CK2: L<-CKSUMRW-T,:R2;
+KW1671> CK2: L<-CKSUMRW-T,:R2;
; BUS=0 MAPS R2 TO R2
-KW01667> RW2: CKSUMRW<-L;
+KW1667> RW2: CKSUMRW<-L;
-KW01757> T<-KDATA<-CKSUMRW,RWC; THIS CODE HANDLES THE FINAL CHECKSUM
-KW01760> L<-KDATA-T,BLOCK,:R2;
+KW1757> T<-KDATA<-CKSUMRW,RWC; THIS CODE HANDLES THE FINAL CHECKSUM
+KW1760> L<-KDATA-T,BLOCK,:R2;
; RWC=CHECK NEVER GETS HERE
; RWC=WRITE MAPS R2 TO W2
; RWC=INIT MAPS R2 AND W2 TO KWD
-KW01731> R2: L<-MRPAL, SH=0; SET READ POSTAMBLE LENGTH, CHECK CKSUM
-KW01761> KCOMM<-TOTUWC, :CKSMERR;
+KW1731> R2: L<-MRPAL, SH=0; SET READ POSTAMBLE LENGTH, CHECK CKSUM
+KW1761> KCOMM<-TOTUWC, :CKSMERR;
; SH=0 MAPS CKSMERR TO PXFLP0
-KW01733> W2: L<-MWPAL, TASK; SET WRITE POSTAMBLE LENGTH
-KW01762> CKSUMRW<-L, :PXFLP;
+KW1733> W2: L<-MWPAL, TASK; SET WRITE POSTAMBLE LENGTH
+KW1762> CKSUMRW<-L, :PXFLP;
-KW01720> CKSMERR: KSTAT<-0,:PXFLP0; 0 MEANS CHECKSUM ERROR .. CONTINUE
+KW1720> CKSMERR: KSTAT<-0,:PXFLP0; 0 MEANS CHECKSUM ERROR .. CONTINUE
-KW01676> PXFLP: L<-CKSUMRW+1, INIT, BLOCK;
-KW01721> PXFLP0: CKSUMRW<-L, TASK, SH=0, :PXFLP1;
+KW1676> PXFLP: L<-CKSUMRW+1, INIT, BLOCK;
+KW1721> PXFLP0: CKSUMRW<-L, TASK, SH=0, :PXFLP1;
; INIT MAPS PXFLP1 TO KWD
-KW01711> PXFLP1: KDATA<-0,:PXFLP;
+KW1711> PXFLP1: KDATA<-0,:PXFLP;
; SH=0 MAPS PXFLP TO PXF2
-KW01677> PXF2: RECNO, BLOCK; DISPATCH BASED ON RECORD NUMBER
-KW01763> :REC1;
+KW1677> PXF2: RECNO, BLOCK; DISPATCH BASED ON RECORD NUMBER
+KW1763> :REC1;
; RECNO=2 MAPS REC1 INTO REC2
; RECNO=3 MAPS REC1 INTO REC3
; RECNO=INIT MAPS REC1 INTO KWD
-KW01717> REC3: KSTAT<-4,:PXFLP; 4 MEANS SUCCESS!!!
+KW1717> REC3: KSTAT<-4,:PXFLP; 4 MEANS SUCCESS!!!
-KW01674> CKERR: KCOMM<-TOTUWC; TURN OFF DATA TRANSFER
-KW01764> L<-KSTAT<-6, :PXFLP1; SHOW CHECK ERROR AND LOOP
+KW1674> CKERR: KCOMM<-TOTUWC; TURN OFF DATA TRANSFER
+KW1764> L<-KSTAT<-6, :PXFLP1; SHOW CHECK ERROR AND LOOP
;The Parity Error Task
;Its label predefinition is way earlier
@@ -2091,24 +2091,24 @@ KW01764> L<-KSTAT<-6, :PXFLP1; SHOW CHECK ERROR AND LOOP
;620/ PC Emulator program counter
;621/ SAD Emulator temporary register for indirection
-PA00015> PART: T<- 10;
-PA01765> L<- ALLONES; TURN OFF MEMORY INTERRUPTS
-PA01766> MAR<- ERRCTRL, :PX1;
-PA00450> PR8: L<- SAD, :PX;
-PA00447> PR7: L<- PC, :PX;
-PA00446> PR6: L<- CBA, :PX;
-PA00445> PR5: L<- DWA, :PX;
-PA00444> PR4: L<- KNMAR, :PX;
-PA00443> PR3: L<- DCBR, :PX;
-PA00442> PR2: L<- NWW OR T, TASK; T CONTAINS 1 AT THIS POINT
-PA00440> PR0: NWW<- L, :PART;
+PA0015> PART: T<- 10;
+PA1765> L<- ALLONES; TURN OFF MEMORY INTERRUPTS
+PA1766> MAR<- ERRCTRL, :PX1;
+PA0450> PR8: L<- SAD, :PX;
+PA0447> PR7: L<- PC, :PX;
+PA0446> PR6: L<- CBA, :PX;
+PA0445> PR5: L<- DWA, :PX;
+PA0444> PR4: L<- KNMAR, :PX;
+PA0443> PR3: L<- DCBR, :PX;
+PA0442> PR2: L<- NWW OR T, TASK; T CONTAINS 1 AT THIS POINT
+PA0440> PR0: NWW<- L, :PART;
-PA01767> PX: MAR<- 612+T;
-PA01770> PX1: MTEMP<- L, L<- T;
-PA01771> MD<- MTEMP;
-PA01772> CURDATA<- L; THIS CLOBBERS THE CURSOR FOR ONE
-PA01773> T<- CURDATA-1, BUS; FRAME WHEN AN ERROR OCCURS
-PA01774> :PR0;
+PA1767> PX: MAR<- 612+T;
+PA1770> PX1: MTEMP<- L, L<- T;
+PA1771> MD<- MTEMP;
+PA1772> CURDATA<- L; THIS CLOBBERS THE CURSOR FOR ONE
+PA1773> T<- CURDATA-1, BUS; FRAME WHEN AN ERROR OCCURS
+PA1774> :PR0;
AltoIIMRT4K.mu:
;
@@ -2185,48 +2185,48 @@ $EngNumber $30000; ALTO II WITH EXTENDED MEMORY
; MAR_ R37 XOR 200 TOGGLES BIT 8
; MAR_ R37 XOR 202 TOGGLES BITS 8 AND 14
-MR00010> MRT: MAR<- R37; **FIRST REFRESH CYCLE**
-MR00351> SINK<- MOUSE, BUS; MOUSE DATA IS ANDED WITH 17B
-MR00360> MRTA: L<- T<- -2, :TX0; DISPATCH ON MOUSE CHANGE
-MR00340> TX0: L<- R37 AND NOT T, T<- R37;INCREMENT CLOCK
-MR00361> T<- 3+T+1, SH=0; IE. T<- T +4. IS INTV TIMER ON?
-MR00362> L<- REFIIMSK AND T, :DOTIMER; [DOTIMER,NOTIMER] ZERO HIGH 4 BITS
-MR00331> NOTIMER: R37<- L; STORE UPDATED CLOCK
-MR00332> NOTIMERINT: T<- 2; NO STATE AT THIS POINT IN PUBLIC REGS
-MR00363> MAR<- R37 XOR T,T<- R37; **SECOND REFRESH CYCLE**
-MR00364> L<- REFZERO AND T; ONLY THE CLOKCK BITS, PLEASE
-MR00365> SH=0, TASK; TEST FOR CLOCK OVERFLOW
-MR00366> :NOCLK; [NOCLK,CLOCK]
-MR00354> NOCLK: T <- 200;
-MR00367> MAR<- R37 XOR T; **THIRD FEFRESH CYCLE**
-MR00370> L<- CURX, BLOCK; CLEARS WAKEUP REQUEST FF
-MR00371> T<- 2 OR T, SH=0; NEED TO CHECK CURSOR?
-MR00372> MAR<- R37 XOR T, :DOCUR; **FOURTH REFRESH CYCLE**
-MR00335> NOCUR: CURDATA<- L, TASK;
-MR00327> MRTLAST:CURDATA<- L, :MRT; END OF MAIN LOOP
+MR0010> MRT: MAR<- R37; **FIRST REFRESH CYCLE**
+MR0351> SINK<- MOUSE, BUS; MOUSE DATA IS ANDED WITH 17B
+MR0360> MRTA: L<- T<- -2, :TX0; DISPATCH ON MOUSE CHANGE
+MR0340> TX0: L<- R37 AND NOT T, T<- R37;INCREMENT CLOCK
+MR0361> T<- 3+T+1, SH=0; IE. T<- T +4. IS INTV TIMER ON?
+MR0362> L<- REFIIMSK AND T, :DOTIMER; [DOTIMER,NOTIMER] ZERO HIGH 4 BITS
+MR0331> NOTIMER: R37<- L; STORE UPDATED CLOCK
+MR0332> NOTIMERINT: T<- 2; NO STATE AT THIS POINT IN PUBLIC REGS
+MR0363> MAR<- R37 XOR T,T<- R37; **SECOND REFRESH CYCLE**
+MR0364> L<- REFZERO AND T; ONLY THE CLOKCK BITS, PLEASE
+MR0365> SH=0, TASK; TEST FOR CLOCK OVERFLOW
+MR0366> :NOCLK; [NOCLK,CLOCK]
+MR0354> NOCLK: T <- 200;
+MR0367> MAR<- R37 XOR T; **THIRD FEFRESH CYCLE**
+MR0370> L<- CURX, BLOCK; CLEARS WAKEUP REQUEST FF
+MR0371> T<- 2 OR T, SH=0; NEED TO CHECK CURSOR?
+MR0372> MAR<- R37 XOR T, :DOCUR; **FOURTH REFRESH CYCLE**
+MR0335> NOCUR: CURDATA<- L, TASK;
+MR0327> MRTLAST:CURDATA<- L, :MRT; END OF MAIN LOOP
-MR00330> DOTIMER:R37<- L; STORE UPDATED CLOCK
-MR00373> MAR<- EIALOC; INTERVAL TIMER/EIA INTERFACE
-MR00374> L<- 2 AND T;
-MR00375> SH=0, L<- T<- REFZERO.T; ***V3 CHANGE (USED TO BE BIAS)
-MR00376> CURDATA<-L, :SPCHK; CURDATA<- CURRENT TIME WITHOUT CONTROL BITS
+MR0330> DOTIMER:R37<- L; STORE UPDATED CLOCK
+MR0373> MAR<- EIALOC; INTERVAL TIMER/EIA INTERFACE
+MR0374> L<- 2 AND T;
+MR0375> SH=0, L<- T<- REFZERO.T; ***V3 CHANGE (USED TO BE BIAS)
+MR0376> CURDATA<-L, :SPCHK; CURDATA<- CURRENT TIME WITHOUT CONTROL BITS
-MR00352> SPCHK: SINK<- MD, BUS=0, TASK; CHECK FOR EIA LINE SPACING
-MR00377> SPIA: :NOTIMERINT, CLOCKTEMP<- L;
+MR0352> SPCHK: SINK<- MD, BUS=0, TASK; CHECK FOR EIA LINE SPACING
+MR0377> SPIA: :NOTIMERINT, CLOCKTEMP<- L;
-MR00353> NOSPCHK:L<-MD; CHECK FOR TIME = NOW
-MR00400> MAR<-TRAPDISP-1; CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
-MR00401> MTEMP<-L; IF INTERRUPT IS CAUSED,
-MR00402> L<- MD-T; LINE STATE WILL BE STORED
-MR00403> SH=0, TASK, L<-MTEMP, :SPIA;
+MR0353> NOSPCHK:L<-MD; CHECK FOR TIME = NOW
+MR0400> MAR<-TRAPDISP-1; CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
+MR0401> MTEMP<-L; IF INTERRUPT IS CAUSED,
+MR0402> L<- MD-T; LINE STATE WILL BE STORED
+MR0403> SH=0, TASK, L<-MTEMP, :SPIA;
-MR00333> TIMERINT:MAR<- ITQUAN; STORE THE THING IN CLOCKTEMP AT ITQUAN
-MR00404> L<- CURDATA;
-MR00405> R37<- L;
-MR00406> T<-NWW; AND CAUSE AN INTERRUPT ON THE CHANNELS
-MR00407> MD<-CLOCKTEMP; SPECIFIED BY ITQUAN+1
-MR00410> L<-MD OR T, TASK;
-MR00411> NWW<-L,:NOTIMERINT;
+MR0333> TIMERINT:MAR<- ITQUAN; STORE THE THING IN CLOCKTEMP AT ITQUAN
+MR0404> L<- CURDATA;
+MR0405> R37<- L;
+MR0406> T<-NWW; AND CAUSE AN INTERRUPT ON THE CHANNELS
+MR0407> MD<-CLOCKTEMP; SPECIFIED BY ITQUAN+1
+MR0410> L<-MD OR T, TASK;
+MR0411> NWW<-L,:NOTIMERINT;
;The rest of MRT, starting at the label CLOCK is unchanged
diff --git a/Contralto/IO/DiskController.cs b/Contralto/IO/DiskController.cs
index d35edaa..46090ff 100644
--- a/Contralto/IO/DiskController.cs
+++ b/Contralto/IO/DiskController.cs
@@ -16,7 +16,7 @@ namespace Contralto.IO
_pack = new DiabloPack(DiabloDiskType.Diablo31);
// TODO: this does not belong here.
- FileStream fs = new FileStream("Disk\\games.dsk", FileMode.Open, FileAccess.Read);
+ FileStream fs = new FileStream("Disk\\nonprog.dsk", FileMode.Open, FileAccess.Read);
_pack.Load(fs);
@@ -38,6 +38,7 @@ namespace Contralto.IO
set
{
_kDataWrite = value;
+ _kDataWriteLatch = true;
}
}
@@ -48,10 +49,13 @@ namespace Contralto.IO
{
_kAdr = value;
_recNo = 0;
+ _syncWordWritten = false;
// "In addition, it causes the head address bit to be loaded from KDATA[13]."
int newHead = (_kDataWrite & 0x4) >> 2;
-
+
+ _disk = ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1);
+
if (newHead != _head)
{
// If we switch heads, we need to reload the sector
@@ -79,8 +83,24 @@ namespace Contralto.IO
(_kDataWrite & 0x2) >> 1,
(_kDataWrite & 0x1));
- Log.Write(LogComponent.DiskController, " -Selected disk is {0}", ((_kDataWrite & 0x2) >> 1) ^ (_kAdr & 0x1));
+ Log.Write(LogComponent.DiskController, " -Selected disk is {0}", _disk);
+ if (((_kAdr & 0xc) >> 2) == 2 ||
+ ((_kAdr & 0xc) >> 2) == 3)
+ {
+ Console.WriteLine("DATA WRITE");
+ }
+
+ if (_disk != 0)
+ {
+ Console.WriteLine("*** DISK 1 SELECTED ***");
+ }
+
+ if ((_kDataWrite & 0x1) != 0)
+ {
+ // Restore operation to cyl. 0:
+ InitSeek(0);
+ }
}
}
@@ -121,7 +141,8 @@ namespace Contralto.IO
{
get
{
- // Bits 4-7 of KSTAT are always 1s.
+ // Bits 4-7 of KSTAT are always 1s (it's a shortcut allowing the disk microcode to write
+ // "-1" to bits 4-7 of the disk status word at 522 without extra code.)
return (ushort)(_kStat | (0x0f00));
}
set
@@ -139,12 +160,7 @@ namespace Contralto.IO
{
get { return _dataXfer; }
}
-
- ///
- /// This is a hack to see how the microcode expects INIT to work
- ///
-
-
+
public int Cylinder
{
get { return _cylinder; }
@@ -179,9 +195,8 @@ namespace Contralto.IO
{
get
{
- // TODO: verify if this is correct.
- // Not ready if we're in the middle of a seek.
- return (_kStat & 0x0040) == 0;
+ // TODO: verify what generates this signal
+ return true;
}
}
@@ -192,9 +207,11 @@ namespace Contralto.IO
_cylinder = _destCylinder = 0;
_sector = 0;
_head = 0;
+ _disk = 0;
_kStat = 0;
_kDataRead = 0;
_kDataWrite = 0;
+ _kDataWriteLatch = false;
_sendAdr = false;
_wdInhib = true;
@@ -202,6 +219,9 @@ namespace Contralto.IO
_wdInit = false;
+ _syncWordWritten = false;
+ _sectorModified = false;
+
_diskBitCounterEnable = false;
_sectorWordIndex = 0;
@@ -229,7 +249,14 @@ namespace Contralto.IO
}
private void SectorCallback(ulong timeNsec, ulong skewNsec, object context)
- {
+ {
+ // Write last sector out if it was modified
+ if (_sectorModified)
+ {
+ CommitSector();
+ _sectorModified = false;
+ }
+
//
// Next sector; move to next sector and wake up Disk Sector task.
//
@@ -238,9 +265,10 @@ namespace Contralto.IO
_kStat = (ushort)((_kStat & 0x0fff) | (_sector << 12));
// Reset internal state machine for sector data
- _sectorWordIndex = 0;
+ _sectorWordIndex = 0;
+ _syncWordWritten = false;
- _kDataRead = 0;
+ _kDataRead = 0;
// Load new sector in
LoadSector();
@@ -346,6 +374,8 @@ namespace Contralto.IO
_kAdr = (ushort)(_kAdr << 2);
_recNo++;
+ _syncWordWritten = false;
+
if (_recNo > 3)
{
// sanity check for now
@@ -370,7 +400,12 @@ namespace Contralto.IO
Log.Write(LogComponent.DiskController, "STROBE: Seek initialized.");
- _destCylinder = (_kDataWrite & 0x0ff8) >> 3;
+ InitSeek((_kDataWrite & 0x0ff8) >> 3);
+ }
+
+ private void InitSeek(int destCylinder)
+ {
+ _destCylinder = destCylinder;
// set "seek fail" bit based on selected cylinder (if out of bounds) and do not
// commence a seek if so.
@@ -395,7 +430,7 @@ namespace Contralto.IO
_seekEvent.TimestampNsec = _seekDuration;
_system.Scheduler.Schedule(_seekEvent);
-
+
Log.Write(LogComponent.DiskController, "Seek to {0} from {1} commencing. Will take {2} nsec.", _destCylinder, _cylinder, _seekDuration);
}
}
@@ -411,7 +446,7 @@ namespace Contralto.IO
//
double seekTimeMsec = 15.0 + 8.6 * Math.Sqrt(dt);
- return (ulong)(seekTimeMsec * Conversion.MsecToNsec); // hack to speed things up
+ return (ulong)(seekTimeMsec * Conversion.MsecToNsec);
}
///
@@ -465,16 +500,47 @@ namespace Contralto.IO
{
if (!_xferOff)
{
- // Debugging: on a read/check, if we are overwriting a word that was never read by the
- // microcode via KDATA, log it.
- if (_debugRead && (((KADR & 0x00c0) >> 6) == 0 || ((KADR & 0x00c0) >> 6) == 1))
+ if (!IsWrite())
{
- Console.WriteLine("--- missed sector word {0}({1}) ---", _sectorWordIndex, _kDataRead);
- }
+ // Read operation:
+ // Debugging: on a read/check, if we are overwriting a word that was never read by the
+ // microcode via KDATA, log it.
+ if (_debugRead)
+ {
+ Console.WriteLine("--- missed sector word {0}({1}) ---", _sectorWordIndex, _kDataRead);
+ }
- Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, Conversion.ToOctal(diskWord));
- _kDataRead = diskWord;
- _debugRead = _sectorData[_sectorWordIndex].Type == CellType.Data;
+ Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Sector {0} Word {1} read into KDATA", _sector, Conversion.ToOctal(diskWord));
+ _kDataRead = diskWord;
+ _debugRead = _sectorData[_sectorWordIndex].Type == CellType.Data;
+ }
+ else
+ {
+ // Write
+ Log.Write(LogType.Normal, LogComponent.DiskController, "Sector {0} Word {1} (rec {2}) to be written with {3} from KDATA", _sector, _sectorWordIndex, _recNo, Conversion.ToOctal(_kDataWrite));
+
+ if (_kDataWriteLatch)
+ {
+ _kDataRead = _kDataWrite;
+ _kDataWriteLatch = false;
+ }
+
+ if (_syncWordWritten && _sectorWordIndex < _sectorData.Length)
+ {
+ if (_sectorData[_sectorWordIndex].Type == CellType.Data)
+ {
+ Console.WriteLine("Data written to data section.");
+ _sectorData[_sectorWordIndex].Data = _kDataWrite;
+ }
+ else
+ {
+ Console.WriteLine("Data written to non-data section.");
+ _sectorData[_sectorWordIndex].Data = _kDataWrite;
+ }
+
+ _sectorModified = true;
+ }
+ }
}
if (!_wdInhib)
@@ -489,16 +555,38 @@ namespace Contralto.IO
// the clock. This occurs late in the cycle so that the NEXT word
// (not the sync word) is actually read. TODO: this should only happen on reads.
//
- if (!_wffo && diskWord == 1)
+ if (!IsWrite() && !_wffo && diskWord == 1)
{
_diskBitCounterEnable = true;
}
+ else if (IsWrite() && _wffo && _kDataWrite == 1 && !_syncWordWritten)
+ {
+ Log.Write(LogType.Normal, LogComponent.DiskController, "Sector {0} Sync Word {1} (rec {2}) written.", _sector, _sectorWordIndex, _recNo);
+ _syncWordWritten = true;
+
+ // "Adjust" the write index to the start of the data area for the current record.
+ // This is cheating.
+ switch(_recNo)
+ {
+ case 0:
+ _sectorWordIndex = _headerOffset;
+ break;
+
+ case 1:
+ _sectorWordIndex = _labelOffset;
+ break;
+
+ case 2:
+ _sectorWordIndex = _dataOffset;
+ break;
+ }
+ }
if (bWakeup)
{
Log.Write(LogType.Verbose, LogComponent.DiskWordTask, "Word task awoken for word {0}.", _sectorWordIndex);
_system.CPU.WakeupTask(TaskType.DiskWord);
- }
+ }
// Last, move to the next word.
_sectorWordIndex++;
@@ -549,6 +637,37 @@ namespace Contralto.IO
}
+ ///
+ /// Commits modified sector data back to the emulated disk.
+ /// Intended to be called at the end of the sector / beginning of the next.
+ /// TODO: we should modify this so that checksums are persisted, possibly...
+ ///
+ private void CommitSector()
+ {
+ DiabloDiskSector sector = _pack.GetSector(_cylinder, _head, _sector);
+
+ // Header (2 words data, 1 word cksum)
+ for (int i = _headerOffset + 1, j = 1; i < _headerOffset + 3; i++, j--)
+ {
+ // actual data to be loaded from disk / cksum calculated
+ sector.Header[j] = _sectorData[i].Data;
+ }
+
+ // Label (8 words data, 1 word cksum)
+ for (int i = _labelOffset + 1, j = 7; i < _labelOffset + 9; i++, j--)
+ {
+ // actual data to be loaded from disk / cksum calculated
+ sector.Label[j] = _sectorData[i].Data;
+ }
+
+ // sector data (256 words data, 1 word cksum)
+ for (int i = _dataOffset + 1, j = 255; i < _dataOffset + 257; i++, j--)
+ {
+ // actual data to be loaded from disk / cksum calculated
+ sector.Data[j] = _sectorData[i].Data;
+ }
+ }
+
private void InitSector()
{
// Fill in sector with default data (basically, fill in non-data areas).
@@ -576,7 +695,7 @@ namespace Contralto.IO
_sectorData[_dataOffset] = new DataCell(1, CellType.Sync);
// read-postamble
- for (int i = _dataOffset + 257; i < _sectorWordCount;i++)
+ for (int i = _dataOffset + 258; i < _sectorWordCount;i++)
{
_sectorData[i] = new DataCell(0, CellType.Gap);
}
@@ -606,8 +725,14 @@ namespace Contralto.IO
return checksum;
}
+ private bool IsWrite()
+ {
+ return ((_kAdr & 0x00c0) >> 6) == 2 || ((_kAdr & 0x00c0) >> 6) == 3;
+ }
+
private ushort _kDataRead;
private ushort _kDataWrite;
+ private bool _kDataWriteLatch;
private ushort _kAdr;
private ushort _kCom;
private ushort _kStat;
@@ -634,12 +759,18 @@ namespace Contralto.IO
private int _head;
private int _sector;
+ // Selected disk
+ private int _disk;
+
// bit clock flag
private bool _diskBitCounterEnable;
// WDINIT signal
private bool _wdInit;
+ private bool _syncWordWritten;
+ private bool _sectorModified;
+
// Sector timing. Based on table on pg. 43 of the Alto Hardware Manual
// From altoconsts23.mu: [all constants in octal, for reference]
diff --git a/Contralto/Logging/Log.cs b/Contralto/Logging/Log.cs
index a7f0264..ddfd896 100644
--- a/Contralto/Logging/Log.cs
+++ b/Contralto/Logging/Log.cs
@@ -44,7 +44,7 @@ namespace Contralto.Logging
static Log()
{
// TODO: make configurable
- _components = LogComponent.Memory; // LogComponent.DiskController | LogComponent.DiskSectorTask;
+ _components = LogComponent.DiskController | LogComponent.DiskSectorTask;
_type = LogType.Normal | LogType.Warning | LogType.Error;
}
diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs
index d47d6da..2d36c92 100644
--- a/Contralto/Memory/Memory.cs
+++ b/Contralto/Memory/Memory.cs
@@ -38,7 +38,7 @@ namespace Contralto.Memory
if (extendedMemory)
{
Log.Write(LogComponent.Memory, "Extended memory read, bank {0} address {1}, read {2}", GetBankNumber(task, extendedMemory), Conversion.ToOctal(address), Conversion.ToOctal(_mem[address + 0x10000 * GetBankNumber(task, extendedMemory)]));
- } */
+ } */
address += 0x10000 * GetBankNumber(task, extendedMemory);
return _mem[address];
}
@@ -62,7 +62,8 @@ namespace Contralto.Memory
{
Log.Write(LogComponent.Memory, "Extended memory write, bank {0} address {1}, data {2}", GetBankNumber(task, extendedMemory), Conversion.ToOctal(address), Conversion.ToOctal(data));
} */
- address += 0x10000 * GetBankNumber(task, extendedMemory);
+ address += 0x10000 * GetBankNumber(task, extendedMemory);
+
_mem[address] = data;
}
}
diff --git a/Contralto/Program.cs b/Contralto/Program.cs
index a969247..d79f369 100644
--- a/Contralto/Program.cs
+++ b/Contralto/Program.cs
@@ -11,7 +11,8 @@ namespace Contralto
// for now everything is driven through the debugger
Debugger d = new Debugger(system);
system.AttachDisplay(d);
- d.LoadSourceCode("Disassembly\\altoIIcode3.mu");
+ d.LoadSourceCode(MicrocodeBank.ROM0, "Disassembly\\altoIIcode3.mu");
+ d.LoadSourceCode(MicrocodeBank.ROM1, "Disassembly\\MesaROM.mu");
d.ShowDialog();
}