diff --git a/AGC/Memory/IMemoryBus.cs b/AGC/Memory/IMemoryBus.cs new file mode 100644 index 0000000..332fcae --- /dev/null +++ b/AGC/Memory/IMemoryBus.cs @@ -0,0 +1,16 @@ +namespace Apollo.Virtual.AGC.Memory +{ + public interface IMemoryBus + { + OnesCompliment this[ushort a] { get; set; } + int MaxAddress { get; } + + /// + /// The AGC has memory mapped registerss, so they need a method to regiser themselves to the MemoryBus + /// + /// + /// + /// + RegisterType MapRegister(ushort address) where RegisterType : MemoryWord; + } +} \ No newline at end of file diff --git a/AGC/MemoryMap.cs b/AGC/MemoryMap.cs index 0e818de..5283114 100644 --- a/AGC/MemoryMap.cs +++ b/AGC/MemoryMap.cs @@ -1,8 +1,10 @@ using Apollo.Virtual.AGC.Memory; +using System; +using System.Diagnostics; namespace Apollo.Virtual.AGC { - public class MemoryMap + public class MemoryMap : IMemoryBus { const uint EB_Address = 0x03; const uint FB_Address = 0x04; @@ -34,7 +36,7 @@ public class MemoryMap /// /// Divided into 8 (E0 - E7) banks controlled by register EB or BB /// - private MemoryBank[] switchedErasable = new MemoryBank[] + private MemoryBank[] switchedErasable = new MemoryBank[] { new MemoryBank(256, 0x300), new MemoryBank(256, 0x300), @@ -79,19 +81,15 @@ public class MemoryMap /// private MemoryBank ioChannels = new MemoryBank(512); + public int MaxAddress => throw new NotImplementedException(); + public OnesCompliment this[ushort a] { - get - { - return GetWord(a).Read(); - } - set - { - GetWord(a).Write(value); - } + get => GetWord(a).Read(); + set => GetWord(a).Write(value); } - public IWord GetWord(ushort address) + private IWord GetWord(ushort address) { // registers if (address <= 0x031) @@ -100,7 +98,7 @@ public IWord GetWord(ushort address) int bank = 0; // look at bits in address to determine appropriate bank and memory type - switch(address & 0xF00) + switch (address & 0xF00) { case 0x000: case 0x100: @@ -144,11 +142,13 @@ public IWord GetWord(ushort address) /// /// /// - internal RegisterType AddRegister(ushort address) where RegisterType : MemoryWord + RegisterType IMemoryBus.MapRegister(ushort address) { // reflectively get constructor that takes memory bank and call it var constructor = typeof(RegisterType).GetConstructor(new[] { typeof(ushort), typeof(MemoryBank) }); + Debug.Assert(constructor != null, $"Register of type {typeof(RegisterType).Name} does not have usable constructor"); + var r = constructor.Invoke(new object[] { address, unswitchedErasable }) as RegisterType; // add to memory space and return the object created diff --git a/AGC/Processor.cs b/AGC/Processor.cs index 923bd68..bf7e2fd 100644 --- a/AGC/Processor.cs +++ b/AGC/Processor.cs @@ -1,4 +1,6 @@ -using Apollo.Virtual.AGC.Memory; +using AGC; +using Apollo.Virtual.AGC.Instructions; +using Apollo.Virtual.AGC.Memory; using Apollo.Virtual.AGC.Registers; namespace Apollo.Virtual.AGC @@ -10,10 +12,10 @@ namespace Apollo.Virtual.AGC /// public class Processor { - internal MemoryMap Memory; + internal IMemoryBus Memory; - private InstructionSet instructions; - private ExtraCodeInstructionSet extraCodeInstructions; + private readonly InstructionList standardInstructions; + private readonly InstructionList extraCodeInstructions; /// /// used to allow more than 8 instruction codes @@ -215,60 +217,60 @@ public class Processor #endregion - public Processor(MemoryMap memory) + public Processor(IMemoryBus memory) { this.Memory = memory; - instructions = new InstructionSet(); - extraCodeInstructions = new ExtraCodeInstructionSet(); + standardInstructions = StandardInstructions.Build(this); + extraCodeInstructions = ExtraInstructions.Build(this); // configure registers // main registers? - A = memory.AddRegister(0x00); - L = memory.AddRegister(0x01); - Q = memory.AddRegister(0x02); - EB = memory.AddRegister(0x03); - FB = memory.AddRegister(0x4); - Z = memory.AddRegister(0x05); - BB = memory.AddRegister(0x06); + A = memory.MapRegister(0x00); + L = memory.MapRegister(0x01); + Q = memory.MapRegister(0x02); + EB = memory.MapRegister(0x03); + FB = memory.MapRegister(0x4); + Z = memory.MapRegister(0x05); + BB = memory.MapRegister(0x06); //memory[0x7] = 0; // this is always set to 0, TODO: need to hard code? // interrupt helper registers - ARUPT = memory.AddRegister(0x08); - LRUPT = memory.AddRegister(0x09); - QRUPT = memory.AddRegister(0x0A); + ARUPT = memory.MapRegister(0x08); + LRUPT = memory.MapRegister(0x09); + QRUPT = memory.MapRegister(0x0A); // 0XB, 0XC are spares. not used? - ZRUPT = memory.AddRegister(0x0D); - BBRUPT = memory.AddRegister(0x0E); - BRUPT = memory.AddRegister(0x0F); + ZRUPT = memory.MapRegister(0x0D); + BBRUPT = memory.MapRegister(0x0E); + BRUPT = memory.MapRegister(0x0F); // editing registers - CYR = memory.AddRegister(0x10); - SR = memory.AddRegister(0x11); - CYL = memory.GetWord(0x12); - EDOP = memory.GetWord(0x13); + CYR = memory.MapRegister(0x10); + SR = memory.MapRegister(0x11); + CYL = memory.MapRegister(0x12); // temp + EDOP = memory.MapRegister(0x13); // temp // time registers - TIME2 = memory.GetWord(0x14); - TIME1 = memory.GetWord(0x15); - TIME3 = memory.GetWord(0x16); - TIME4 = memory.GetWord(0x17); - TIME5 = memory.GetWord(0x18); - TIME6 = memory.GetWord(0x19); + TIME2 = memory.MapRegister(0x14); // temp + TIME1 = memory.MapRegister(0x15); // temp + TIME3 = memory.MapRegister(0x16); // temp + TIME4 = memory.MapRegister(0x17); // temp + TIME5 = memory.MapRegister(0x18); // temp + TIME6 = memory.MapRegister(0x19); // temp // orientation registers - CDUX = memory.AddRegister(0x1A); - CDUY = memory.AddRegister(0x1B); - CDUZ = memory.AddRegister(0x1C); - OPTY = memory.AddRegister(0x1D); - OPTX = memory.AddRegister(0x1E); - PIPAX = memory.AddRegister(0x1F); - PIPAY = memory.AddRegister(0x20); - PIPAZ = memory.AddRegister(0x21); + CDUX = memory.MapRegister(0x1A); + CDUY = memory.MapRegister(0x1B); + CDUZ = memory.MapRegister(0x1C); + OPTY = memory.MapRegister(0x1D); + OPTX = memory.MapRegister(0x1E); + PIPAX = memory.MapRegister(0x1F); + PIPAY = memory.MapRegister(0x20); + PIPAZ = memory.MapRegister(0x21); // LM Only Pitch, Yaw, and Roll registers - INLINK = memory.AddRegister(0x25); + INLINK = memory.MapRegister(0x25); // prime Z to start at the boot interrupt Z.Write(new OnesCompliment(0x800)); @@ -277,13 +279,15 @@ public Processor(MemoryMap memory) public void Execute() { // get address of instruction to run - var address = Memory.GetWord(Z.Read().NativeValue); + ushort address = Z.Read().NativeValue; // update Z Z.Increment(); + // get instruction + ushort instruction = Memory[address].NativeValue; // we only care about 15-bit instructions - var instruction = address.Read() & 0x7FFF; + instruction &= 0x7FFF; var code = (ushort)(instruction >> 12); var K = (ushort)(instruction & 0xFFF); @@ -292,7 +296,6 @@ public void Execute() if (ExtraCodeFlag) { // reset CPU for instruction to execute - extraCodeInstructions[code].CPU = this; extraCodeInstructions[code].Execute(K); // clear the extra code flag @@ -301,8 +304,7 @@ public void Execute() else { // reset CPU for instruction to execute - instructions[code].CPU = this; - instructions[code].Execute(K); + standardInstructions[code].Execute(K); } } }