From 03661fc90bb35f5fcaafe74e5a1822d50216cd33 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Mon, 16 Nov 2015 16:46:24 -0800 Subject: [PATCH] Fixed display microcode and display controller. Alto display now generated 100% by microcode tasks. A few small optimizations. --- Contralto/AltoSystem.cs | 9 ++- Contralto/CPU/CPU.cs | 19 +---- Contralto/CPU/Tasks/DisplayHorizontalTask.cs | 12 ++- Contralto/CPU/Tasks/DisplayWordTask.cs | 10 ++- Contralto/Debugger.Designer.cs | 14 ---- Contralto/Debugger.cs | 14 ++-- Contralto/Display/DisplayController.cs | 85 +++++++++++--------- Contralto/Display/FakeDisplayController.cs | 2 +- Contralto/Logging/Log.cs | 2 +- Contralto/Memory/Memory.cs | 36 +++------ Contralto/Memory/MemoryBus.cs | 61 ++++++++++---- 11 files changed, 138 insertions(+), 126 deletions(-) diff --git a/Contralto/AltoSystem.cs b/Contralto/AltoSystem.cs index a87b36f..4d77140 100644 --- a/Contralto/AltoSystem.cs +++ b/Contralto/AltoSystem.cs @@ -25,7 +25,7 @@ namespace Contralto _keyboard = new Keyboard(); _diskController = new DiskController(this); _displayController = new DisplayController(this); - _fakeDisplayController = new FakeDisplayController(this); + //_fakeDisplayController = new FakeDisplayController(this); // Attach memory-mapped devices to the bus _memBus.AddDevice(_mem); @@ -36,7 +36,7 @@ namespace Contralto _clockableDevices.Add(_memBus); _clockableDevices.Add(_diskController); _clockableDevices.Add(_displayController); - _clockableDevices.Add(_fakeDisplayController); + //_clockableDevices.Add(_fakeDisplayController); _clockableDevices.Add(_cpu); Reset(); @@ -62,13 +62,14 @@ namespace Contralto public void AttachDisplay(Debugger d) { _displayController.AttachDisplay(d); - _fakeDisplayController.AttachDisplay(d); + // _fakeDisplayController.AttachDisplay(d); } public void SingleStep() { // Run every device that needs attention for a single clock cycle. - for (int i = 0; i < _clockableDevices.Count; i++) + int count = _clockableDevices.Count; + for (int i = 0; i < count; i++) { _clockableDevices[i].Clock(); } diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 51705bd..66cd539 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -31,27 +31,14 @@ namespace Contralto.CPU _tasks[(int)TaskType.Emulator] = new EmulatorTask(this); _tasks[(int)TaskType.DiskSector] = new DiskTask(this, true); _tasks[(int)TaskType.DiskWord] = new DiskTask(this, false); - //_tasks[(int)TaskType.DisplayWord] = new DisplayWordTask(this); - //_tasks[(int)TaskType.DisplayHorizontal] = new DisplayHorizontalTask(this); + _tasks[(int)TaskType.DisplayWord] = new DisplayWordTask(this); + _tasks[(int)TaskType.DisplayHorizontal] = new DisplayHorizontalTask(this); _tasks[(int)TaskType.DisplayVertical] = new DisplayVerticalTask(this); _tasks[(int)TaskType.Cursor] = new CursorTask(this); _tasks[(int)TaskType.MemoryRefresh] = new MemoryRefreshTask(this); Reset(); - } - - public void Hack() - { - _tasks[(int)TaskType.DisplayWord] = new DisplayWordTask(this); - //_tasks[(int)TaskType.DisplayHorizontal] = new DisplayHorizontalTask(this); - //_tasks[(int)TaskType.DisplayVertical] = new DisplayVerticalTask(this); - //_tasks[(int)TaskType.Cursor] = new CursorTask(this); - - _tasks[(int)TaskType.DisplayWord].Reset(); - //_tasks[(int)TaskType.DisplayHorizontal].Reset(); - //_tasks[(int)TaskType.DisplayVertical].Reset(); - //_tasks[(int)TaskType.Cursor].Reset(); - } + } public Task[] Tasks { diff --git a/Contralto/CPU/Tasks/DisplayHorizontalTask.cs b/Contralto/CPU/Tasks/DisplayHorizontalTask.cs index 0ff1e7e..231e19c 100644 --- a/Contralto/CPU/Tasks/DisplayHorizontalTask.cs +++ b/Contralto/CPU/Tasks/DisplayHorizontalTask.cs @@ -17,8 +17,16 @@ namespace Contralto.CPU { _taskType = TaskType.DisplayHorizontal; _wakeup = false; - } - + } + + protected override bool ExecuteInstruction(MicroInstruction instruction) + { + // We put ourselves back to sleep immediately once we've started running + _wakeup = false; + + return base.ExecuteInstruction(instruction); + } + protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { DisplayHorizontalF2 dh2 = (DisplayHorizontalF2)instruction.F2; diff --git a/Contralto/CPU/Tasks/DisplayWordTask.cs b/Contralto/CPU/Tasks/DisplayWordTask.cs index 88bc108..6727f62 100644 --- a/Contralto/CPU/Tasks/DisplayWordTask.cs +++ b/Contralto/CPU/Tasks/DisplayWordTask.cs @@ -18,7 +18,15 @@ namespace Contralto.CPU { _taskType = TaskType.DisplayWord; _wakeup = false; - } + } + + protected override bool ExecuteInstruction(MicroInstruction instruction) + { + // We put ourselves back to sleep immediately once we've started running + _wakeup = false; + + return base.ExecuteInstruction(instruction); + } protected override void ExecuteSpecialFunction2(MicroInstruction instruction) { diff --git a/Contralto/Debugger.Designer.cs b/Contralto/Debugger.Designer.cs index 58e4a88..b7076b7 100644 --- a/Contralto/Debugger.Designer.cs +++ b/Contralto/Debugger.Designer.cs @@ -110,7 +110,6 @@ this.NovaStep = new System.Windows.Forms.Button(); this.groupBox6 = new System.Windows.Forms.GroupBox(); this.DisplayBox = new System.Windows.Forms.PictureBox(); - this.button1 = new System.Windows.Forms.Button(); this.Microcode.SuspendLayout(); this.SourceTabs.SuspendLayout(); this.Rom0Page.SuspendLayout(); @@ -960,23 +959,11 @@ this.DisplayBox.TabStop = false; this.DisplayBox.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.DisplayBox_PreviewKeyDown); // - // button1 - // - this.button1.Location = new System.Drawing.Point(799, 873); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 1; - this.button1.TabStop = false; - this.button1.Text = "HACK"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - // // Debugger // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1376, 997); - this.Controls.Add(this.button1); this.Controls.Add(this.groupBox6); this.Controls.Add(this.NovaStep); this.Controls.Add(this.RunToNextTaskButton); @@ -1071,7 +1058,6 @@ private System.Windows.Forms.DataGridViewTextBoxColumn Disassembly; private System.Windows.Forms.GroupBox groupBox6; private System.Windows.Forms.PictureBox DisplayBox; - private System.Windows.Forms.Button button1; private System.Windows.Forms.TabControl SourceTabs; private System.Windows.Forms.TabPage Rom0Page; private System.Windows.Forms.TabPage Rom1Page; diff --git a/Contralto/Debugger.cs b/Contralto/Debugger.cs index b168f85..5ca4306 100644 --- a/Contralto/Debugger.cs +++ b/Contralto/Debugger.cs @@ -89,6 +89,8 @@ namespace Contralto _displayBuffer.UnlockBits(data); DisplayBox.Refresh(); + + Array.Clear(_displayData, 0, _displayData.Length); } /// @@ -833,7 +835,7 @@ namespace Contralto break; } - + if (_execAbort || // The Stop button was hit _microcodeBreakpointEnabled[_system.CPU.CurrentTask.MPC] || // A microcode breakpoint was hit (execType == ExecutionType.NextTask && @@ -855,7 +857,7 @@ namespace Contralto _execAbort = false; break; - } + } } } @@ -1031,12 +1033,6 @@ namespace Contralto private Rectangle _displayRect = new Rectangle(0, 0, 608, 808); // Keyboard mapping from windows vkeys to Alto keys - private Dictionary _keyMap; - - private void button1_Click(object sender, EventArgs e) - { - _system.CPU.Hack(); - } - + private Dictionary _keyMap; } } diff --git a/Contralto/Display/DisplayController.cs b/Contralto/Display/DisplayController.cs index c7340cb..450dd83 100644 --- a/Contralto/Display/DisplayController.cs +++ b/Contralto/Display/DisplayController.cs @@ -35,8 +35,16 @@ namespace Contralto.Display _state = DisplayState.VerticalBlank; _scanline = 0; _word = 0; - _dwtBlocked = false; + _dwtBlocked = true; _dhtBlocked = false; + + _whiteOnBlack = false; + _lowRes = false; + + // Wakeup DVT + _system.CPU.WakeupTask(TaskType.DisplayVertical); + _system.CPU.BlockTask(TaskType.DisplayHorizontal); + _system.CPU.BlockTask(TaskType.DisplayWord); } public void Clock() @@ -63,13 +71,16 @@ namespace Contralto.Display // // Check the BLOCK status of the DWT and DHT tasks for the last executed uInstruction. // - _dhtBlocked = _system.CPU.CurrentTask.Priority == (int)CPU.TaskType.DisplayHorizontal && - _system.CPU.CurrentTask.BLOCK; + + if (_system.CPU.CurrentTask.Priority == (int)CPU.TaskType.DisplayHorizontal && + _system.CPU.CurrentTask.BLOCK) + { + _dhtBlocked = true; + } if (_system.CPU.CurrentTask.Priority == (int)CPU.TaskType.DisplayWord && _system.CPU.CurrentTask.BLOCK) - { - //Console.WriteLine("DWT BLOCK"); + { _dwtBlocked = true; // @@ -88,23 +99,12 @@ namespace Contralto.Display // "If the DWT has not executed a BLOCK, if DHT is not blocked, and if the // buffer is not full, DWT wakeups are generated." // - if (_dataBuffer.Count < 16 && - !_system.CPU.IsBlocked(TaskType.DisplayHorizontal) && + if (_dataBuffer.Count < 16 && + !_dhtBlocked && !_dwtBlocked) - { - //Console.WriteLine("DWT wakeup, {0}", _dataBuffer.Count); + { _system.CPU.WakeupTask(TaskType.DisplayWord); - } - else - { - // We can't take any words right now, remove Wakeup from - // the DWT. - if (_dataBuffer.Count >= 16) - { - //Log.Write(LogComponent.Display, "buffer full, blocking DWT."); - } - _system.CPU.BlockTask(TaskType.DisplayWord); - } + } switch (_state) { @@ -112,7 +112,7 @@ namespace Contralto.Display // Just killing time if (_clocks > _verticalBlankClocks) { - // End of VBlank + // End of VBlank, start new visible frame _clocks -= _verticalBlankClocks; _scanline = _evenField ? 0 : 1; _word = 0; @@ -121,12 +121,9 @@ namespace Contralto.Display // Wake up DVT, DHT _dwtBlocked = false; _dhtBlocked = false; - _system.CPU.WakeupTask(TaskType.DisplayHorizontal); - _system.CPU.BlockTask(TaskType.DisplayWord); + _system.CPU.WakeupTask(TaskType.DisplayHorizontal); - _state = DisplayState.HorizontalBlank; - - //Console.WriteLine("Frame"); + _state = DisplayState.HorizontalBlank; } break; @@ -139,14 +136,14 @@ namespace Contralto.Display { _clocks -= _wordClocks; - ushort displayWord = 0xaaaa; + ushort displayWord = (ushort)(_whiteOnBlack ? 0 : 0xffff); if (_dataBuffer.Count > 0) { // Dequeue a word and draw it to the screen - displayWord = _dataBuffer.Dequeue(); + displayWord = _whiteOnBlack ? _dataBuffer.Dequeue() : (ushort)~_dataBuffer.Dequeue(); } - //_display.DrawDisplayWord(_scanline, _word, displayWord); + _display.DrawDisplayWord(_scanline, _word, displayWord); _word++; if (_word > 37) @@ -154,7 +151,7 @@ namespace Contralto.Display // Done with this line _dwtBlocked = false; _dataBuffer.Clear(); - _state = DisplayState.HorizontalBlank; + _state = DisplayState.HorizontalBlank; } } break; @@ -170,7 +167,7 @@ namespace Contralto.Display _word = 0; if (_scanline > 807) - { + { // Done with field, move to vblank, tell display to render _state = DisplayState.VerticalBlank; _evenField = !_evenField; @@ -178,13 +175,13 @@ namespace Contralto.Display // Wakeup DVT _system.CPU.WakeupTask(TaskType.DisplayVertical); - // Block DHT + // Block DHT, DWT _system.CPU.BlockTask(TaskType.DisplayHorizontal); _system.CPU.BlockTask(TaskType.DisplayWord); - //_display.RefreshAltoDisplay(); + _display.RefreshAltoDisplay(); - _frames++; + _fields++; //Log.Write(LogComponent.Display, "Display field completed. {0} total clocks elapsed.", _totalClocks); _totalClocks = 0; } @@ -204,16 +201,22 @@ namespace Contralto.Display { _dataBuffer.Enqueue(word); - //Console.WriteLine("Enqueue {0}", _dataBuffer.Count); + //Console.WriteLine("Enqueue {0}, scanline {1}", word, _scanline); // Sanity check: data length should never exceed 16 words. if (_dataBuffer.Count > 16) - { - _dataBuffer.Dequeue(); - _system.CPU.BlockTask(TaskType.DisplayWord); + { + //_dataBuffer.Dequeue(); + //_system.CPU.BlockTask(TaskType.DisplayWord); } } + public void SETMODE(ushort word) + { + _lowRes = (word & 0x8000) != 0; + _whiteOnBlack = (word & 0x4000) != 0; + } + public bool EVENFIELD { get { return _evenField; } @@ -228,15 +231,17 @@ namespace Contralto.Display } private bool _evenField; + private bool _lowRes; + private bool _whiteOnBlack; private double _clocks; private double _totalClocks; - private int _frames; + private int _fields; private DisplayState _state; // Indicates whether the DWT or DHT blocked itself // in which case they cannot be reawakened until the next field. private bool _dwtBlocked; - private bool _dhtBlocked; + private bool _dhtBlocked; private int _scanline; private int _word; diff --git a/Contralto/Display/FakeDisplayController.cs b/Contralto/Display/FakeDisplayController.cs index bebc790..4dcbb23 100644 --- a/Contralto/Display/FakeDisplayController.cs +++ b/Contralto/Display/FakeDisplayController.cs @@ -98,7 +98,7 @@ namespace Contralto.Display _display.DrawDisplayWord(scanline, wordOffset, (ushort)(dcb.whiteOnBlack ? 0x0 : 0xffff)); } - //_display.RefreshAltoDisplay(); + _display.RefreshAltoDisplay(); // decrement scan line counter for this DCB, if < 0, grab next DCB. dcb.scanlineCount--; diff --git a/Contralto/Logging/Log.cs b/Contralto/Logging/Log.cs index cc5af43..0a4066c 100644 --- a/Contralto/Logging/Log.cs +++ b/Contralto/Logging/Log.cs @@ -48,7 +48,7 @@ namespace Contralto.Logging static Log() { // TODO: make configurable - _components = LogComponent.All; + _components = LogComponent.None; _type = LogType.Normal | LogType.Warning | LogType.Error; } diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs index ae6a595..6706f49 100644 --- a/Contralto/Memory/Memory.cs +++ b/Contralto/Memory/Memory.cs @@ -15,6 +15,14 @@ namespace Contralto.Memory Reset(); } + /// + /// The top address of main memory (above which lies the I/O space) + /// + public static ushort MemTop + { + get { return _memTop; } + } + public void Reset() { // 4 64K banks @@ -33,13 +41,6 @@ namespace Contralto.Memory { address += 0x10000 * GetBankNumber(task, extendedMemory); ushort data = _mem[address]; - - /* - if (extendedMemory) - { - Log.Write(LogComponent.Memory, "extended memory read from {0} - {1}", Conversion.ToOctal(address), Conversion.ToOctal(data)); - } */ - return data; } } @@ -58,18 +59,7 @@ namespace Contralto.Memory else { address += 0x10000 * GetBankNumber(task, extendedMemory); - _mem[address] = data; - - if (address == 0x110 && data != 0) - { - Console.WriteLine("DASTART WRITE!"); - } - - /* - if (extendedMemory) - { - Log.Write(LogComponent.Memory, "extended memory write to {0} of {1}", Conversion.ToOctal(address), Conversion.ToOctal(data)); - } */ + _mem[address] = data; } } @@ -85,12 +75,12 @@ namespace Contralto.Memory private readonly MemoryRange[] _addresses = { - new MemoryRange(0, _memTop), // Main bank of RAM to 176777; IO page above this. - new MemoryRange(_xmBanksStart, _xmBanksStart + 16), // Memory bank registers + new MemoryRange(0, _memTop), // Main bank of RAM to 176777; IO page above this. + new MemoryRange(_xmBanksStart, (ushort)(_xmBanksStart + 16)), // Memory bank registers }; - private const int _memTop = 0xfdff; // 176777 - private const int _xmBanksStart = 0xffe0; // 177740 + private static readonly ushort _memTop = 0xfdff; // 176777 + private static readonly ushort _xmBanksStart = 0xffe0; // 177740 private ushort[] _mem; diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs index 653b801..dfa833e 100644 --- a/Contralto/Memory/MemoryBus.cs +++ b/Contralto/Memory/MemoryBus.cs @@ -42,6 +42,11 @@ namespace Contralto.Memory else { _bus.Add(addr, dev); + + if (dev is Memory) + { + _mainMemory = (Memory)dev; + } } } } @@ -269,17 +274,27 @@ namespace Contralto.Memory /// private ushort ReadFromBus(ushort address, TaskType task, bool extendedMemoryReference) { - // Look up address in hash; if populated ask the device - // to return a value otherwise throw. - if (_bus.ContainsKey(address)) + if (address <= Memory.MemTop) { - return _bus[address].Read(address, task, extendedMemoryReference); + // Main memory access; shortcut hashtable lookup for performance reasons. + return _mainMemory.Read(address, task, extendedMemoryReference); } else { - //throw new NotImplementedException(String.Format("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address))); - //Console.WriteLine("Read from unimplemented memory-mapped I/O device at {0}.", Conversion.ToOctal(address)); - return 0; + // Memory-mapped device access: + // Look up address in hash; if populated ask the device + // to return a value otherwise throw. + IMemoryMappedDevice memoryMappedDevice = null; + if (_bus.TryGetValue(address, out memoryMappedDevice)) + { + return memoryMappedDevice.Read(address, task, extendedMemoryReference); + } + else + { + //throw new NotImplementedException(String.Format("Read from unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address))); + //Console.WriteLine("Read from unimplemented memory-mapped I/O device at {0}.", Conversion.ToOctal(address)); + return 0; + } } } @@ -291,16 +306,26 @@ namespace Contralto.Memory /// private void WriteToBus(ushort address, ushort data, TaskType task, bool extendedMemoryReference) { - // Look up address in hash; if populated ask the device - // to store a value otherwise throw. - if (_bus.ContainsKey(address)) - { - _bus[address].Load(address, data, task, extendedMemoryReference); + if (address <= Memory.MemTop) + { + // Main memory access; shortcut hashtable lookup for performance reasons. + _mainMemory.Load(address, data, task, extendedMemoryReference); } else { - // throw new NotImplementedException(String.Format("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address))); - //Console.WriteLine("Write to unimplemented memory-mapped I/O device at {0}.", Conversion.ToOctal(address)); + // Memory-mapped device access: + // Look up address in hash; if populated ask the device + // to store a value otherwise throw. + IMemoryMappedDevice memoryMappedDevice = null; + if (_bus.TryGetValue(address, out memoryMappedDevice)) + { + memoryMappedDevice.Load(address, data, task, extendedMemoryReference); + } + else + { + // throw new NotImplementedException(String.Format("Write to unimplemented memory-mapped I/O device at {0}.", OctalHelpers.ToOctal(address))); + //Console.WriteLine("Write to unimplemented memory-mapped I/O device at {0}.", Conversion.ToOctal(address)); + } } } @@ -308,7 +333,13 @@ namespace Contralto.Memory /// Hashtable used for address-based dispatch to devices on the memory bus. /// private Dictionary _bus; - + + // + // Optimzation: keep reference to main memory; since 99.9999% of accesses go directly there, + // we can avoid the hashtable overhead using a simple address check. + // + private Memory _mainMemory; + private bool _memoryOperationActive; private int _memoryCycle; private ushort _memoryAddress;