diff --git a/Contralto/CPU/ALU.cs b/Contralto/CPU/ALU.cs index 3db19f1..fac3b2b 100644 --- a/Contralto/CPU/ALU.cs +++ b/Contralto/CPU/ALU.cs @@ -6,7 +6,10 @@ using System.Threading.Tasks; namespace Contralto.CPU { - // From Alto Hardware Manual, Section 2.1 + // + // This implements the stripped-down version of the 74181 ALU + // that the Alto exposes to the microcode, and nothing more. + // static class ALU { static ALU() @@ -14,14 +17,87 @@ namespace Contralto.CPU _lastCarry = 0; } - - - public static ushort Execute(AluFunction fn, ushort a, ushort b) + public int Carry { - - return 0; + get { return _lastCarry; } } - private static ushort _lastCarry; + public static ushort Execute(AluFunction fn, ushort bus, ushort t) + { + int r = 0; + switch (fn) + { + case AluFunction.Bus: + _lastCarry = 0; // M = 1 + r = bus; + break; + + case AluFunction.T: + _lastCarry = 0; // M = 1 + r= t; + break; + + case AluFunction.BusOrT: + _lastCarry = 0; // M = 1 + r = (bus | t); + break; + + case AluFunction.BusAndT: + case AluFunction.AluBusAndT: + _lastCarry = 0; // M = 1 + r = (bus & t); + break; + + case AluFunction.BusXorT: + _lastCarry = 0; // M = 1 + r = (bus ^ t); + break; + + case AluFunction.BusPlus1: + r = bus + 1; + _lastCarry = (r > 0xffff) ? 1 : 0; + break; + + case AluFunction.BusMinus1: + r = bus - 1; + _lastCarry = (r < 0) ? 1 : 0; + break; + + case AluFunction.BusPlusT: + r = bus + t; + _lastCarry = (r > 0xffff) ? 1 : 0; + break; + + case AluFunction.BusMinusT: + r = bus - t; + _lastCarry = (r < 0) ? 1 : 0; + break; + + case AluFunction.BusMinusTMinus1: + r = bus - t - 1; + _lastCarry = (r < 0) ? 1 : 0; + break; + + case AluFunction.BusPlusTPlus1: + r = bus + t + 1; + _lastCarry = (r > 0xffff) ? 1 : 0; + break; + + case AluFunction.BusPlusSkip: + throw new NotImplementedException("SKIP?"); + + case AluFunction.BusAndNotT: + r = bus & (~t); + _lastCarry = 0; + break; + + default: + throw new InvalidOperationException(String.Format("Unhandled ALU function {0}", fn)); + } + + return (ushort)r; + } + + private static int _lastCarry; } } diff --git a/Contralto/CPU/CPU.cs b/Contralto/CPU/CPU.cs index 7dc8967..dfc8157 100644 --- a/Contralto/CPU/CPU.cs +++ b/Contralto/CPU/CPU.cs @@ -1,4 +1,5 @@ -using System; +using Contralto.Memory; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -41,6 +42,9 @@ namespace Contralto.CPU _currentTask = _nextTask; _nextTask = null; + + // test + _l = ConstantMemory.ConstantROM[0]; } public void ExecuteNext() @@ -80,7 +84,7 @@ namespace Contralto.CPU // Base task class: provides implementation for non-task-specific microcode execution and // state. Task subclasses implement and execute Task-specific behavior and are called into // by the base class as necessary. - private class Task + private abstract class Task { public Task(AltoCPU cpu) { @@ -164,7 +168,7 @@ namespace Contralto.CPU break; case BusSource.ReadMD: - busData = Memory.MD; + busData = MemoryBus.ReadMD(); break; case BusSource.ReadMouse: @@ -215,7 +219,7 @@ namespace Contralto.CPU break; case SpecialFunction1.LoadMAR: - Memory.LoadMAR(aluData); // Start main memory reference + MemoryBus.LoadMAR(aluData); // Start main memory reference break; case SpecialFunction1.Task: @@ -297,7 +301,7 @@ namespace Contralto.CPU break; case SpecialFunction2.StoreMD: - Memory.StoreMD(busData); + MemoryBus.StoreMD(busData); break; case SpecialFunction2.Constant: @@ -307,6 +311,7 @@ namespace Contralto.CPU default: // Let the specific task implementation take a crack at this. ExecuteSpecialFunction2((int)instruction.F1); + break; } // diff --git a/Contralto/CPU/ConstantMemory.cs b/Contralto/CPU/ConstantMemory.cs index 1de60cb..e96d046 100644 --- a/Contralto/CPU/ConstantMemory.cs +++ b/Contralto/CPU/ConstantMemory.cs @@ -49,18 +49,52 @@ namespace Contralto.CPU // OR in the data for (int i = 0; i < length; i++) { - _constantRom[file.StartingAddress + i] |= (ushort)((data[AddressMap(i)] & 0xf) << file.BitPosition); + _constantRom[file.StartingAddress + i] |= (ushort)((DataMap(data[AddressMap(i)]) & 0xf) << file.BitPosition); } } } + + // And invert all bits + for (int i = 0; i < _constantRom.Length; i++) + { + _constantRom[i] = (ushort)((~_constantRom[i]) & 0xffff); + } } private static int AddressMap(int address) - { - int mappedAddress = (~address) & 0xff; + { + // Descramble the address bits as they are in no sane order. + // (See 05a_AIM.pdf, pg. 5 (Page 9 of the orginal docs)) + int[] addressMapping = { 7, 2, 1, 0, 3, 4, 5, 6 }; + + int mappedAddress = 0; + + for (int i = 0; i < addressMapping.Length; i++) + { + if ((address & (1 << i)) != 0) + { + mappedAddress |= (1 << (addressMapping[i])); + } + } return mappedAddress; } + private static int DataMap(int data) + { + // Reverse bits 0-4. + int mappedData = 0; + + for (int i = 0; i < 4; i++) + { + if ((data & (1 << i)) != 0) + { + mappedData |= (1 << (3-i)); + } + } + + return mappedData; + } + private static RomFile[] _constantRoms = { new RomFile("c0", 0x000, 12), @@ -69,6 +103,6 @@ namespace Contralto.CPU new RomFile("c3", 0x000, 0), }; - private static UInt16[] _constantRom; + private static ushort[] _constantRom; } } diff --git a/Contralto/CPU/MicroInstruction.cs b/Contralto/CPU/MicroInstruction.cs index ca284fb..9f61efc 100644 --- a/Contralto/CPU/MicroInstruction.cs +++ b/Contralto/CPU/MicroInstruction.cs @@ -49,20 +49,21 @@ namespace Contralto.CPU public enum AluFunction { Bus = 0, - BusOrT = 1, - BusAndT = 2, - BusXorT = 3, - BusPlus1 = 4, - BusMinus1 = 5, - BusPlusT = 6, - BusMinusT = 7, - BusMinusTMinus1 = 8, - BusPlusTPlus1 = 9, - BusPlusSkip = 10, - AluBusAndT = 11, - BusAndNotT = 12, - Undefined1 = 13, - Undefined2 = 14, + T = 1, + BusOrT = 2, + BusAndT = 3, + BusXorT = 4, + BusPlus1 = 5, + BusMinus1 = 6, + BusPlusT = 7, + BusMinusT = 8 , + BusMinusTMinus1 = 9, + BusPlusTPlus1 = 10, + BusPlusSkip = 11, + AluBusAndT = 12, + BusAndNotT = 13, + Undefined1 = 14, + Undefined2 = 15, } public class MicroInstruction diff --git a/Contralto/Contralto.csproj b/Contralto/Contralto.csproj index 006ea30..6a03537 100644 --- a/Contralto/Contralto.csproj +++ b/Contralto/Contralto.csproj @@ -47,22 +47,25 @@ + + + - PreserveNewest + Always - PreserveNewest + Always + + + Always - PreserveNewest - - - PreserveNewest + Always PreserveNewest diff --git a/Contralto/Memory/IMemoryMappedDevice.cs b/Contralto/Memory/IMemoryMappedDevice.cs new file mode 100644 index 0000000..4c67253 --- /dev/null +++ b/Contralto/Memory/IMemoryMappedDevice.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contralto.Memory +{ + public interface IMemoryMappedDevice + { + ushort Read(int address); + + void Load(int address, ushort data); + } +} diff --git a/Contralto/Memory/Memory.cs b/Contralto/Memory/Memory.cs new file mode 100644 index 0000000..e643195 --- /dev/null +++ b/Contralto/Memory/Memory.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contralto.Memory +{ + public class Memory : IMemoryMappedDevice + { + public Memory() + { + _mem = new ushort[0xffff]; + } + + public ushort Read(int address) + { + return _mem[address]; + } + + public void Load(int address, ushort data) + { + _mem[address] = data; + } + + private ushort[] _mem; + } +} diff --git a/Contralto/Memory/MemoryBus.cs b/Contralto/Memory/MemoryBus.cs new file mode 100644 index 0000000..134e299 --- /dev/null +++ b/Contralto/Memory/MemoryBus.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Contralto.Memory +{ + public static class MemoryBus + { + static MemoryBus() + { + _mem = new Memory(); + _memoryCycle = 0; + _memoryAddress = 0; + _memoryData = 0; + _memoryOperationActive = false; + } + + public static void Clock() + { + if (_memoryOperationActive) + { + _memoryCycle++; + + switch (_memoryCycle) + { + case 3: + _memoryData = ReadFromBus(_memoryAddress); + break; + + case 4: + _memoryData2 = ReadFromBus(_memoryAddress ^ 1); + break; + + case 6: + _memoryOperationActive = false; + _doubleWordStore = false; + _memoryCycle = 0; + break; + } + } + } + + public static void LoadMAR(ushort address) + { + if (_memoryOperationActive) + { + // TODO: stall CPU + } + else + { + _memoryOperationActive = true; + _doubleWordStore = false; + _memoryAddress = address; + _memoryCycle = 1; + } + } + + public static ushort ReadMD() + { + if (_memoryOperationActive) + { + switch (_memoryCycle) + { + case 1: + case 2: + // TODO: good microcode should never do this + 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. + + break; + + case 5: + // Single word read + return _memoryData; + + case 6: // TODO: rectify with timing (doubleword read extends cycle to 6) + // Doubleword read: + return _memoryData2; + + default: + // Invalid state. + throw new InvalidOperationException(string.Format("Unexpected memory cycle {0} in memory state machine.", _memoryCycle)); + } + } + else + { + // not running, just return last latched contents + return _memoryData; + } + } + + public static void LoadMD(ushort data) + { + if (_memoryOperationActive) + { + switch (_memoryCycle) + { + case 1: + 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; + + case 3: + // Start of doubleword write: + WriteToBus(_memoryAddress, data); + _doubleWordStore = true; + break; + + case 4: + WriteToBus(_doubleWordStore ? _memoryAddress ^ 1 : _memoryAddress, data); + break; + } + + } + } + + + private static Memory _mem; + private static bool _memoryOperationActive; + private static int _memoryCycle; + private static ushort _memoryAddress; + + // Buffered read data (on cycles 3 and 4) + private static ushort _memoryData; + private static ushort _memoryData2; + + // Indicates a double-word store (started on cycle 3) + private static bool _doubleWordStore; + } +} diff --git a/Contralto/Program.cs b/Contralto/Program.cs index 483af07..1ccebbc 100644 --- a/Contralto/Program.cs +++ b/Contralto/Program.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Contralto.CPU; +using Contralto.Memory; namespace Contralto { @@ -16,6 +17,7 @@ namespace Contralto while(true) { + MemoryBus.Clock(); cpu.ExecuteNext(); } diff --git a/Contralto/ROM/C2 b/Contralto/ROM/C2 new file mode 100644 index 0000000..68e488e Binary files /dev/null and b/Contralto/ROM/C2 differ diff --git a/Contralto/ROM/C3 b/Contralto/ROM/C3 index 68e488e..9c5cc18 100644 Binary files a/Contralto/ROM/C3 and b/Contralto/ROM/C3 differ diff --git a/Contralto/ROM/C4 b/Contralto/ROM/C4 deleted file mode 100644 index 9c5cc18..0000000 Binary files a/Contralto/ROM/C4 and /dev/null differ