summaryrefslogtreecommitdiff
path: root/Q1.core/Arch/Chip.cs
diff options
context:
space:
mode:
authorMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-17 20:49:22 +1000
committerMelodi <62381002+Melodi17@users.noreply.github.com>2026-03-17 20:49:22 +1000
commit18868128e18d38b706e7df14e8e683e1a9739c17 (patch)
tree6f0e0e5eee646f10cbad9c0c89c24d330bc58cc6 /Q1.core/Arch/Chip.cs
parentd87ab8af4c86a3fc6ee237444e372d87e536e3ef (diff)
chore: Initial commit
Diffstat (limited to 'Q1.core/Arch/Chip.cs')
-rw-r--r--Q1.core/Arch/Chip.cs143
1 files changed, 143 insertions, 0 deletions
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