From 9c3ee3afacaf0daf7ab7af01cdd5c5eef3352ec5 Mon Sep 17 00:00:00 2001 From: Josh Dersch Date: Fri, 21 Aug 2015 17:12:28 -0700 Subject: [PATCH] Tweaks to ALU, CPU, Memory --- Contralto/CPU/ALU.cs | 32 +++++------ Contralto/CPU/CPU.cs | 22 +++++-- Contralto/Memory/MemoryBus.cs | 105 ++++++++++++++++++++++++++++------ 3 files changed, 120 insertions(+), 39 deletions(-) diff --git a/Contralto/CPU/ALU.cs b/Contralto/CPU/ALU.cs index fac3b2b..deceb0f 100644 --- a/Contralto/CPU/ALU.cs +++ b/Contralto/CPU/ALU.cs @@ -14,12 +14,12 @@ namespace Contralto.CPU { static ALU() { - _lastCarry = 0; + _carry = 0; } - public int Carry + public static int Carry { - get { return _lastCarry; } + get { return _carry; } } public static ushort Execute(AluFunction fn, ushort bus, ushort t) @@ -28,59 +28,59 @@ namespace Contralto.CPU switch (fn) { case AluFunction.Bus: - _lastCarry = 0; // M = 1 + _carry = 0; // M = 1 r = bus; break; case AluFunction.T: - _lastCarry = 0; // M = 1 + _carry = 0; // M = 1 r= t; break; case AluFunction.BusOrT: - _lastCarry = 0; // M = 1 + _carry = 0; // M = 1 r = (bus | t); break; case AluFunction.BusAndT: case AluFunction.AluBusAndT: - _lastCarry = 0; // M = 1 + _carry = 0; // M = 1 r = (bus & t); break; case AluFunction.BusXorT: - _lastCarry = 0; // M = 1 + _carry = 0; // M = 1 r = (bus ^ t); break; case AluFunction.BusPlus1: r = bus + 1; - _lastCarry = (r > 0xffff) ? 1 : 0; + _carry = (r > 0xffff) ? 1 : 0; break; case AluFunction.BusMinus1: r = bus - 1; - _lastCarry = (r < 0) ? 1 : 0; + _carry = (r < 0) ? 1 : 0; break; case AluFunction.BusPlusT: r = bus + t; - _lastCarry = (r > 0xffff) ? 1 : 0; + _carry = (r > 0xffff) ? 1 : 0; break; case AluFunction.BusMinusT: r = bus - t; - _lastCarry = (r < 0) ? 1 : 0; + _carry = (r < 0) ? 1 : 0; break; case AluFunction.BusMinusTMinus1: r = bus - t - 1; - _lastCarry = (r < 0) ? 1 : 0; + _carry = (r < 0) ? 1 : 0; break; case AluFunction.BusPlusTPlus1: r = bus + t + 1; - _lastCarry = (r > 0xffff) ? 1 : 0; + _carry = (r > 0xffff) ? 1 : 0; break; case AluFunction.BusPlusSkip: @@ -88,7 +88,7 @@ namespace Contralto.CPU case AluFunction.BusAndNotT: r = bus & (~t); - _lastCarry = 0; + _carry = 0; break; default: @@ -98,6 +98,6 @@ namespace Contralto.CPU return (ushort)r; } - private static int _lastCarry; + private static int _carry; } } diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index dfc8157..a4fa88f 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -43,8 +43,6 @@ namespace Contralto.CPU _currentTask = _nextTask; _nextTask = null; - // test - _l = ConstantMemory.ConstantROM[0]; } public void ExecuteNext() @@ -141,7 +139,20 @@ namespace Contralto.CPU ushort busData = 0; // from BUS ushort aluData = 0; // from ALU bool nextTask = false; - ushort nextModifier = 0; // for branches (OR'd into NEXT field) + ushort nextModifier = 0; // for branches (OR'd into NEXT field) + + // + // Wait for memory state machine if a memory operation is requested by this instruction and + // the memory isn't ready yet. + // + if ((instruction.BS == BusSource.ReadMD || + instruction.F1 == SpecialFunction1.LoadMAR || + instruction.F2 == SpecialFunction2.StoreMD) + && !MemoryBus.Ready()) + { + // Suspend operation for this cycle. + return false; + } // Select BUS data. if (instruction.F1 != SpecialFunction1.Constant && @@ -168,6 +179,7 @@ namespace Contralto.CPU break; case BusSource.ReadMD: + // TODO: wait for MD if not ready. busData = MemoryBus.ReadMD(); break; @@ -301,7 +313,7 @@ namespace Contralto.CPU break; case SpecialFunction2.StoreMD: - MemoryBus.StoreMD(busData); + MemoryBus.LoadMD(busData); break; case SpecialFunction2.Constant: @@ -345,7 +357,7 @@ namespace Contralto.CPU _cpu._l = aluData; // Save ALUC0 for use in the next ALUCY special function. - _cpu._aluC0 = ALU.Carry; + _cpu._aluC0 = (ushort)ALU.Carry; } // Do shifter diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs index 134e299..8664e3b 100644 --- a/Contralto/Memory/MemoryBus.cs +++ b/Contralto/Memory/MemoryBus.cs @@ -6,6 +6,13 @@ using System.Threading.Tasks; namespace Contralto.Memory { + public enum MemoryOperation + { + LoadAddress, + Read, + Load + } + public static class MemoryBus { static MemoryBus() @@ -19,34 +26,65 @@ namespace Contralto.Memory public static void Clock() { + _memoryCycle++; if (_memoryOperationActive) - { - _memoryCycle++; - + { switch (_memoryCycle) { case 3: + // Buffered read of single word _memoryData = ReadFromBus(_memoryAddress); break; case 4: - _memoryData2 = ReadFromBus(_memoryAddress ^ 1); + // Buffered read of double-word + _memoryData2 = ReadFromBus((ushort)(_memoryAddress ^ 1)); break; - case 6: + case 5: + // End of memory operation _memoryOperationActive = false; - _doubleWordStore = false; - _memoryCycle = 0; + _doubleWordStore = false; break; } } } + public static bool Ready(MemoryOperation op) + { + if (_memoryOperationActive) + { + switch (op) + { + case MemoryOperation.LoadAddress: + // Can't start a new Load operation until the current one is finished. + return false; + + case MemoryOperation.Read: + // Read operations take place on cycles 5 and 6 + return _memoryCycle > 4; + + case MemoryOperation.Load: + // Write operations take place on cycles 3 and 4 + return _memoryCycle > 2; + + default: + throw new InvalidOperationException(String.Format("Unexpected memory operation {0}", op)); + } + } + else + { + // Nothing running right now, we're ready for anything. + return true; + } + } + public static void LoadMAR(ushort address) { if (_memoryOperationActive) { - // TODO: stall CPU + // This should not happen; CPU should check whether the operation is possible using Ready and stall if not. + throw new InvalidOperationException("Invalid LoadMAR request during active memory operation."); } else { @@ -69,17 +107,17 @@ namespace Contralto.Memory throw new InvalidOperationException("Unexpected microcode behavior -- ReadMD too soon after start of memory cycle."); case 3: case 4: - // TODO: not ready yet; need to tell CPU to wait. - + // This should not happen; CPU should check whether the operation is possible using Ready and stall if not. + throw new InvalidOperationException("Invalid ReadMR request during cycle 3 or 4 of memory operation."); break; case 5: // Single word read return _memoryData; - case 6: // TODO: rectify with timing (doubleword read extends cycle to 6) - // Doubleword read: - return _memoryData2; + // *** + // NB: Handler for double-word read (cycle 6) is in the "else" clause below; this is kind of a hack. + // *** default: // Invalid state. @@ -88,8 +126,18 @@ namespace Contralto.Memory } else { - // not running, just return last latched contents - return _memoryData; + // memory state machine not running, just return last latched contents. + // ("Because the Alto II latches memory contents, it is possible to execute _MD anytime after + // cycle 5 of a reference and obtain the results of the read operation") + // If this is memory cycle 6 we will return the last half of the doubleword to complete a double-word read. + if (_memoryCycle == 6) + { + return _memoryData2; + } + else + { + return _memoryData; + } } } @@ -103,8 +151,7 @@ namespace Contralto.Memory case 2: case 5: // TODO: good microcode should never do this - throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD too soon after start of memory cycle."); - break; + throw new InvalidOperationException("Unexpected microcode behavior -- LoadMD during incorrect memory cycle."); case 3: // Start of doubleword write: @@ -113,13 +160,35 @@ namespace Contralto.Memory break; case 4: - WriteToBus(_doubleWordStore ? _memoryAddress ^ 1 : _memoryAddress, data); + WriteToBus(_doubleWordStore ? (ushort)(_memoryAddress ^ 1) : _memoryAddress, data); break; } } } + /// + /// Dispatches reads to memory mapped hardware (RAM, I/O) + /// + /// + /// + private static ushort ReadFromBus(ushort address) + { + // TODO: actually dispatch to I/O + return _mem.Read(address); + } + + /// + /// Dispatches writes to memory mapped hardware (RAM, I/O + /// + /// + /// + /// + private static void WriteToBus(ushort address, ushort data) + { + _mem.Load(address, data); + } + private static Memory _mem; private static bool _memoryOperationActive;