diff options
| author | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-03-18 23:08:58 +1000 |
|---|---|---|
| committer | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-03-18 23:08:58 +1000 |
| commit | 7d20ff2a8e89e646fa79be69c8d07a512081daba (patch) | |
| tree | 67433c74d55f778065363010a593c44a0f65296b /Q1.core/Arch/Lookups | |
| parent | 0bb62fc65526a0981cd328dea1b09aba8ce0a576 (diff) | |
test: Add tests for all control instructions and base CPU implementation
Diffstat (limited to 'Q1.core/Arch/Lookups')
| -rw-r--r-- | Q1.core/Arch/Lookups/AddressingModes.cs | 344 | ||||
| -rw-r--r-- | Q1.core/Arch/Lookups/InstructionSet.cs | 484 |
2 files changed, 828 insertions, 0 deletions
diff --git a/Q1.core/Arch/Lookups/AddressingModes.cs b/Q1.core/Arch/Lookups/AddressingModes.cs new file mode 100644 index 0000000..95e798d --- /dev/null +++ b/Q1.core/Arch/Lookups/AddressingModes.cs @@ -0,0 +1,344 @@ +namespace Q1.core.Arch.Lookups; + +using Q1.core.Components; + +public static class AddressingModes +{ + public static AddressingMode[] Lookup = new AddressingMode[8]; + + public static u8 GetAddressingMode(string name) + { + for (u8 i = 0; i < AddressingModes.Lookup.Length; i++) + { + if (AddressingModes.Lookup[i].Name == name) + return i; + } + + throw new ArgumentException($"Invalid addressing mode: {name}"); + } + + 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/Lookups/InstructionSet.cs b/Q1.core/Arch/Lookups/InstructionSet.cs new file mode 100644 index 0000000..2ea20fc --- /dev/null +++ b/Q1.core/Arch/Lookups/InstructionSet.cs @@ -0,0 +1,484 @@ +namespace Q1.core.Arch.Lookups; + +public static class InstructionSet +{ + public static readonly InstructionGroup[] Lookup = new InstructionGroup[128]; + + public static u8 GetOpcode(string instructionName) + { + for (u8 opcode = 0; opcode < InstructionSet.Lookup.Length; opcode++) + { + var group = InstructionSet.Lookup[opcode]; + if (group.Implicit.Name == instructionName || + group.SimpleAddressing.Name == instructionName || + group.ExtendedImplicit.Name == instructionName || + group.ExtendedAddressing.Name == instructionName) + { + return opcode; + } + } + throw new ArgumentException($"Instruction '{instructionName}' not found in the instruction set."); + } + + 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 + }; + + InstructionSet.Lookup[0x05] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = new SimpleInstruction { Name = "INT", Execute = InstructionSet.Interrupt }, + 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 = "SHR", Execute = InstructionSet.ShiftRight } + }; + + #endregion + + #region Logic Group + + InstructionSet.Lookup[0x20] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "NOT(LX)", Execute = InstructionSet.NotLx }, + SimpleAddressing = new SimpleInstruction { Name = "NOT", Execute = InstructionSet.Not }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "CMP", Execute = InstructionSet.Compare } + }; + + InstructionSet.Lookup[0x21] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "LT", Execute = InstructionSet.LessThan } + }; + + InstructionSet.Lookup[0x22] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "GT", Execute = InstructionSet.GreaterThan } + }; + + #endregion + + #region Arithmatic Group + + InstructionSet.Lookup[0x30] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "INC(AX)", Execute = InstructionSet.IncrementAx }, + SimpleAddressing = new SimpleInstruction { Name = "INC", Execute = InstructionSet.Increment }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "ADD", Execute = InstructionSet.Add } + }; + + InstructionSet.Lookup[0x31] = new InstructionGroup + { + Implicit = new ImplicitInstruction { Name = "DEC(AX)", Execute = InstructionSet.DecrementAx }, + SimpleAddressing = new SimpleInstruction { Name = "DEC", Execute = InstructionSet.Decrement }, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "SUB", Execute = InstructionSet.Subtract } + }; + + InstructionSet.Lookup[0x32] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "DIV", Execute = InstructionSet.Divide } + }; + + InstructionSet.Lookup[0x33] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "MUL", Execute = InstructionSet.Multiply } + }; + + InstructionSet.Lookup[0x34] = new InstructionGroup + { + Implicit = nop, + SimpleAddressing = nopSimple, + ExtendedImplicit = nop, + ExtendedAddressing = new ExtendedInstruction { Name = "MOD", Execute = InstructionSet.Modulo } + }; + + #endregion + } + + public static void Nop(Chip chip, bool word) { /* No operation */ } + public static void Nop(Chip chip, u8 m1, bool word) { /* No operation */ } + public static void Nop(Chip chip, u8 m1, u8 m2, bool word) { /* No operation */ } + + #region Control Instructions + + public static void Halt(Chip chip, bool word) + { + throw new HaltException(); + } + + public static void Suspend(Chip chip, bool word) + { + throw new NotImplementedException("SUS instruction is not implemented yet."); + } + + public static void Interrupt(Chip chip, u8 m1, bool word) + { + u16 interruptNumber = chip.Load(m1, word); + + chip.Interrupt(interruptNumber); + } + + public static void Move(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value = chip.Load(m1, word); + chip.Store(m2, value, word); + } + + public static void Jump(Chip chip, u8 m1, bool word) + { + u16 address = chip.Load(m1, word); + chip.Pc = address; + } + + public static void Call(Chip chip, u8 m1, bool word) + { + u16 targetAddress = chip.Load(m1, word); + chip.Push(chip.Pc); + chip.Pc = targetAddress; + } + + public static void Return(Chip chip, bool word) + { + u16 returnAddress = chip.Pop(); + chip.Pc = returnAddress; + } + + public static void BranchIfZero(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + if (value == 0) + chip.SkipInstruction(); + } + + public static void BranchIfZeroLx(Chip chip, bool word) + { + if (chip.Lx == 0) + chip.SkipInstruction(); + } + + public static void Branch(Chip chip, bool word) + { + chip.SkipInstruction(); + } + + public static void Push(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + chip.Push(value); + } + + public static void Pop(Chip chip, u8 m1, bool word) + { + u16 value = chip.Pop(); + chip.Store(m1, value, word); + } + + #endregion + + #region Data Instructions + + public static void Inverse(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + value = (u16)~value; + + chip.Dx = value; + } + + public static void InverseDx(Chip chip, bool word) + { + chip.Dx = (u16)~chip.Dx; + } + + public static void And(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 & value2); + + chip.Dx = result; + } + + public static void Or(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 | value2); + + chip.Dx = result; + } + + public static void Xor(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 ^ value2); + + chip.Dx = result; + } + + public static void ShiftLeft(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value = chip.Load(m1, word); + u16 shiftAmount = (u16) (chip.Load(m2, word) & 0xF); // Limit shift to 0-15 + u16 result = (u16) (value << shiftAmount); + + chip.Dx = result; + } + + public static void ShiftRight(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value = chip.Load(m1, word); + u16 shiftAmount = (u16) (chip.Load(m2, word) & 0xF); // Limit shift to 0-15 + u16 result = (u16) (value >> shiftAmount); + + chip.Dx = result; + } + + public static void ShiftPlaceLeft(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + u16 result = (u16) ((value << 1) | (value >> 15)); // Rotate left + + chip.Dx = result; + } + + public static void ShiftPlaceRight(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + u16 result = (u16) ((value >> 1) | (value << 15)); // Rotate right + + chip.Dx = result; + } + + public static void ShiftPlaceLeftDx(Chip chip, bool word) + { + u16 value = chip.Dx; + u16 result = (u16) ((value << 1) | (value >> 15)); // Rotate left + + chip.Dx = result; + } + + public static void ShiftPlaceRightDx(Chip chip, bool word) + { + u16 value = chip.Dx; + u16 result = (u16) ((value >> 1) | (value << 15)); // Rotate right + + chip.Dx = result; + } + + #endregion + + #region Logic Instructions + + public static void Not(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + chip.Lx = value == 0 ? (u16)1 : (u16)0; + } + + public static void NotLx(Chip chip, bool word) + { + chip.Lx = chip.Lx == 0 ? (u16)1 : (u16)0; + } + + public static void Compare(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + chip.Lx = value1 == value2 ? (u16)1 : (u16)0; + } + + public static void LessThan(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + chip.Lx = value1 < value2 ? (u16)1 : (u16)0; + } + + public static void GreaterThan(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + chip.Lx = value1 > value2 ? (u16)1 : (u16)0; + } + + #endregion + + #region Arithmetic Instructions + + public static void Increment(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + value++; + chip.Store(m1, value, word); + } + + public static void IncrementAx(Chip chip, bool word) + { + chip.Ax++; + } + + public static void Decrement(Chip chip, u8 m1, bool word) + { + u16 value = chip.Load(m1, word); + value--; + chip.Store(m1, value, word); + } + + public static void DecrementAx(Chip chip, bool word) + { + chip.Ax--; + } + + public static void Add(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 + value2); + + chip.Ax = result; + } + + public static void Subtract(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 - value2); + + chip.Ax = result; + } + + public static void Multiply(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + u16 result = (u16)(value1 * value2); + + chip.Ax = result; + } + + public static void Divide(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + if (value2 == 0) + throw new DivideByZeroException("Attempted to divide by zero."); + + u16 result = (u16)(value1 / value2); + chip.Ax = result; + } + + public static void Modulo(Chip chip, u8 m1, u8 m2, bool word) + { + u16 value1 = chip.Load(m1, word); + u16 value2 = chip.Load(m2, word); + if (value2 == 0) + throw new DivideByZeroException("Attempted to modulo by zero."); + + u16 result = (u16)(value1 % value2); + chip.Ax = result; + } + + #endregion +}
\ No newline at end of file |
