qbyte Read(qbyte address, AddressingMode mode) { switch (mode) { case AddressingMode.Immediate: { return(address); } case AddressingMode.Absolute: { return(mmu.Read(address)); } case AddressingMode.Indirect: { return(mmu.Read(Read(address, AddressingMode.Register))); } case AddressingMode.Register: { return(registers.Get(address)); } } throw new Exception("invalid read value: " + address); }
void jle(qbyte addr, qbyte b, qbyte c) { if (Read(b, OpNum.Two) <= Read(c, OpNum.Three)) { jmp(addr); } }
void jgt(qbyte addr, qbyte b, qbyte c) { if (Read(b, OpNum.Two) > Read(c, OpNum.Three)) { jmp(addr); } }
void sys(qbyte addr) { qbyte v = Read(addr, AddressingMode.Immediate); if (!syscallbacks.ContainsKey(v)) { throw new Exception("syscall " + v + " not provided"); } syscallbacks[v].Invoke(); }
public qbyte Get(qbyte n) { switch (n) { case 0: return(a); case 1: return(b); case 2: return(c); case 3: return(d); case 4: return(x); case 5: return(y); } throw new Exception("attempted to write to unknown register " + n); }
void Write(qbyte address, qbyte _value, AddressingMode mode) { qbyte value = _value; while (value < 0) { value += 0x10000; } while (value > 0xffff) { value -= 0x10000; } switch (mode) { case AddressingMode.Immediate: { throw new Exception("cannot write to immediate value " + address + " (value: " + value + ")"); } case AddressingMode.Absolute: { mmu.Write(address, value); } break; case AddressingMode.Indirect: { mmu.Write(Read(address, AddressingMode.Register), value); } break; case AddressingMode.Register: { registers.Set(address, value); } break; } }
void sub(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) - Read(b, OpNum.Two), OpNum.One); }
void jsr(qbyte addr) { callstack.Push(pc); jmp(addr); }
qbyte Read(qbyte address, OpNum arity) { return(Read(address, Mode(arity))); }
void not(qbyte a) { Write(a, ~Read(a, OpNum.One), OpNum.One); }
void and(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) & Read(b, OpNum.Two), OpNum.One); }
void ext(qbyte code) { pc--; exit = true; }
public void AddSysCallback(qbyte key, Action callback) { syscallbacks[key] = callback; }
void Write(qbyte address, qbyte value, OpNum arity) { Write(address, value, Mode(arity)); }
void mul(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) * Read(b, OpNum.Two), OpNum.One); }
void mod(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) % Read(b, OpNum.Two), OpNum.One); }
void mov(qbyte to, qbyte from) { Write(to, Read(from, OpNum.Two), OpNum.One); }
void orr(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) | Read(b, OpNum.Two), OpNum.One); }
void jmp(qbyte addr) { pc = Read(addr, OpNum.One) - 1; }
void xor(qbyte a, qbyte b) { Write(a, Read(a, OpNum.One) ^ Read(b, OpNum.Two), OpNum.One); }
public bool Step() { qbyte opcode = mmu.Read(pc); qbyte op = (opcode & 0x00FF); lastop = opcode; qbyte arity = Constants.kArities[op]; qbyte start = pc + 1; var args = mmu.memory.Slice(start, start + arity); pc += arity; cycles++; switch (op) { case 0: { nop(); } break; case 1: { ext(args[0]); } break; case 2: { sys(args[0]); } break; case 3: { mov(args[0], args[1]); } break; case 4: { jmp(args[0]); } break; case 5: { jeq(args[0], args[1], args[2]); } break; case 6: { jne(args[0], args[1], args[2]); } break; case 7: { jgt(args[0], args[1], args[2]); } break; case 8: { jge(args[0], args[1], args[2]); } break; case 9: { jlt(args[0], args[1], args[2]); } break; case 10: { jle(args[0], args[1], args[2]); } break; case 11: { jsr(args[0]); } break; case 12: { ret(); } break; case 13: { add(args[0], args[1]); } break; case 14: { sub(args[0], args[1]); } break; case 15: { mul(args[0], args[1]); } break; case 16: { mod(args[0], args[1]); } break; case 17: { and(args[0], args[1]); } break; case 18: { orr(args[0], args[1]); } break; case 19: { not(args[0]); } break; case 20: { xor(args[0], args[1]); } break; case 21: { lsl(args[0], args[1]); } break; case 22: { lsr(args[0], args[1]); } break; case 23: { psh(args[0]); } break; case 24: { pop(args[0]); } break; } pc++; return(exit); }