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