diff options
Diffstat (limited to 'Q1.core')
| -rw-r--r-- | Q1.core/Arch/AddressingMode.cs | 13 | ||||
| -rw-r--r-- | Q1.core/Arch/AddressingModes.cs | 331 | ||||
| -rw-r--r-- | Q1.core/Arch/Chip.cs | 143 | ||||
| -rw-r--r-- | Q1.core/Arch/ChipLayout.cs | 12 | ||||
| -rw-r--r-- | Q1.core/Arch/IInstruction.cs | 35 | ||||
| -rw-r--r-- | Q1.core/Arch/InstructionSet.cs | 203 | ||||
| -rw-r--r-- | Q1.core/GlobalUsings.cs | 12 | ||||
| -rw-r--r-- | Q1.core/IAddressable.cs | 26 | ||||
| -rw-r--r-- | Q1.core/Memory.cs | 15 | ||||
| -rw-r--r-- | Q1.core/Q1.core.csproj | 9 |
10 files changed, 799 insertions, 0 deletions
diff --git a/Q1.core/Arch/AddressingMode.cs b/Q1.core/Arch/AddressingMode.cs new file mode 100644 index 0000000..190439b --- /dev/null +++ b/Q1.core/Arch/AddressingMode.cs @@ -0,0 +1,13 @@ +namespace Q1.core.Arch; + +public record struct AddressingMode +{ + public string Name; + public u8 SizeB; + public u8 SizeW; + + public Func<Chip, u8> LoadByte; + public Func<Chip, u16> LoadWord; + public Action<Chip, u8> StoreByte; + public Action<Chip, u16> StoreWord; +}
\ No newline at end of file diff --git a/Q1.core/Arch/AddressingModes.cs b/Q1.core/Arch/AddressingModes.cs new file mode 100644 index 0000000..206ee4f --- /dev/null +++ b/Q1.core/Arch/AddressingModes.cs @@ -0,0 +1,331 @@ +namespace Q1.core.Arch; + +public static class AddressingModes +{ + public static AddressingMode[] Lookup = new AddressingMode[8]; + + static AddressingModes() + { + AddressingModes.Lookup[0x00] = new AddressingMode + { + Name = "Implicit", + SizeB = 0, + SizeW = 0, + LoadByte = AddressingModes.ImplicitLoadByte, + LoadWord = AddressingModes.ImplicitLoadWord, + StoreByte = AddressingModes.ImplicitStoreByte, + StoreWord = AddressingModes.ImplicitStoreWord + }; + + AddressingModes.Lookup[0x01] = new AddressingMode + { + Name = "Immediate", + SizeB = 1, + SizeW = 2, + LoadByte = AddressingModes.ImmediateLoadByte, + LoadWord = AddressingModes.ImmediateLoadWord, + StoreByte = AddressingModes.ImmediateStoreByte, + StoreWord = AddressingModes.ImmediateStoreWord + }; + + AddressingModes.Lookup[0x02] = new AddressingMode + { + Name = "Direct", + SizeB = 2, + SizeW = 2, + LoadByte = AddressingModes.DirectLoadByte, + LoadWord = AddressingModes.DirectLoadWord, + StoreByte = AddressingModes.DirectStoreByte, + StoreWord = AddressingModes.DirectStoreWord + }; + + AddressingModes.Lookup[0x03] = new AddressingMode + { + Name = "Indirect", + SizeB = 2, + SizeW = 2, + LoadByte = AddressingModes.IndirectLoadByte, + LoadWord = AddressingModes.IndirectLoadWord, + StoreByte = AddressingModes.IndirectStoreByte, + StoreWord = AddressingModes.IndirectStoreWord + }; + + AddressingModes.Lookup[0x04] = new AddressingMode + { + Name = "Relative", + SizeB = 2, + SizeW = 2, + LoadByte = AddressingModes.RelativeLoadByte, + LoadWord = AddressingModes.RelativeLoadWord, + StoreByte = AddressingModes.RelativeStoreByte, + StoreWord = AddressingModes.RelativeStoreWord + }; + + AddressingModes.Lookup[0x05] = new AddressingMode + { + Name = "Register", + SizeB = 1, + SizeW = 1, + LoadByte = AddressingModes.RegisterLoadByte, + LoadWord = AddressingModes.RegisterLoadWord, + StoreByte = AddressingModes.RegisterStoreByte, + StoreWord = AddressingModes.RegisterStoreWord + }; + + AddressingModes.Lookup[0x06] = new AddressingMode + { + Name = "Register Indirect", + SizeB = 1, + SizeW = 1, + LoadByte = AddressingModes.RegisterIndirectLoadByte, + LoadWord = AddressingModes.RegisterIndirectLoadWord, + StoreByte = AddressingModes.RegisterIndirectStoreByte, + StoreWord = AddressingModes.RegisterIndirectStoreWord + }; + + AddressingModes.Lookup[0x07] = new AddressingMode + { + Name = "Register Indirect with Offset", + SizeB = 3, + SizeW = 3, + LoadByte = AddressingModes.RegisterIndirectOffsetLoadByte, + LoadWord = AddressingModes.RegisterIndirectOffsetLoadWord, + StoreByte = AddressingModes.RegisterIndirectOffsetStoreByte, + StoreWord = AddressingModes.RegisterIndirectOffsetStoreWord + }; + } + + private static u8 ImplicitLoadByte(Chip chip) + => throw new InvalidOperationException("Cannot load from an implicit value"); + private static u16 ImplicitLoadWord(Chip chip) + => throw new InvalidOperationException("Cannot load from an implicit value"); + private static void ImplicitStoreByte(Chip chip, u8 value) + => throw new InvalidOperationException("Cannot store to an implicit value"); + private static void ImplicitStoreWord(Chip chip, u16 value) + => throw new InvalidOperationException("Cannot store to an implicit value"); + + + private static u8 ImmediateLoadByte(Chip chip) + { + u8 value = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + return value; + } + private static u16 ImmediateLoadWord(Chip chip) + { + u16 value = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + return value; + } + private static void ImmediateStoreByte(Chip chip, u8 value) + => throw new InvalidOperationException("Cannot store to an immediate value"); + private static void ImmediateStoreWord(Chip chip, u16 value) + => throw new InvalidOperationException("Cannot store to an immediate value"); + + + private static u8 DirectLoadByte(Chip chip) + { + u16 address = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + return chip.Bus.Read(address); + } + private static u16 DirectLoadWord(Chip chip) + { + u16 address = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + return chip.Bus.ReadWord(address); + } + private static void DirectStoreByte(Chip chip, u8 value) + { + u16 address = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + chip.Bus.Write(address, value); + } + private static void DirectStoreWord(Chip chip, u16 value) + { + u16 address = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + chip.Bus.WriteWord(address, value); + } + + + private static u8 IndirectLoadByte(Chip chip) + { + u16 pointer = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = chip.Bus.ReadWord(pointer); + return chip.Bus.Read(address); + } + private static u16 IndirectLoadWord(Chip chip) + { + u16 pointer = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = chip.Bus.ReadWord(pointer); + return chip.Bus.ReadWord(address); + } + private static void IndirectStoreByte(Chip chip, u8 value) + { + u16 pointer = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = chip.Bus.ReadWord(pointer); + chip.Bus.Write(address, value); + } + private static void IndirectStoreWord(Chip chip, u16 value) + { + u16 pointer = chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = chip.Bus.ReadWord(pointer); + chip.Bus.WriteWord(address, value); + } + + + private static u8 RelativeLoadByte(Chip chip) + { + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16) (chip.Pc + offset); + return chip.Bus.Read(address); + } + private static u16 RelativeLoadWord(Chip chip) + { + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16) (chip.Pc + offset); + return chip.Bus.ReadWord(address); + } + private static void RelativeStoreByte(Chip chip, u8 value) + { + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16) (chip.Pc + offset); + chip.Bus.Write(address, value); + } + private static void RelativeStoreWord(Chip chip, u16 value) + { + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16) (chip.Pc + offset); + chip.Bus.WriteWord(address, value); + } + + private static u8 RegisterLoadByte(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + return (u8) (chip.GetRegister(regIndex) & 0xFF); + } + private static u16 RegisterLoadWord(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + return chip.GetRegister(regIndex); + } + private static void RegisterStoreByte(Chip chip, u8 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + u16 current = chip.GetRegister(regIndex); + u16 newValue = (u16)((current & 0xFF00) | value); + chip.SetRegister(regIndex, newValue); + } + private static void RegisterStoreWord(Chip chip, u16 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + chip.SetRegister(regIndex, value); + } + + private static u8 RegisterIndirectLoadByte(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + u16 address = chip.GetRegister(regIndex); + return chip.Bus.Read(address); + } + private static u16 RegisterIndirectLoadWord(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + u16 address = chip.GetRegister(regIndex); + return chip.Bus.ReadWord(address); + } + private static void RegisterIndirectStoreByte(Chip chip, u8 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + u16 address = chip.GetRegister(regIndex); + chip.Bus.Write(address, value); + } + private static void RegisterIndirectStoreWord(Chip chip, u16 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + u16 address = chip.GetRegister(regIndex); + chip.Bus.WriteWord(address, value); + } + + private static u8 RegisterIndirectOffsetLoadByte(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16)(chip.GetRegister(regIndex) + offset); + return chip.Bus.Read(address); + } + private static u16 RegisterIndirectOffsetLoadWord(Chip chip) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16)(chip.GetRegister(regIndex) + offset); + return chip.Bus.ReadWord(address); + } + private static void RegisterIndirectOffsetStoreByte(Chip chip, u8 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16)(chip.GetRegister(regIndex) + offset); + chip.Bus.Write(address, value); + } + private static void RegisterIndirectOffsetStoreWord(Chip chip, u16 value) + { + u8 regIndex = chip.Bus.Read(chip.Pc); + chip.Pc += 1; + + i16 offset = (i16) chip.Bus.ReadWord(chip.Pc); + chip.Pc += 2; + + u16 address = (u16)(chip.GetRegister(regIndex) + offset); + chip.Bus.WriteWord(address, value); + } +}
\ No newline at end of file diff --git a/Q1.core/Arch/Chip.cs b/Q1.core/Arch/Chip.cs new file mode 100644 index 0000000..af131dd --- /dev/null +++ b/Q1.core/Arch/Chip.cs @@ -0,0 +1,143 @@ +namespace Q1.core.Arch; + +// Big endian +public class Chip +{ + public IAddressable Bus; + public u16 Pc, Sp; + public u16 Ax, Dx, Lx; + + private u16[] _registers; + + public void Reset() + { + this._registers = new u16[64]; + this.Pc = ChipLayout.PROGRAM_START; + this.Sp = ChipLayout.STACK_START; + } + + public void Clock() + { + this.Bus.Clock(); + + this.Fetch(out u8 opcode, out u8 m1, out u8 m2, out bool word); + + switch (m1, m2) + { + case (0x00, 0x00): + InstructionSet.Lookup[opcode].Implicit.Execute(this, word); + break; + + case (_, 0x00): + InstructionSet.Lookup[opcode].SimpleAddressing.Execute(this, m1, word); + break; + + case (0x00, 0x01): + InstructionSet.Lookup[opcode].ExtendedImplicit.Execute(this, word); + break; + + case (_, _): + InstructionSet.Lookup[opcode].ExtendedAddressing.Execute(this, m1, m2, word); + break; + } + } + + /// [opcode: 7 bits] [word: 1 bits] [m1: 4 bits] [m2: 4 bits] + public void Fetch(out u8 opcode, out u8 m1, out u8 m2, out bool word) + { + u16 instruction = this.Bus.ReadWord(this.Pc); + this.Pc += 2; + + opcode = (u8) ((instruction >> 8) & 0xFE); // 128 opcodes + word = ((instruction >> 8) & 0x1) != 0; // flag for word mode + + m1 = (u8) ((instruction >> 4) & 0x0F); // 16 modes + m2 = (u8) (instruction & 0x0F); // 16 modes + } + + public void SkipInstruction() + { + this.Fetch(out u8 _, out u8 m1, out u8 m2, out bool word); + this.Pc += (u8)(Size(m1, word) + Size(m2, word)); + } + + public u16 Load(u8 mode, bool word) + { + AddressingMode am = AddressingModes.Lookup[mode]; + return word ? am.LoadWord(this) : am.LoadByte(this); + } + + public void Store(u8 mode, u16 value, bool word) + { + AddressingMode am = AddressingModes.Lookup[mode]; + if (word) am.StoreWord(this, value); + else am.StoreByte(this, (u8)(value & 0xFF)); + } + + public u8 Size(u8 mode, bool word) + { + AddressingMode am = AddressingModes.Lookup[mode]; + return word ? am.SizeW : am.SizeB; + } + + public void Push(u16 value) + { + if (this.Sp + 2 > ChipLayout.STACK_START + ChipLayout.STACK_SIZE) + throw new InvalidOperationException("Stack overflow"); + + this.Bus.WriteWord(this.Sp, value); + + this.Sp += 2; + } + + public u16 Pop() + { + if (this.Sp - 2 < ChipLayout.STACK_START) + throw new InvalidOperationException("Stack underflow"); + + this.Sp -= 2; + u16 value = this.Bus.ReadWord(this.Sp); + + return value; + } + + public u16 GetRegister(u8 index) + { + if (index < 64) return this._registers[index]; + + if (index == 0x40) return this.Ax; + if (index == 0x41) return (u16) (this.Ax >> 8); // High byte of Ax + if (index == 0x42) return (u16) (this.Ax & 0xFF); // Low byte of Ax + + if (index == 0x44) return this.Dx; + if (index == 0x45) return (u16) (this.Dx >> 8); // High byte of Dx + if (index == 0x46) return (u16) (this.Dx & 0xFF); // Low byte of Dx + + if (index == 0x48) return this.Lx; + + if (index == 0x4C) return this.Pc; + if (index == 0x4D) return this.Sp; + + throw new InvalidOperationException($"Invalid register index: {index}"); + } + + public void SetRegister(u8 index, u16 value) + { + if (index < 64) this._registers[index] = value; + + else if (index == 0x40) this.Ax = value; + else if (index == 0x41) this.Ax = (u16)((this.Ax & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Ax + else if (index == 0x42) this.Ax = (u16)((this.Ax & 0xFF00) | (value & 0xFF)); // Set low byte of Ax + + else if (index == 0x44) this.Dx = value; + else if (index == 0x45) this.Dx = (u16)((this.Dx & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Dx + else if (index == 0x46) this.Dx = (u16)((this.Dx & 0xFF00) | (value & 0xFF)); // Set low byte of Dx + + else if (index == 0x48) this.Lx = value; + + else if (index == 0x4C) this.Pc = value; + else if (index == 0x4D) this.Sp = value; + + else throw new InvalidOperationException($"Invalid register index: {index}"); + } +}
\ No newline at end of file diff --git a/Q1.core/Arch/ChipLayout.cs b/Q1.core/Arch/ChipLayout.cs new file mode 100644 index 0000000..8c916f6 --- /dev/null +++ b/Q1.core/Arch/ChipLayout.cs @@ -0,0 +1,12 @@ +namespace Q1.core.Arch; + +public static class ChipLayout +{ + public const u16 MEMORY_START = 0x0000; + public const u16 MEMORY_SIZE = 0xFF00; // 64KB - 256 bytes reserved for stack + + public const u16 STACK_START = ChipLayout.MEMORY_START; + public const u16 STACK_SIZE = 256 * 2; // 256 words (512 bytes) + + public const u16 PROGRAM_START = ChipLayout.MEMORY_START + ChipLayout.STACK_SIZE; +}
\ No newline at end of file diff --git a/Q1.core/Arch/IInstruction.cs b/Q1.core/Arch/IInstruction.cs new file mode 100644 index 0000000..2889937 --- /dev/null +++ b/Q1.core/Arch/IInstruction.cs @@ -0,0 +1,35 @@ +namespace Q1.core.Arch; + +public interface IInstruction +{ + public string Name { get; } +} + +public record struct ImplicitInstruction : IInstruction +{ + public string Name { get; set; } + + public Action<Chip, bool> Execute; +} + +public record struct SimpleInstruction : IInstruction +{ + public string Name { get; set; } + + public Action<Chip, u8, bool> Execute; +} + +public record struct ExtendedInstruction : IInstruction +{ + public string Name { get; set; } + + public Action<Chip, u8, u8, bool> Execute; +} + +public record struct InstructionGroup +{ + public ImplicitInstruction Implicit; + public SimpleInstruction SimpleAddressing; + public ImplicitInstruction ExtendedImplicit; + public ExtendedInstruction ExtendedAddressing; +}
\ No newline at end of file diff --git a/Q1.core/Arch/InstructionSet.cs b/Q1.core/Arch/InstructionSet.cs new file mode 100644 index 0000000..68a9b55 --- /dev/null +++ b/Q1.core/Arch/InstructionSet.cs @@ -0,0 +1,203 @@ +namespace Q1.core.Arch; + +public static class InstructionSet +{ + public static readonly InstructionGroup[] Lookup = new InstructionGroup[128]; + + static InstructionSet() + { + var nop = new ImplicitInstruction { Name = "NOP", Execute = InstructionSet.Nop }; + var nopSimple = new SimpleInstruction { Name = "NOP", Execute = InstructionSet.Nop }; + var nopExtended = new ExtendedInstruction { Name = "NOP", Execute = InstructionSet.Nop }; + + #region Control Group + + InstructionSet.Lookup[0x00] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = new SimpleInstruction { Name = "JMP", Execute = InstructionSet.Jump }, + ExtendedImplicit = new ImplicitInstruction { Name = "HALT", Execute = InstructionSet.Halt }, + ExtendedAddressing = new ExtendedInstruction { Name = "MOV", Execute = InstructionSet.Move } + }; + + InstructionSet.Lookup[0x01] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "RET", Execute = InstructionSet.Return }, + SimpleAddressing = new SimpleInstruction { Name = "CALL", Execute = InstructionSet.Call }, + ExtendedImplicit = new ImplicitInstruction { Name = "SUS", Execute = InstructionSet.Suspend }, + ExtendedAddressing = nopExtended + }; + + InstructionSet.Lookup[0x02] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "BZ(LX)", Execute = InstructionSet.BranchIfZeroLx }, + SimpleAddressing = new SimpleInstruction { Name = "BZ", Execute = InstructionSet.BranchIfZero }, + ExtendedImplicit = new ImplicitInstruction { Name = "BR", Execute = InstructionSet.Branch }, + ExtendedAddressing = nopExtended + }; + + InstructionSet.Lookup[0x03] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = new SimpleInstruction { Name = "PUSH", Execute = InstructionSet.Push }, + ExtendedImplicit = nop, + ExtendedAddressing = nopExtended + }; + + InstructionSet.Lookup[0x04] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = new SimpleInstruction { Name = "POP", Execute = InstructionSet.Pop }, + ExtendedImplicit = nop, + ExtendedAddressing = nopExtended + }; + + #endregion + + #region Data Group + + InstructionSet.Lookup[0x10] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "INV(DX)", Execute = InstructionSet.InverseDx }, + SimpleAddressing = new SimpleInstruction { Name = "INV", Execute = InstructionSet.Inverse }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "AND", Execute = InstructionSet.And } + }; + + InstructionSet.Lookup[0x11] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "OR", Execute = InstructionSet.Or } + }; + + InstructionSet.Lookup[0x12] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "XOR", Execute = InstructionSet.Xor } + }; + + InstructionSet.Lookup[0x13] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "SHPL(DX)", Execute = InstructionSet.ShiftPlaceLeftDx }, + SimpleAddressing = new SimpleInstruction { Name = "SHPL", Execute = InstructionSet.ShiftPlaceLeft }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "SHL", Execute = InstructionSet.ShiftLeft } + }; + + InstructionSet.Lookup[0x14] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "SHPR(DX)", Execute = InstructionSet.ShiftPlaceRightDx }, + SimpleAddressing = new SimpleInstruction { Name = "SHPR", Execute = InstructionSet.ShiftPlaceRight }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "SHL", Execute = InstructionSet.ShiftRight } + }; + + #endregion + } + + private static void Nop(Chip chip, bool word) { /* No operation */ } + private static void Nop(Chip chip, u8 m1, bool word) { /* No operation */ } + private static void Nop(Chip chip, u8 m1, u8 m2, bool word) { /* No operation */ } + + #region Control Instructions + + private static void Halt(Chip chip, bool word) + { + throw new NotImplementedException("HALT instruction is not implemented yet."); + } + + private static void Suspend(Chip chip, bool word) + { + throw new NotImplementedException("SUS instruction is not implemented yet."); + } + + private static void Move(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value = chip.Load(m1, word); + chip.Store(m2, value, word); + } + + private static void Jump(Chip chip, u8 m1, bool word) + { + u16 address = chip.Load(m1, word); + chip.Pc = address; + } + + private static void Call(Chip chip, u8 m1, bool word) + { + u16 targetAddress = chip.Load(m1, word); + chip.Push(chip.Pc); + chip.Pc = targetAddress; + } + + private static void Return(Chip chip, bool word) + { + u16 returnAddress = chip.Pop(); + chip.Pc = returnAddress; + } + + private static void BranchIfZero(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + if (value == 0) + chip.SkipInstruction(); + } + + private static void BranchIfZeroLx(Chip chip, bool word) + { + if (chip.Lx == 0) + chip.SkipInstruction(); + } + + private static void Branch(Chip chip, bool word) + { + chip.SkipInstruction(); + } + + private static void Push(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + chip.Push(value); + } + + private static void Pop(Chip chip, u8 m1, bool word) + { + u16 value = chip.Pop(); + chip.Store(m1, value, word); + } + + #endregion + + #region Data Instructions + + private static void Inverse(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + value = (u16)~value; + + chip.Dx = value; + } + + private static void InverseDx(Chip chip, bool word) + { + chip.Dx = (u16)~chip.Dx; + } + + #endregion + + #region Logic Instructions + + + + #endregion + + #region Arithmetic Instructions + + + + #endregion +}
\ No newline at end of file diff --git a/Q1.core/GlobalUsings.cs b/Q1.core/GlobalUsings.cs new file mode 100644 index 0000000..aca802e --- /dev/null +++ b/Q1.core/GlobalUsings.cs @@ -0,0 +1,12 @@ +// Integer type aliases +global using i8 = sbyte; // -128 to 127 +global using u8 = byte; // 0 to 255 +global using i16 = short; // -32,768 to 32,767 +global using u16 = ushort; // 0 to 65,535 +global using i32 = int; // -2,147,483,648 to 2,147,483,647 +global using u32 = uint; // 0 to 4,294,967,295 +global using i64 = long; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +global using u64 = ulong; // 0 to 18,446,744,073,709,551,615 + +global using ref8 = System.Span<byte>; +global using data8 = byte[];
\ No newline at end of file diff --git a/Q1.core/IAddressable.cs b/Q1.core/IAddressable.cs new file mode 100644 index 0000000..49a697e --- /dev/null +++ b/Q1.core/IAddressable.cs @@ -0,0 +1,26 @@ +namespace Q1.core; + +public interface IAddressable +{ + public u8 Read(u16 address); + public void Write(u16 address, u8 value); + public void Clock(); +} + +public static class AddressableExtensions +{ + public static u16 ReadWord(this IAddressable bus, u16 address) + { + u8 high = bus.Read(address); + u8 low = bus.Read((u16)(address + 1)); + return (u16)((high << 8) | low); + } + + public static void WriteWord(this IAddressable bus, u16 address, u16 value) + { + u8 high = (u8) (value & 0xFF); + u8 low = (u8)((value >> 8) & 0xFF); + bus.Write(address, low); + bus.Write((u16)(address + 1), high); + } +}
\ No newline at end of file diff --git a/Q1.core/Memory.cs b/Q1.core/Memory.cs new file mode 100644 index 0000000..d140809 --- /dev/null +++ b/Q1.core/Memory.cs @@ -0,0 +1,15 @@ +namespace Q1.core; + +public class Memory : IAddressable +{ + private readonly u8[] _memory; + + public Memory(int size) + { + _memory = new u8[size]; + } + + public u8 Read(u16 address) => _memory[address]; + public void Write(u16 address, u8 value) => _memory[address] = value; + public void Clock() { /* No timing behavior for simple memory */ } +}
\ No newline at end of file diff --git a/Q1.core/Q1.core.csproj b/Q1.core/Q1.core.csproj new file mode 100644 index 0000000..17b910f --- /dev/null +++ b/Q1.core/Q1.core.csproj @@ -0,0 +1,9 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>net9.0</TargetFramework> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + </PropertyGroup> + +</Project> |
