diff options
Diffstat (limited to '6502/src')
| -rw-r--r-- | 6502/src/6502.c | 197 | ||||
| -rw-r--r-- | 6502/src/test.c | 142 |
2 files changed, 228 insertions, 111 deletions
diff --git a/6502/src/6502.c b/6502/src/6502.c index c9b802d..add78a0 100644 --- a/6502/src/6502.c +++ b/6502/src/6502.c @@ -15,162 +15,137 @@ void l6502_mem_basic_new(l6502_mem *m) { m->data = calloc(1 << 16, sizeof(u8)); } -static u8 l6502_flag_get(l6502_emu *e, l6502_flag f) { return (e->regs.flags & (u8) f) != 0; } -static void l6502_flag_set(l6502_emu *e, l6502_flag f, u8 v) { - if (v) e->regs.flags |= (u8) f; - else e->regs.flags &= ~((u8) f); -} -static void l6502_flags_check_zn(l6502_emu *e, u8 v) { +static void flags_check_zn(l6502_emu *e, u8 v) { l6502_flag_set(e, L6502_FLAG_ZERO, v == 0); l6502_flag_set(e, L6502_FLAG_NEGATIVE, (v >> 7) & 0b1); } -static u8 l6502_read(l6502_emu *e, u16 addr) { return e->mem.rh(e->mem.data, addr); } -static void l6502_write(l6502_emu *e, u16 addr, u8 val) { e->mem.wh(e->mem.data, addr, val); } -static u16 l6502_read_addr(l6502_emu *e, u16 addr) { - u8 alo = l6502_read(e, addr); - u8 ahi = l6502_read(e, addr + 1); - return ahi << 8 | alo; -} - -static u8 l6502_pop(l6502_emu *e) { return l6502_read(e, 0x0100 + (u16) ++e->regs.sp); } -static void l6502_push(l6502_emu *e, u8 val) { l6502_write(e, 0x0100 + (u16) e->regs.sp--, val); } -static u16 l6502_pop_addr(l6502_emu *e) { - u8 ahi = l6502_pop(e); - u8 alo = l6502_pop(e); - return ahi << 8 | alo; -} -static void l6502_push_addr(l6502_emu *e, u16 addr) { - l6502_push(e, (u8) (addr & 0xff)); - l6502_push(e, (u8) (addr >> 8)); -} - -static u16 l6502_addressing_mode_immediate(l6502_emu *e) { - return e->regs.pc++; +static u16 amode_immediate(l6502_emu *e) { + return e->pc++; } -static u16 l6502_addressing_mode_absolute(l6502_emu *e) { - u16 addr = l6502_read_addr(e, e->regs.pc); - e->regs.pc += 2; +static u16 amode_absolute(l6502_emu *e) { + u16 addr = l6502_read_addr(e, e->pc); + e->pc += 2; return addr; } -static u16 l6502_addressing_mode_absolute_x(l6502_emu *e) { - u16 addr = l6502_read_addr(e, e->regs.pc) + (u16) e->regs.x; - e->regs.pc += 2; +static u16 amode_absolute_x(l6502_emu *e) { + u16 addr = l6502_read_addr(e, e->pc) + (u16) e->regs[L6502_REG_X]; + e->pc += 2; return addr; } -static u16 l6502_addressing_mode_absolute_y(l6502_emu *e) { - u16 addr = l6502_read_addr(e, e->regs.pc) + (u16) e->regs.y; - e->regs.pc += 2; +static u16 amode_absolute_y(l6502_emu *e) { + u16 addr = l6502_read_addr(e, e->pc) + (u16) e->regs[L6502_REG_Y]; + e->pc += 2; return addr; } -static u16 l6502_addressing_mode_zeropage(l6502_emu *e) { - return (u16) l6502_read(e, e->regs.pc++); +static u16 amode_zeropage(l6502_emu *e) { + return (u16) l6502_read(e, e->pc++); } -static u16 l6502_addressing_mode_zeropage_x(l6502_emu *e) { - return (u16) (l6502_read(e, e->regs.pc++) + e->regs.x); +static u16 amode_zeropage_x(l6502_emu *e) { + return (u16) (l6502_read(e, e->pc++) + e->regs[L6502_REG_X]); } -static u16 l6502_addressing_mode_indirect_zeropage_x(l6502_emu *e) { - return l6502_read_addr(e, l6502_read(e, e->regs.pc++) + e->regs.x); +static u16 amode_indirect_zeropage_x(l6502_emu *e) { + return l6502_read_addr(e, l6502_read(e, e->pc++) + (u16) e->regs[L6502_REG_X]); } -static u16 l6502_addressing_mode_indirect_zeropage_y(l6502_emu *e) { - return l6502_read_addr(e, l6502_read(e, e->regs.pc++)) + (u16) e->regs.y; +static u16 amode_indirect_zeropage_y(l6502_emu *e) { + return l6502_read_addr(e, l6502_read(e, e->pc++)) + (u16) e->regs[L6502_REG_Y]; } void l6502_emulate(l6502_emu *e) { - u8 ins = l6502_read(e, e->regs.pc++); + u8 ins = l6502_read(e, e->pc++); u8 val = 0; u16 res = 0; bool set_flags = true; bool set_result = true; - u8 *set_reg = NULL; + l6502_reg set_reg = L6502_REG__MARKER; u16 addr = 0; switch (ins) { /* identify some special-case instructions */ case BRK: - l6502_push_addr(e, e->regs.pc); - l6502_push(e, e->regs.flags); - e->regs.pc = l6502_read_addr(e, 0xfffe); + l6502_push_addr(e, e->pc); + l6502_push(e, e->regs[L6502_REG_FLAGS]); + e->pc = l6502_read_addr(e, 0xfffe); l6502_flag_set(e, L6502_FLAG_BREAK_COMMAND, true); break; - case PHP: l6502_push(e, e->regs.flags); break; + case PHP: l6502_push(e, e->regs[L6502_REG_FLAGS]); break; case CLC: l6502_flag_set(e, L6502_FLAG_CARRY, false); break; case JSR: - addr = l6502_read_addr(e, e->regs.pc); - l6502_push_addr(e, e->regs.pc + 1); - e->regs.pc = addr; + addr = l6502_read_addr(e, e->pc); + l6502_push_addr(e, e->pc + 1); + e->pc = addr; break; - case PLP: e->regs.flags = l6502_pop(e); break; + case PLP: e->regs[L6502_REG_FLAGS] = l6502_pop(e); break; case SEC: l6502_flag_set(e, L6502_FLAG_CARRY, true); break; case RTI: - e->regs.flags = l6502_pop(e); - e->regs.pc = l6502_pop_addr(e); + e->regs[L6502_REG_FLAGS] = l6502_pop(e); + e->pc = l6502_pop_addr(e); break; - case PHA: l6502_push(e, e->regs.a); break; + case PHA: l6502_push(e, e->regs[L6502_REG_A]); break; case JMP_ABSOLUTE: - addr = l6502_read_addr(e, e->regs.pc); - e->regs.pc = addr; + addr = l6502_read_addr(e, e->pc); + e->pc = addr; break; case CLI: l6502_flag_set(e, L6502_FLAG_INTERRUPT_DISABLE, false); break; - case RTS: e->regs.pc = l6502_pop_addr(e) + 1; break; - case PLA: e->regs.a = l6502_pop(e); break; + case RTS: e->pc = l6502_pop_addr(e) + 1; break; + case PLA: e->regs[L6502_REG_A] = l6502_pop(e); break; case JMP_INDIRECT: - addr = l6502_read_addr(e, l6502_read_addr(e, e->regs.pc)); - e->regs.pc = addr; + addr = l6502_read_addr(e, l6502_read_addr(e, e->pc)); + e->pc = addr; break; case SEI: l6502_flag_set(e, L6502_FLAG_INTERRUPT_DISABLE, true); break; - case DEY: e->regs.y -= 1; l6502_flags_check_zn(e, e->regs.y); break; - case TXA: e->regs.a = e->regs.x; l6502_flags_check_zn(e, e->regs.a); break; - case TYA: e->regs.a = e->regs.y; l6502_flags_check_zn(e, e->regs.a); break; - case TXS: e->regs.sp = e->regs.x; break; /* note TXS does not set flags */ - case TAY: e->regs.y = e->regs.a; l6502_flags_check_zn(e, e->regs.y); break; - case TAX: e->regs.x = e->regs.a; l6502_flags_check_zn(e, e->regs.x); break; + case DEY: e->regs[L6502_REG_Y] -= 1; flags_check_zn(e, e->regs[L6502_REG_Y]); break; + case TXA: e->regs[L6502_REG_A] = e->regs[L6502_REG_X]; flags_check_zn(e, e->regs[L6502_REG_A]); break; + case TYA: e->regs[L6502_REG_A] = e->regs[L6502_REG_Y]; flags_check_zn(e, e->regs[L6502_REG_A]); break; + case TXS: e->regs[L6502_REG_SP] = e->regs[L6502_REG_X]; break; /* note TXS does not set flags */ + case TAY: e->regs[L6502_REG_Y] = e->regs[L6502_REG_A]; flags_check_zn(e, e->regs[L6502_REG_Y]); break; + case TAX: e->regs[L6502_REG_X] = e->regs[L6502_REG_A]; flags_check_zn(e, e->regs[L6502_REG_X]); break; case CLV: l6502_flag_set(e, L6502_FLAG_OVERFLOW, false); break; - case TSX: e->regs.x = e->regs.sp; l6502_flags_check_zn(e, e->regs.x); break; - case INY: e->regs.y += 1; l6502_flags_check_zn(e, e->regs.y); break; - case DEX: e->regs.x -= 1; l6502_flags_check_zn(e, e->regs.x); break; + case TSX: e->regs[L6502_REG_X] = e->regs[L6502_REG_SP]; flags_check_zn(e, e->regs[L6502_REG_X]); break; + case INY: e->regs[L6502_REG_Y] += 1; flags_check_zn(e, e->regs[L6502_REG_Y]); break; + case DEX: e->regs[L6502_REG_X] -= 1; flags_check_zn(e, e->regs[L6502_REG_X]); break; case CLD: l6502_flag_set(e, L6502_FLAG_DECIMAL, false); break; - case INX: e->regs.x += 1; l6502_flags_check_zn(e, e->regs.x); break; + case INX: e->regs[L6502_REG_X] += 1; flags_check_zn(e, e->regs[L6502_REG_X]); break; case NOP: break; case SED: l6502_flag_set(e, L6502_FLAG_DECIMAL, true); break; } if ((ins & 0b11111) == 0b10000) { /* identify conditional branches */ l6502_flag flags[4] = { L6502_FLAG_NEGATIVE, L6502_FLAG_OVERFLOW, L6502_FLAG_CARRY, L6502_FLAG_ZERO }; - u8 off = l6502_read(e, e->regs.pc++); + u8 off = l6502_read(e, e->pc++); if (l6502_flag_get(e, flags[(ins >> 6) & 0b11]) == ((ins >> 5) & 0b1)) { - e->regs.pc = (u16) ((i16) e->regs.pc + (i16) (i8) off); + e->pc = (u16) ((i16) e->pc + (i16) (i8) off); } return; } switch (ins & 0b11) { /* identify instructions in common forms */ case 0b01: { /* group one */ - set_reg = &e->regs.a; + set_reg = L6502_REG_A; switch ((ins >> 2) & 0b111) { - case G1_ADDRESSING_MODE_INDIRECT_ZEROPAGE_X: addr = l6502_addressing_mode_indirect_zeropage_x(e); break; - case G1_ADDRESSING_MODE_ZEROPAGE: addr = l6502_addressing_mode_zeropage(e); break; - case G1_ADDRESSING_MODE_IMMEDIATE: addr = l6502_addressing_mode_immediate(e); break; - case G1_ADDRESSING_MODE_ABSOLUTE: addr = l6502_addressing_mode_absolute(e); break; - case G1_ADDRESSING_MODE_INDIRECT_ZEROPAGE_Y: addr = l6502_addressing_mode_indirect_zeropage_y(e); break; - case G1_ADDRESSING_MODE_ZEROPAGE_X: addr = l6502_addressing_mode_zeropage_x(e); break; - case G1_ADDRESSING_MODE_ABSOLUTE_Y: addr = l6502_addressing_mode_absolute_y(e); break; - case G1_ADDRESSING_MODE_ABSOLUTE_X: addr = l6502_addressing_mode_absolute_x(e); break; + case G1_ADDRESSING_MODE_INDIRECT_ZEROPAGE_X: addr = amode_indirect_zeropage_x(e); break; + case G1_ADDRESSING_MODE_ZEROPAGE: addr = amode_zeropage(e); break; + case G1_ADDRESSING_MODE_IMMEDIATE: addr = amode_immediate(e); break; + case G1_ADDRESSING_MODE_ABSOLUTE: addr = amode_absolute(e); break; + case G1_ADDRESSING_MODE_INDIRECT_ZEROPAGE_Y: addr = amode_indirect_zeropage_y(e); break; + case G1_ADDRESSING_MODE_ZEROPAGE_X: addr = amode_zeropage_x(e); break; + case G1_ADDRESSING_MODE_ABSOLUTE_Y: addr = amode_absolute_y(e); break; + case G1_ADDRESSING_MODE_ABSOLUTE_X: addr = amode_absolute_x(e); break; } val = l6502_read(e, addr); switch ((ins >> 5) & 0b111) { - case G1_OPCODE_ORA: res = (u16) e->regs.a | (u16) val; break; - case G1_OPCODE_AND: res = (u16) e->regs.a & (u16) val; break; - case G1_OPCODE_EOR: res = (u16) e->regs.a ^ (u16) val; break; + case G1_OPCODE_ORA: res = (u16) e->regs[L6502_REG_A] | (u16) val; break; + case G1_OPCODE_AND: res = (u16) e->regs[L6502_REG_A] & (u16) val; break; + case G1_OPCODE_EOR: res = (u16) e->regs[L6502_REG_A] ^ (u16) val; break; case G1_OPCODE_ADC: - res = (u16) e->regs.a + (u16) val; + res = (u16) e->regs[L6502_REG_A] + (u16) val; res += (u16) l6502_flag_get(e, L6502_FLAG_CARRY); l6502_flag_set(e, L6502_FLAG_OVERFLOW, ((res >> 8) != 0) != ((res >> 7) & 0b1)); break; - case G1_OPCODE_STA: l6502_write(e, addr, e->regs.a); set_flags = set_result = false; break; + case G1_OPCODE_STA: l6502_write(e, addr, e->regs[L6502_REG_A]); set_flags = set_result = false; break; case G1_OPCODE_LDA: res = (u16) l6502_read(e, addr); break; case G1_OPCODE_CMP: set_result = false; - res = (u16) e->regs.a - (u16) val; + res = (u16) e->regs[L6502_REG_A] - (u16) val; break; case G1_OPCODE_SBC: - res = (u16) e->regs.a - (u16) val; + res = (u16) e->regs[L6502_REG_A] - (u16) val; res -= (u16) (1 - l6502_flag_get(e, L6502_FLAG_CARRY)); l6502_flag_set(e, L6502_FLAG_OVERFLOW, ((res >> 8) != 0) != ((res >> 7) & 0b1)); break; @@ -179,12 +154,12 @@ void l6502_emulate(l6502_emu *e) { } case 0b10: { /* group two */ switch ((ins >> 2) & 0b111) { - case G2_ADDRESSING_MODE_IMMEDIATE: addr = l6502_addressing_mode_immediate(e); break; - case G2_ADDRESSING_MODE_ZEROPAGE: addr = l6502_addressing_mode_zeropage(e); break; - case G2_ADDRESSING_MODE_ACCUMULATOR: addr = (u16) e->regs.a; set_reg = &e->regs.a; break; - case G2_ADDRESSING_MODE_ABSOLUTE: addr = l6502_addressing_mode_absolute(e); break; - case G2_ADDRESSING_MODE_ZEROPAGE_X: addr = l6502_addressing_mode_zeropage_x(e); break; - case G2_ADDRESSING_MODE_ABSOLUTE_X: addr = l6502_addressing_mode_absolute_x(e); break; + case G2_ADDRESSING_MODE_IMMEDIATE: addr = amode_immediate(e); break; + case G2_ADDRESSING_MODE_ZEROPAGE: addr = amode_zeropage(e); break; + case G2_ADDRESSING_MODE_ACCUMULATOR: addr = (u16) e->regs[L6502_REG_A]; set_reg = L6502_REG_A; break; + case G2_ADDRESSING_MODE_ABSOLUTE: addr = amode_absolute(e); break; + case G2_ADDRESSING_MODE_ZEROPAGE_X: addr = amode_zeropage_x(e); break; + case G2_ADDRESSING_MODE_ABSOLUTE_X: addr = amode_absolute_x(e); break; } val = set_reg ? (u8) addr : l6502_read(e, addr); switch ((ins >> 5) & 0b111) { @@ -199,8 +174,8 @@ void l6502_emulate(l6502_emu *e) { | (u16) l6502_flag_get(e, L6502_FLAG_CARRY) << 7 | (u16) (val & 0b1) << 8; /* same as above */ break; - case G2_OPCODE_STX: l6502_write(e, addr, e->regs.x); set_flags = set_result = false; break; - case G2_OPCODE_LDX: res = (u16) l6502_read(e, addr); set_reg = &e->regs.x; break; + case G2_OPCODE_STX: l6502_write(e, addr, e->regs[L6502_REG_X]); set_flags = set_result = false; break; + case G2_OPCODE_LDX: res = (u16) l6502_read(e, addr); set_reg = L6502_REG_X; break; case G2_OPCODE_DEC: res = (u16) val - 1; break; case G2_OPCODE_INC: res = (u16) val + 1; break; } @@ -208,29 +183,29 @@ void l6502_emulate(l6502_emu *e) { } case 0b00: { /* group three */ switch ((ins >> 2) & 0b111) { - case G3_ADDRESSING_MODE_IMMEDIATE: addr = l6502_addressing_mode_immediate(e); break; - case G3_ADDRESSING_MODE_ZEROPAGE: addr = l6502_addressing_mode_zeropage(e); break; - case G3_ADDRESSING_MODE_ABSOLUTE: addr = l6502_addressing_mode_absolute(e); break; - case G3_ADDRESSING_MODE_ZEROPAGE_X: addr = l6502_addressing_mode_zeropage_x(e); break; - case G3_ADDRESSING_MODE_ABSOLUTE_X: addr = l6502_addressing_mode_absolute_x(e); break; + case G3_ADDRESSING_MODE_IMMEDIATE: addr = amode_immediate(e); break; + case G3_ADDRESSING_MODE_ZEROPAGE: addr = amode_zeropage(e); break; + case G3_ADDRESSING_MODE_ABSOLUTE: addr = amode_absolute(e); break; + case G3_ADDRESSING_MODE_ZEROPAGE_X: addr = amode_zeropage_x(e); break; + case G3_ADDRESSING_MODE_ABSOLUTE_X: addr = amode_absolute_x(e); break; } val = l6502_read(e, addr); switch ((ins >> 5) & 0b111) { case G3_OPCODE_BIT: set_flags = set_result = false; - l6502_flag_set(e, L6502_FLAG_ZERO, (e->regs.a & val) == 0); + l6502_flag_set(e, L6502_FLAG_ZERO, (e->regs[L6502_REG_A] & val) == 0); l6502_flag_set(e, L6502_FLAG_OVERFLOW, (val >> 6) & 0b1); l6502_flag_set(e, L6502_FLAG_NEGATIVE, (val >> 7) & 0b1); break; - case G3_OPCODE_STY: l6502_write(e, addr, e->regs.y); set_flags = set_result = false; break; - case G3_OPCODE_LDY: res = (u16) l6502_read(e, addr); set_reg = &e->regs.y; break; + case G3_OPCODE_STY: l6502_write(e, addr, e->regs[L6502_REG_Y]); set_flags = set_result = false; break; + case G3_OPCODE_LDY: res = (u16) l6502_read(e, addr); set_reg = L6502_REG_Y; break; case G3_OPCODE_CPY: set_result = false; - res = (u16) e->regs.y - (u16) val; + res = (u16) e->regs[L6502_REG_Y] - (u16) val; break; case G3_OPCODE_CPX: set_result = false; - res = (u16) e->regs.x - (u16) val; + res = (u16) e->regs[L6502_REG_X] - (u16) val; break; } } @@ -241,7 +216,7 @@ void l6502_emulate(l6502_emu *e) { l6502_flag_set(e, L6502_FLAG_CARRY, (res >> 8) != 0); } if (set_result) { - if (set_reg) *set_reg = (u8) res; + if (set_reg != L6502_REG__MARKER) e->regs[set_reg] = (u8) res; else l6502_write(e, addr, (u8) res); } } diff --git a/6502/src/test.c b/6502/src/test.c new file mode 100644 index 0000000..1b4e241 --- /dev/null +++ b/6502/src/test.c @@ -0,0 +1,142 @@ +/* test harness - we build this to a shared object and then run it from Lua */ +/* see the ../test directory */ + +#include <stdlib.h> +#include <stdio.h> +#include <lua.h> +#include <lcq/6502.h> + +static l6502_emu *get_emu(lua_State *l) { + l6502_emu *e = lua_touserdata(l, 1); + if (!e) { lua_pushliteral(l, "expected emulator as first argument"); lua_error(l); } + return e; +} + +int emu_summary(lua_State *l); +int emu_summary(lua_State *l) { + l6502_emu *e = get_emu(l); + lua_newtable(l); + lua_pushinteger(l, e->pc); lua_setfield(l, -2, "pc"); + lua_newtable(l); + lua_pushinteger(l, e->regs[L6502_REG_SP]); lua_setfield(l, -2, "sp"); + lua_pushinteger(l, e->regs[L6502_REG_A]); lua_setfield(l, -2, "a"); + lua_pushinteger(l, e->regs[L6502_REG_X]); lua_setfield(l, -2, "x"); + lua_pushinteger(l, e->regs[L6502_REG_Y]); lua_setfield(l, -2, "y"); + lua_setfield(l, -2, "regs"); + lua_newtable(l); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_CARRY)); lua_setfield(l, -2, "carry"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_ZERO)); lua_setfield(l, -2, "zero"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_INTERRUPT_DISABLE)); lua_setfield(l, -2, "interrupt_disable"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_DECIMAL)); lua_setfield(l, -2, "decimal"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_BREAK_COMMAND)); lua_setfield(l, -2, "break_command"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_OVERFLOW)); lua_setfield(l, -2, "overflow"); + lua_pushinteger(l, l6502_flag_get(e, L6502_FLAG_NEGATIVE)); lua_setfield(l, -2, "negative"); + lua_setfield(l, -2, "flags"); + return 1; +} + +int emu_get_reg(lua_State *l); +int emu_get_reg(lua_State *l) { + l6502_emu *e = get_emu(l); + l6502_reg r = lua_tointeger(l, 2); + if (r >= 0 && r < L6502_REG__MARKER) lua_pushinteger(l, e->regs[r]); + else { lua_pushliteral(l, "invalid register"); lua_error(l); } + return 1; +} +int emu_set_reg(lua_State *l); +int emu_set_reg(lua_State *l) { + l6502_emu *e = get_emu(l); + l6502_reg r = lua_tointeger(l, 2); + u8 v = (u8) lua_tointeger(l, 3); + if (r >= 0 && r < L6502_REG__MARKER) e->regs[r] = v; + else { lua_pushliteral(l, "invalid register"); lua_error(l); } + lua_pushvalue(l, 1); + return 1; +} + +int emu_get_flag(lua_State *l); +int emu_get_flag(lua_State *l) { + l6502_emu *e = get_emu(l); + l6502_flag f = lua_tointeger(l, 2); + lua_pushinteger(l, l6502_flag_get(e, f)); + return 1; +} +int emu_set_flag(lua_State *l); +int emu_set_flag(lua_State *l) { + l6502_emu *e = get_emu(l); + l6502_flag f = lua_tointeger(l, 2); + u8 v = (u8) lua_tointeger(l, 3); + l6502_flag_set(e, f, v); + lua_pushvalue(l, 1); + return 1; +} + +int emu_get_pc(lua_State *l); +int emu_get_pc(lua_State *l) { + l6502_emu *e = get_emu(l); + lua_pushinteger(l, e->pc); + return 1; +} + +int emu_set_pc(lua_State *l); +int emu_set_pc(lua_State *l) { + l6502_emu *e = get_emu(l); + e->pc = (u16) lua_tointeger(l, 2); + lua_pushvalue(l, 1); + return 1; +} + +int emu_emulate(lua_State *l); +int emu_emulate(lua_State *l) { + l6502_emu *e = get_emu(l); + l6502_emulate(e); + return 1; +} + +int new(lua_State *l); +int new(lua_State *l) { + l6502_emu *e = lua_newuserdata(l, sizeof(l6502_emu)); + l6502_mem_basic_new(&e->mem); + lua_newtable(l); + lua_newtable(l); + lua_pushcfunction(l, emu_summary); lua_setfield(l, -2, "summary"); + lua_pushcfunction(l, emu_get_reg); lua_setfield(l, -2, "reg"); + lua_pushcfunction(l, emu_set_reg); lua_setfield(l, -2, "set-reg"); + lua_pushcfunction(l, emu_get_flag); lua_setfield(l, -2, "flag"); + lua_pushcfunction(l, emu_set_flag); lua_setfield(l, -2, "set-flag"); + lua_pushcfunction(l, emu_get_pc); lua_setfield(l, -2, "pc"); + lua_pushcfunction(l, emu_set_pc); lua_setfield(l, -2, "set-pc"); + lua_pushcfunction(l, emu_emulate); lua_setfield(l, -2, "emulate"); + lua_setfield(l, -2, "__index"); + lua_setmetatable(l, -2); + return 1; +} + +#define PUSH_ENUM(enum, field) { lua_pushinteger(l, enum ## _ ## field); lua_setfield(l, -2, #field); } +static void push_enum_flag(lua_State *l) { + lua_newtable(l); + PUSH_ENUM(L6502_FLAG, CARRY); + PUSH_ENUM(L6502_FLAG, ZERO); + PUSH_ENUM(L6502_FLAG, INTERRUPT_DISABLE); + PUSH_ENUM(L6502_FLAG, DECIMAL); + PUSH_ENUM(L6502_FLAG, BREAK_COMMAND); + PUSH_ENUM(L6502_FLAG, OVERFLOW); + PUSH_ENUM(L6502_FLAG, NEGATIVE); +} +static void push_enum_reg(lua_State *l) { + lua_newtable(l); + PUSH_ENUM(L6502_REG, SP); + PUSH_ENUM(L6502_REG, A); + PUSH_ENUM(L6502_REG, X); + PUSH_ENUM(L6502_REG, Y); + PUSH_ENUM(L6502_REG, FLAGS); +} + +int luaopen_l6502(lua_State *l); +int luaopen_l6502(lua_State *l) { + lua_newtable(l); + push_enum_flag(l); lua_setfield(l, -2, "flag"); + push_enum_reg(l); lua_setfield(l, -2, "reg"); + lua_pushcfunction(l, new); lua_setfield(l, -2, "new"); + return 1; +} |
