summaryrefslogtreecommitdiff
path: root/Q1.tests/Core
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.tests/Core
parent0bb62fc65526a0981cd328dea1b09aba8ce0a576 (diff)
test: Add tests for all control instructions and base CPU implementation
Diffstat (limited to 'Q1.tests/Core')
-rw-r--r--Q1.tests/Core/AddressingModesTests.cs4
-rw-r--r--Q1.tests/Core/ChipTestBase.cs20
-rw-r--r--Q1.tests/Core/ChipTests.cs87
-rw-r--r--Q1.tests/Core/InstructionEncodingTests.cs28
-rw-r--r--Q1.tests/Core/InstructionShapeTests.cs63
-rw-r--r--Q1.tests/Core/Instructions/ControlInstructionTests.cs451
-rw-r--r--Q1.tests/Core/Instructions/InstructionTestBase.cs6
-rw-r--r--Q1.tests/Core/InstructionsTests.cs20
8 files changed, 659 insertions, 20 deletions
diff --git a/Q1.tests/Core/AddressingModesTests.cs b/Q1.tests/Core/AddressingModesTests.cs
index 19be64d..058e373 100644
--- a/Q1.tests/Core/AddressingModesTests.cs
+++ b/Q1.tests/Core/AddressingModesTests.cs
@@ -2,6 +2,7 @@ namespace Q1.tests.Core;
using core;
using core.Arch;
+using core.Arch.Lookups;
[TestFixture]
public class AddressingModesTests
@@ -16,5 +17,8 @@ public class AddressingModesTests
Assert.That(populatedModes, Has.Length.EqualTo(8),
"Expected 8 addressing modes to be defined");
+
+ Assert.That(AddressingModes.Lookup.Length, Is.EqualTo(8),
+ "Expected addressing mode lookup to have 8 entries");
}
} \ No newline at end of file
diff --git a/Q1.tests/Core/ChipTestBase.cs b/Q1.tests/Core/ChipTestBase.cs
new file mode 100644
index 0000000..3540954
--- /dev/null
+++ b/Q1.tests/Core/ChipTestBase.cs
@@ -0,0 +1,20 @@
+namespace Q1.tests.Core;
+
+using Q1.core.Arch;
+using Q1.core.Arch.Constants;
+using Q1.core.Components;
+
+public abstract class ChipTestBase
+{
+ protected Chip CreateChip()
+ {
+ var chip = new Chip();
+
+ var memory = new Memory(ChipLayout.MEMORY_START, ChipLayout.MEMORY_SIZE);
+ var bus = new Bus(0x0, u16.MaxValue);
+ bus.MountDevice(memory);
+
+ bus.AttachChip(chip);
+ return chip;
+ }
+} \ No newline at end of file
diff --git a/Q1.tests/Core/ChipTests.cs b/Q1.tests/Core/ChipTests.cs
new file mode 100644
index 0000000..2b0d20f
--- /dev/null
+++ b/Q1.tests/Core/ChipTests.cs
@@ -0,0 +1,87 @@
+namespace Q1.tests.Core;
+
+using core.Arch;
+using core.Arch.Constants;
+
+[TestFixture]
+public class ChipTests : ChipTestBase
+{
+ [TestCase(ChipRegisters.AX)]
+ [TestCase(ChipRegisters.DX)]
+ [TestCase(ChipRegisters.LX)]
+ public void Register_ShouldRoundTrip(u8 register)
+ {
+ var chip = this.CreateChip();
+
+ u16 value = (u16) (register * 0x1111); // unique value for each register
+ chip.SetRegister(register, value);
+ u16 readValue = chip.GetRegister(register);
+
+ Assert.That(readValue, Is.EqualTo(value), $"Register {register:X2} should round trip");
+ }
+
+ [Test]
+ public void PushPop_ShouldRoundTrip()
+ {
+ var chip = this.CreateChip();
+
+ u16 value = 0xABCD;
+ chip.Push(value);
+ u16 poppedValue = chip.Pop();
+
+ Assert.That(poppedValue, Is.EqualTo(value), "Popped value should match pushed value");
+ }
+
+ [Test]
+ public void StackOverflow_ShouldThrow()
+ {
+ var chip = this.CreateChip();
+
+ // Fill the stack to its limit
+ for (int i = 0; i < ChipLayout.STACK_COUNT; i++)
+ chip.Push((u16) i);
+
+ // Next push should cause overflow
+ Assert.Throws<InvalidOperationException>(() => chip.Push(0xFFFF), "Expected stack overflow to throw");
+ }
+
+ [Test]
+ public void StackUnderflow_ShouldThrow()
+ {
+ var chip = this.CreateChip();
+
+ // Attempt to pop from an empty stack
+ Assert.Throws<InvalidOperationException>(() => chip.Pop(), "Expected stack underflow to throw");
+ }
+
+ [Test]
+ public void InvalidRegisterAccess_ShouldThrow()
+ {
+ var chip = this.CreateChip();
+
+ // Attempt to access an invalid register index
+ Assert.Throws<InvalidOperationException>(() => chip.GetRegister(0xFF), "Expected invalid register access to throw");
+ Assert.Throws<InvalidOperationException>(() => chip.SetRegister(0xFF, 0x1234), "Expected invalid register access to throw");
+ }
+
+ [Test]
+ public void InterruptHandling_ShouldJumpToInterruptVector()
+ {
+ var chip = this.CreateChip();
+
+ var originalPc = chip.Pc;
+
+ // Set up an interrupt vector at 0xFFFE
+ u16 interruptHandlerAddress = 0x1234;
+ chip.RegisterInterruptHandler(8, interruptHandlerAddress); // Register handler for interrupt 8
+
+ // Trigger the interrupt
+ chip.Interrupt(8);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(chip.Pc, Is.EqualTo(interruptHandlerAddress), "PC should jump to interrupt handler address");
+ Assert.That(chip.Pop(), Is.EqualTo(originalPc), "PC should be pushed onto the stack during interrupt");
+ });
+ }
+} \ No newline at end of file
diff --git a/Q1.tests/Core/InstructionEncodingTests.cs b/Q1.tests/Core/InstructionEncodingTests.cs
new file mode 100644
index 0000000..7bb653f
--- /dev/null
+++ b/Q1.tests/Core/InstructionEncodingTests.cs
@@ -0,0 +1,28 @@
+namespace Q1.tests.Core;
+
+using core.Arch;
+
+[TestFixture]
+public class InstructionEncodingTests
+{
+ [Test]
+ public void EncodeDecode_ShouldRoundTrip()
+ {
+ u8 opcode = 0x01;
+ u8 m1 = 0x5;
+ u8 m2 = 0xC;
+ bool word = true;
+
+ u16 instruction = InstructionEncoding.Encode(opcode, m1, m2, word);
+
+ InstructionEncoding.Decode(instruction, out var op2, out var m1_2, out var m2_2, out var word2);
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(op2, Is.EqualTo(opcode));
+ Assert.That(m1_2, Is.EqualTo(m1));
+ Assert.That(m2_2, Is.EqualTo(m2));
+ Assert.That(word2, Is.EqualTo(word));
+ });
+ }
+} \ No newline at end of file
diff --git a/Q1.tests/Core/InstructionShapeTests.cs b/Q1.tests/Core/InstructionShapeTests.cs
new file mode 100644
index 0000000..969ba7e
--- /dev/null
+++ b/Q1.tests/Core/InstructionShapeTests.cs
@@ -0,0 +1,63 @@
+namespace Q1.tests.Core;
+
+using core;
+using core.Arch;
+using core.Arch.Lookups;
+
+[TestFixture]
+public class InstructionShapeTests
+{
+
+ [Test]
+ public void LookupShouldHaveInstructions()
+ {
+ var populatedSets = InstructionSet.Lookup
+ .Where(x => x != default)
+ .ToArray();
+
+ Assert.That(populatedSets, Has.Length.EqualTo(19),
+ "Expected 19 instruction groups to be defined");
+
+ Assert.That(InstructionSet.Lookup.Length, Is.EqualTo(128),
+ "Expected instruction lookup to have 128 entries");
+ }
+
+ [TestCase(0x00, "NOP", "JMP", "HALT", "MOV")]
+ [TestCase(0x01, "RET", "CALL", "SUS", "NOP")]
+ [TestCase(0x02, "BZ(LX)", "BZ", "BR", "NOP")]
+ [TestCase(0x03, "NOP", "PUSH", "NOP", "NOP")]
+ [TestCase(0x04, "NOP", "POP", "NOP", "NOP")]
+ [TestCase(0x05, "NOP", "INT", "NOP", "NOP")]
+
+ [TestCase(0x10, "INV(DX)", "INV", "NOP", "AND")]
+ [TestCase(0x11, "NOP", "NOP", "NOP", "OR")]
+ [TestCase(0x12, "NOP", "NOP", "NOP", "XOR")]
+ [TestCase(0x13, "SHPL(DX)", "SHPL", "NOP", "SHL")]
+ [TestCase(0x14, "SHPR(DX)", "SHPR", "NOP", "SHR")]
+
+ [TestCase(0x20, "NOT(LX)", "NOT", "NOP", "CMP")]
+ [TestCase(0x21, "NOP", "NOP", "NOP", "LT")]
+ [TestCase(0x22, "NOP", "NOP", "NOP", "GT")]
+
+ [TestCase(0x30, "INC(AX)", "INC", "NOP", "ADD")]
+ [TestCase(0x31, "DEC(AX)", "DEC", "NOP", "SUB")]
+ [TestCase(0x32, "NOP", "NOP", "NOP", "DIV")]
+ [TestCase(0x33, "NOP", "NOP", "NOP", "MUL")]
+ [TestCase(0x34, "NOP", "NOP", "NOP", "MOD")]
+ public void GroupLooksLike(i32 opcode, string impl, string simple, string extendedImpl, string extended)
+ {
+ var group = InstructionSet.Lookup[opcode];
+
+ Assert.That(group.Implicit.Name, Is.EqualTo(impl),
+ $"Expected implicit instruction for opcode {opcode:X2} to be {impl}");
+
+ Assert.That(group.SimpleAddressing.Name, Is.EqualTo(simple),
+ $"Expected simple addressing instruction for opcode {opcode:X2} to be {simple}");
+
+ Assert.That(group.ExtendedImplicit.Name, Is.EqualTo(extendedImpl),
+ $"Expected extended implicit instruction for opcode {opcode:X2} to be {extendedImpl}");
+
+ Assert.That(group.ExtendedAddressing.Name, Is.EqualTo(extended),
+ $"Expected extended addressing instruction for opcode {opcode:X2} to be {extended}");
+ }
+} \ No newline at end of file
diff --git a/Q1.tests/Core/Instructions/ControlInstructionTests.cs b/Q1.tests/Core/Instructions/ControlInstructionTests.cs
new file mode 100644
index 0000000..00c9566
--- /dev/null
+++ b/Q1.tests/Core/Instructions/ControlInstructionTests.cs
@@ -0,0 +1,451 @@
+namespace Q1.tests.Core.Instructions;
+
+using core;
+using core.Arch;
+using core.Arch.Constants;
+using core.Arch.Lookups;
+using core.Components;
+
+public class ControlInstructionTests : InstructionTestBase
+{
+ [Test]
+ public void JumpInstruction_JumpsToAddress()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("JMP"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ u16 jumpAddress = 0x1234;
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+ chip.Bus.WriteWord((u16) (chip.Pc + 2), jumpAddress);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(jumpAddress),
+ "PC should jump to the specified address");
+ }
+
+ [Test]
+ public void HaltInstruction_HaltsExecution()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("HALT"),
+ 0,
+ 1,
+ true);
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+
+ // Act
+ var clock = () => chip.Clock();
+
+ // Assert
+ Assert.That(clock, Throws.TypeOf<HaltException>());
+ }
+
+
+ [Test]
+ public void ReturnInstruction_ReturnsFromSubroutine()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ // Simulate a call by pushing a return address onto the stack
+ u16 returnAddress = 0x5678;
+ chip.Push(returnAddress);
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("RET"),
+ 0,
+ 0,
+ true);
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(returnAddress),
+ "PC should return to the address on top of the stack");
+ }
+
+
+ [Test]
+ public void CallInstruction_CallsSubroutine()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+ u16 subroutineAddress = 0x9ABC;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("CALL"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+ chip.Bus.WriteWord((u16) (pc + 2), subroutineAddress);
+
+ u16 expectedReturnAddress = (u16) (pc + 4);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.Multiple(() =>
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(subroutineAddress),
+ "PC should jump to the subroutine address");
+
+ Assert.That(
+ chip.Bus.ReadWord(ChipLayout.STACK_START),
+ Is.EqualTo(expectedReturnAddress),
+ "Return address should be pushed onto the stack");
+ });
+ }
+
+
+ [Test]
+ public void SuspendInstruction_Fails()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("SUS"),
+ 0,
+ 1,
+ true);
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+
+ // Act
+ var clock = () => chip.Clock();
+
+ // Assert
+ Assert.That(clock, Throws.TypeOf<NotImplementedException>());
+ }
+
+
+ [TestCase(0, true)]
+ [TestCase(1, false)]
+ [TestCase(5, false)]
+ public void BranchIfZeroLx_BranchesCorrectly(i32 lxValue, bool shouldBranch)
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("BZ(LX)"),
+ 0,
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+ chip.Lx = (u16) lxValue;
+
+ u16 nextInstructionAddress = (u16) (pc + 2); // Address of the next instruction
+ u16 branchAddress = (u16) (nextInstructionAddress + 2); // Finish current instruction and skip next one
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ if (shouldBranch)
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(branchAddress),
+ "PC should skip the next instruction when Lx is zero");
+ }
+ else
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(nextInstructionAddress),
+ "PC should proceed to the next instruction when Lx is non-zero");
+ }
+ }
+
+ [TestCase(0, true)]
+ [TestCase(1, false)]
+ [TestCase(5, false)]
+ public void BranchIfZero_BranchesCorrectly(int value, bool shouldBranch)
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("BZ"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+ chip.Bus.WriteWord((u16) (pc + 2), (u16) value);
+
+ u16 nextInstructionAddress = (u16) (pc + 4); // Address of the instruction after the next one
+ u16 branchAddress = (u16) (nextInstructionAddress + 2); // Finish current instruction and skip next one
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ if (shouldBranch)
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(branchAddress),
+ "PC should skip the next instruction when the value is zero");
+ }
+ else
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(nextInstructionAddress),
+ "PC should proceed to the next instruction when the value is non-zero");
+ }
+ }
+
+ [Test]
+ public void Branch_SkipsNextInstruction()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("BR"),
+ 0,
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+
+ u16 nextInstructionAddress = (u16) (pc + 2); // Address of the next instruction
+ u16 branchAddress = (u16) (nextInstructionAddress + 2); // Finish current instruction and skip next one
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(branchAddress),
+ "PC should skip the next instruction unconditionally");
+ }
+
+ [Test]
+ public void PushInstruction_PushesValueOntoStack()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+ u16 valueToPush = 0xABCD;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("PUSH"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+ chip.Bus.WriteWord((u16) (pc + 2), valueToPush);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.Multiple(() =>
+ {
+ Assert.That(
+ chip.Bus.ReadWord(ChipLayout.STACK_START),
+ Is.EqualTo(valueToPush),
+ "Value should be pushed onto the stack");
+
+ Assert.That(
+ chip.Sp,
+ Is.EqualTo((u16) (ChipLayout.STACK_START + 2)),
+ "Stack pointer should move up by 2 bytes after push");
+ });
+ }
+
+ [Test]
+ public void PopInstruction_PopsValueFromStack()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16 pc = chip.Pc;
+ u16 valueToPop = 0xABCD;
+
+ // Simulate a push by writing a value to the stack and moving the stack pointer
+ chip.Bus.WriteWord(ChipLayout.STACK_START, valueToPop);
+ chip.Sp = ChipLayout.STACK_START + 2;
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("POP"),
+ AddressingModes.GetAddressingMode("Register"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(pc, instruction);
+ chip.Bus.Write((u16) (pc + 2), ChipRegisters.DX);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.Multiple(() =>
+ {
+ Assert.That(
+ chip.Dx,
+ Is.EqualTo(valueToPop),
+ "Value should be popped from the stack into the register");
+
+ Assert.That(
+ chip.Sp,
+ Is.EqualTo(ChipLayout.STACK_START),
+ "Stack pointer should move down by 2 bytes after pop");
+ });
+ }
+
+ [Test]
+ public void PushPopSequence_WorksCorrectly()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ u16[] valuesToPush = [0x1111, 0x2222, 0x3333];
+
+ void PushValue(u16 value)
+ {
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("PUSH"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+ chip.Bus.WriteWord((u16) (chip.Pc + 2), value);
+ chip.Clock();
+ }
+
+ u16 PopValue()
+ {
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("POP"),
+ AddressingModes.GetAddressingMode("Register"),
+ 0,
+ true);
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+ chip.Bus.Write((u16) (chip.Pc + 2), ChipRegisters.DX);
+
+ chip.Clock();
+
+ return chip.Dx;
+ }
+
+ // Act & Assert
+ // Push 1 item, then pop it, then push 2 items, then pop them
+ Assert.Multiple(() =>
+ {
+ PushValue(valuesToPush[0]);
+ Assert.That(
+ PopValue(),
+ Is.EqualTo(valuesToPush[0]),
+ "First popped value should match the first pushed value");
+
+ PushValue(valuesToPush[1]);
+ PushValue(valuesToPush[2]);
+ Assert.That(
+ PopValue(),
+ Is.EqualTo(valuesToPush[2]),
+ "Second popped value should match the second pushed value");
+ Assert.That(
+ PopValue(),
+ Is.EqualTo(valuesToPush[1]),
+ "Third popped value should match the first pushed value");
+ });
+ }
+
+ [Test]
+ public void InterruptInstruction_TriggersInterrupt()
+ {
+ // Arrange
+ var chip = CreateChip();
+
+ var instruction = InstructionEncoding
+ .Encode(
+ InstructionSet.GetOpcode("INT"),
+ AddressingModes.GetAddressingMode("Immediate"),
+ 0,
+ true);
+
+ u8 interruptNumber = 8;
+
+ chip.Bus.WriteWord(chip.Pc, instruction);
+ chip.Bus.WriteWord((u16) (chip.Pc + 2), interruptNumber);
+
+ u16 expectedReturnPc = (u16) (chip.Pc + 4); // After the INT instruction and its operand
+ u16 handlerAddress = 0x2345;
+
+ chip.RegisterInterruptHandler(interruptNumber, handlerAddress);
+
+ // Act
+ chip.Clock();
+
+ // Assert
+ Assert.Multiple(() =>
+ {
+ Assert.That(
+ chip.Pc,
+ Is.EqualTo(handlerAddress),
+ "PC should jump to the interrupt handler address");
+
+ Assert.That(
+ chip.Bus.ReadWord(ChipLayout.STACK_START),
+ Is.EqualTo(expectedReturnPc),
+ "PC should be pushed onto the stack during interrupt");
+ });
+ }
+} \ No newline at end of file
diff --git a/Q1.tests/Core/Instructions/InstructionTestBase.cs b/Q1.tests/Core/Instructions/InstructionTestBase.cs
new file mode 100644
index 0000000..e0cdad4
--- /dev/null
+++ b/Q1.tests/Core/Instructions/InstructionTestBase.cs
@@ -0,0 +1,6 @@
+namespace Q1.tests.Core.Instructions;
+
+public abstract class InstructionTestBase : ChipTestBase
+{
+
+} \ No newline at end of file
diff --git a/Q1.tests/Core/InstructionsTests.cs b/Q1.tests/Core/InstructionsTests.cs
deleted file mode 100644
index 45c85ee..0000000
--- a/Q1.tests/Core/InstructionsTests.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Q1.tests.Core;
-
-using core;
-using core.Arch;
-
-[TestFixture]
-public class InstructionsTests
-{
-
- [Test]
- public void LookupShouldHaveInstructions()
- {
- var populatedSets = InstructionSet.Lookup
- .Where(x => x != default)
- .ToArray();
-
- Assert.That(populatedSets, Has.Length.EqualTo(19),
- "Expected 19 instruction groups to be defined");
- }
-} \ No newline at end of file