summaryrefslogtreecommitdiff
path: root/Q1.core/Arch
diff options
context:
space:
mode:
authorMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-18 23:08:58 +1000
committerMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-18 23:08:58 +1000
commit7d20ff2a8e89e646fa79be69c8d07a512081daba (patch)
tree67433c74d55f778065363010a593c44a0f65296b /Q1.core/Arch
parent0bb62fc65526a0981cd328dea1b09aba8ce0a576 (diff)
test: Add tests for all control instructions and base CPU implementation
Diffstat (limited to 'Q1.core/Arch')
-rw-r--r--Q1.core/Arch/Chip.cs75
-rw-r--r--Q1.core/Arch/Constants/ChipLayout.cs (renamed from Q1.core/Arch/ChipLayout.cs)2
-rw-r--r--Q1.core/Arch/Constants/ChipRegisters.cs19
-rw-r--r--Q1.core/Arch/InstructionEncoding.cs26
-rw-r--r--Q1.core/Arch/Lookups/AddressingModes.cs (renamed from Q1.core/Arch/AddressingModes.cs)15
-rw-r--r--Q1.core/Arch/Lookups/InstructionSet.cs (renamed from Q1.core/Arch/InstructionSet.cs)102
6 files changed, 163 insertions, 76 deletions
diff --git a/Q1.core/Arch/Chip.cs b/Q1.core/Arch/Chip.cs
index 9f5f109..fef9cea 100644
--- a/Q1.core/Arch/Chip.cs
+++ b/Q1.core/Arch/Chip.cs
@@ -1,6 +1,8 @@
namespace Q1.core.Arch;
using Components;
+using Constants;
+using Lookups;
// Big endian
public class Chip
@@ -10,10 +12,15 @@ public class Chip
public u16 Ax, Dx, Lx;
private u16[] _registers;
+
+ public Chip()
+ {
+ this.Reset();
+ }
public void Reset()
{
- this._registers = new u16[64];
+ this._registers = new u16[ChipRegisters.GENERIC_REGISTER_COUNT];
this.Pc = ChipLayout.PROGRAM_START;
this.Sp = ChipLayout.STACK_START;
}
@@ -23,23 +30,25 @@ public class Chip
this.Bus.Clock();
this.Fetch(out u8 opcode, out u8 m1, out u8 m2, out bool word);
+
+ var instruction = InstructionSet.Lookup[opcode];
switch (m1, m2)
{
case (0x00, 0x00):
- InstructionSet.Lookup[opcode].Implicit.Execute(this, word);
+ instruction.Implicit.Execute(this, word);
break;
case (_, 0x00):
- InstructionSet.Lookup[opcode].SimpleAddressing.Execute(this, m1, word);
+ instruction.SimpleAddressing.Execute(this, m1, word);
break;
case (0x00, 0x01):
- InstructionSet.Lookup[opcode].ExtendedImplicit.Execute(this, word);
+ instruction.ExtendedImplicit.Execute(this, word);
break;
case (_, _):
- InstructionSet.Lookup[opcode].ExtendedAddressing.Execute(this, m1, m2, word);
+ instruction.ExtendedAddressing.Execute(this, m1, m2, word);
break;
}
}
@@ -49,12 +58,8 @@ public class Chip
{
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
+ InstructionEncoding.Decode(instruction, out opcode, out m1, out m2, out word);
}
public void SkipInstruction()
@@ -105,43 +110,44 @@ public class Chip
public u16 GetRegister(u8 index)
{
- if (index < 64) return this._registers[index];
+ if (index < ChipRegisters.GENERIC_REGISTER_COUNT) 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 == ChipRegisters.AX) return this.Ax;
+ if (index == ChipRegisters.AH) return (u16) (this.Ax >> 8); // High byte of Ax
+ if (index == ChipRegisters.AL) 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 == ChipRegisters.DX) return this.Dx;
+ if (index == ChipRegisters.DH) return (u16) (this.Dx >> 8); // High byte of Dx
+ if (index == ChipRegisters.DL) return (u16) (this.Dx & 0xFF); // Low byte of Dx
- if (index == 0x48) return this.Lx;
+ if (index == ChipRegisters.LX) return this.Lx;
- if (index == 0x4C) return this.Pc;
- if (index == 0x4D) return this.Sp;
+ if (index == ChipRegisters.PC) return this.Pc;
+ if (index == ChipRegisters.SP) return this.Sp;
throw new InvalidOperationException($"Invalid register index: {index}");
}
public void SetRegister(u8 index, u16 value)
{
- if (index < 64) this._registers[index] = value;
+ if (index < ChipRegisters.GENERIC_REGISTER_COUNT) 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 == ChipRegisters.AX) this.Ax = value;
+ else if (index == ChipRegisters.AH) this.Ax = (u16)((this.Ax & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Ax
+ else if (index == ChipRegisters.AL) 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 == ChipRegisters.DX) this.Dx = value;
+ else if (index == ChipRegisters.DH) this.Dx = (u16)((this.Dx & 0x00FF) | ((value & 0xFF) << 8)); // Set high byte of Dx
+ else if (index == ChipRegisters.DL) this.Dx = (u16)((this.Dx & 0xFF00) | (value & 0xFF)); // Set low byte of Dx
- else if (index == 0x48) this.Lx = value;
+ else if (index == ChipRegisters.LX) this.Lx = value;
- else if (index == 0x4C) this.Pc = value;
- else if (index == 0x4D) this.Sp = value;
+ else if (index == ChipRegisters.PC) this.Pc = value;
+ else if (index == ChipRegisters.SP) this.Sp = value;
else throw new InvalidOperationException($"Invalid register index: {index}");
}
+
public void Interrupt(u16 code)
{
if (code >= ChipLayout.IVT_COUNT)
@@ -151,4 +157,13 @@ public class Chip
u16 interruptVectorAddress = (u16) (ChipLayout.IVT_START + code * 2);
this.Pc = this.Bus.ReadWord(interruptVectorAddress);
}
+
+ public void RegisterInterruptHandler(u16 code, u16 handlerAddress)
+ {
+ if (code >= ChipLayout.IVT_COUNT)
+ throw new InvalidOperationException($"Invalid interrupt code: {code}");
+
+ u16 interruptVectorAddress = (u16) (ChipLayout.IVT_START + code * 2);
+ this.Bus.WriteWord(interruptVectorAddress, handlerAddress);
+ }
} \ No newline at end of file
diff --git a/Q1.core/Arch/ChipLayout.cs b/Q1.core/Arch/Constants/ChipLayout.cs
index 6c7187b..6990789 100644
--- a/Q1.core/Arch/ChipLayout.cs
+++ b/Q1.core/Arch/Constants/ChipLayout.cs
@@ -1,4 +1,4 @@
-namespace Q1.core.Arch;
+namespace Q1.core.Arch.Constants;
public static class ChipLayout
{
diff --git a/Q1.core/Arch/Constants/ChipRegisters.cs b/Q1.core/Arch/Constants/ChipRegisters.cs
new file mode 100644
index 0000000..042ce32
--- /dev/null
+++ b/Q1.core/Arch/Constants/ChipRegisters.cs
@@ -0,0 +1,19 @@
+namespace Q1.core.Arch.Constants;
+
+public static class ChipRegisters
+{
+ public const u8 GENERIC_REGISTER_COUNT = 64;
+
+ public const u8 AX = 0x40;
+ public const u8 AH = 0x41;
+ public const u8 AL = 0x42;
+
+ public const u8 DX = 0x44;
+ public const u8 DH = 0x45;
+ public const u8 DL = 0x46;
+
+ public const u8 LX = 0x48;
+
+ public const u8 PC = 0x4C;
+ public const u8 SP = 0x4D;
+} \ No newline at end of file
diff --git a/Q1.core/Arch/InstructionEncoding.cs b/Q1.core/Arch/InstructionEncoding.cs
new file mode 100644
index 0000000..479d61f
--- /dev/null
+++ b/Q1.core/Arch/InstructionEncoding.cs
@@ -0,0 +1,26 @@
+namespace Q1.core.Arch;
+
+public static class InstructionEncoding
+{
+ public static void Decode(u16 instruction, out u8 opcode, out u8 m1, out u8 m2, out bool word)
+ {
+ word = ((instruction >> 15) & 0x1) != 0; // top bit
+ opcode = (u8)((instruction >> 8) & 0x7F); // 7 clean bits
+
+ m1 = (u8)((instruction >> 4) & 0x0F);
+ m2 = (u8)(instruction & 0x0F);
+ }
+
+ public static u16 Encode(u8 opcode, u8 m1, u8 m2, bool word)
+ {
+ u16 instruction = 0;
+
+ instruction |= (u16)((opcode & 0x7F) << 8); // 7-bit opcode
+ instruction |= (u16)((word ? 1 : 0) << 15); // top bit flag
+
+ instruction |= (u16)((m1 & 0x0F) << 4);
+ instruction |= (u16)(m2 & 0x0F);
+
+ return instruction;
+ }
+} \ No newline at end of file
diff --git a/Q1.core/Arch/AddressingModes.cs b/Q1.core/Arch/Lookups/AddressingModes.cs
index 96b4475..95e798d 100644
--- a/Q1.core/Arch/AddressingModes.cs
+++ b/Q1.core/Arch/Lookups/AddressingModes.cs
@@ -1,11 +1,22 @@
-namespace Q1.core.Arch;
+namespace Q1.core.Arch.Lookups;
-using Components;
+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
diff --git a/Q1.core/Arch/InstructionSet.cs b/Q1.core/Arch/Lookups/InstructionSet.cs
index 212e77e..2ea20fc 100644
--- a/Q1.core/Arch/InstructionSet.cs
+++ b/Q1.core/Arch/Lookups/InstructionSet.cs
@@ -1,9 +1,25 @@
-namespace Q1.core.Arch;
+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 };
@@ -173,85 +189,85 @@ public static class InstructionSet
Implicit = nop,
SimpleAddressing = nopSimple,
ExtendedImplicit = nop,
- ExtendedAddressing = new ExtendedInstruction { Name = "DIV", Execute = InstructionSet.Modulo }
+ ExtendedAddressing = new ExtendedInstruction { Name = "MOD", Execute = InstructionSet.Modulo }
};
#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 */ }
+ 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
- private static void Halt(Chip chip, bool word)
+ public static void Halt(Chip chip, bool word)
{
- throw new NotImplementedException("HALT instruction is not implemented yet.");
+ throw new HaltException();
}
- private static void Suspend(Chip chip, bool word)
+ public static void Suspend(Chip chip, bool word)
{
throw new NotImplementedException("SUS instruction is not implemented yet.");
}
- private static void Interrupt(Chip chip, u8 m1, bool word)
+ public static void Interrupt(Chip chip, u8 m1, bool word)
{
u16 interruptNumber = chip.Load(m1, word);
chip.Interrupt(interruptNumber);
}
- private static void Move(Chip chip, u8 m1, u8 m2, bool word)
+ public 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)
+ public 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)
+ public 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)
+ public static void Return(Chip chip, bool word)
{
u16 returnAddress = chip.Pop();
chip.Pc = returnAddress;
}
- private static void BranchIfZero(Chip chip, u8 m1, bool word)
+ public 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)
+ public static void BranchIfZeroLx(Chip chip, bool word)
{
if (chip.Lx == 0)
chip.SkipInstruction();
}
- private static void Branch(Chip chip, bool word)
+ public static void Branch(Chip chip, bool word)
{
chip.SkipInstruction();
}
- private static void Push(Chip chip, u8 m1, bool word)
+ public 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)
+ public static void Pop(Chip chip, u8 m1, bool word)
{
u16 value = chip.Pop();
chip.Store(m1, value, word);
@@ -261,7 +277,7 @@ public static class InstructionSet
#region Data Instructions
- private static void Inverse(Chip chip, u8 m1, bool word)
+ public static void Inverse(Chip chip, u8 m1, bool word)
{
u16 value = chip.Load(m1, word);
value = (u16)~value;
@@ -269,12 +285,12 @@ public static class InstructionSet
chip.Dx = value;
}
- private static void InverseDx(Chip chip, bool word)
+ public static void InverseDx(Chip chip, bool word)
{
chip.Dx = (u16)~chip.Dx;
}
- private static void And(Chip chip, u8 m1, u8 m2, bool word)
+ public static void And(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -283,7 +299,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void Or(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Or(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -292,7 +308,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void Xor(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Xor(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -301,7 +317,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftLeft(Chip chip, u8 m1, u8 m2, bool word)
+ 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
@@ -310,7 +326,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftRight(Chip chip, u8 m1, u8 m2, bool word)
+ 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
@@ -319,7 +335,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftPlaceLeft(Chip chip, u8 m1, bool word)
+ 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
@@ -327,7 +343,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftPlaceRight(Chip chip, u8 m1, bool word)
+ 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
@@ -335,7 +351,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftPlaceLeftDx(Chip chip, bool word)
+ public static void ShiftPlaceLeftDx(Chip chip, bool word)
{
u16 value = chip.Dx;
u16 result = (u16) ((value << 1) | (value >> 15)); // Rotate left
@@ -343,7 +359,7 @@ public static class InstructionSet
chip.Dx = result;
}
- private static void ShiftPlaceRightDx(Chip chip, bool word)
+ public static void ShiftPlaceRightDx(Chip chip, bool word)
{
u16 value = chip.Dx;
u16 result = (u16) ((value >> 1) | (value << 15)); // Rotate right
@@ -355,32 +371,32 @@ public static class InstructionSet
#region Logic Instructions
- private static void Not(Chip chip, u8 m1, bool word)
+ public static void Not(Chip chip, u8 m1, bool word)
{
u16 value = chip.Load(m1, word);
chip.Lx = value == 0 ? (u16)1 : (u16)0;
}
- private static void NotLx(Chip chip, bool word)
+ public static void NotLx(Chip chip, bool word)
{
chip.Lx = chip.Lx == 0 ? (u16)1 : (u16)0;
}
- private static void Compare(Chip chip, u8 m1, u8 m2, bool word)
+ 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;
}
- private static void LessThan(Chip chip, u8 m1, u8 m2, bool word)
+ 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;
}
- private static void GreaterThan(Chip chip, u8 m1, u8 m2, bool word)
+ public static void GreaterThan(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -391,31 +407,31 @@ public static class InstructionSet
#region Arithmetic Instructions
- private static void Increment(Chip chip, u8 m1, bool word)
+ public static void Increment(Chip chip, u8 m1, bool word)
{
u16 value = chip.Load(m1, word);
value++;
chip.Store(m1, value, word);
}
- private static void IncrementAx(Chip chip, bool word)
+ public static void IncrementAx(Chip chip, bool word)
{
chip.Ax++;
}
- private static void Decrement(Chip chip, u8 m1, bool word)
+ public static void Decrement(Chip chip, u8 m1, bool word)
{
u16 value = chip.Load(m1, word);
value--;
chip.Store(m1, value, word);
}
- private static void DecrementAx(Chip chip, bool word)
+ public static void DecrementAx(Chip chip, bool word)
{
chip.Ax--;
}
- private static void Add(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Add(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -424,7 +440,7 @@ public static class InstructionSet
chip.Ax = result;
}
- private static void Subtract(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Subtract(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -433,7 +449,7 @@ public static class InstructionSet
chip.Ax = result;
}
- private static void Multiply(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Multiply(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -442,7 +458,7 @@ public static class InstructionSet
chip.Ax = result;
}
- private static void Divide(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Divide(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);
@@ -453,7 +469,7 @@ public static class InstructionSet
chip.Ax = result;
}
- private static void Modulo(Chip chip, u8 m1, u8 m2, bool word)
+ public static void Modulo(Chip chip, u8 m1, u8 m2, bool word)
{
u16 value1 = chip.Load(m1, word);
u16 value2 = chip.Load(m2, word);