From: Nick Downing Date: Sun, 11 Aug 2024 20:55:48 +0000 (+1000) Subject: In /star_blazer_emu, add 65c02 emulator from multi_emu.git commit 900d9fa3 instead... X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=419b31987b16cdc618dd2842d946c74a8589942a;p=star_disasm.git In /star_blazer_emu, add 65c02 emulator from multi_emu.git commit 900d9fa3 instead of vrEmu6502, with corresponding update to /utils/disasm_to_c.py --- diff --git a/.gitmodules b/.gitmodules index e026680..60cb12d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,3 @@ [submodule "dsk2nib"] path = dsk2nib url = https://github.com/nickd4/dsk2nib.git -[submodule "star_blazer_emu/vrEmu6502"] - path = star_blazer_emu/vrEmu6502 - url = https://github.com/nickd4/vrEmu6502.git diff --git a/star_blazer_emu/Makefile b/star_blazer_emu/Makefile index 11023b8..2702f42 100644 --- a/star_blazer_emu/Makefile +++ b/star_blazer_emu/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-g -Wall -O3 -DVR_6502_EMU_STATIC=1 +CFLAGS=-g -Wall -Wno-attributes -Wno-unused-function -O3 LDFLAGS=-g DOS33=../dos33fsprogs/utils/dos33fs-utils/dos33 @@ -8,7 +8,7 @@ all: \ star_blazer_emu \ star_blazer.c -star_blazer_emu: star_blazer_emu.o star_blazer.o vrEmu6502/src/vrEmu6502.o +star_blazer_emu: star_blazer_emu.o star_blazer.o cpu_65c02.o ${CC} ${LDFLAGS} -o $@ $^ -lSDL2 -lm # make sure star_blazer.h has been built diff --git a/star_blazer_emu/cpu_65c02.c b/star_blazer_emu/cpu_65c02.c new file mode 100644 index 0000000..8789d63 --- /dev/null +++ b/star_blazer_emu/cpu_65c02.c @@ -0,0 +1,879 @@ +#include +#include +#include +#include "cpu_65c02.h" + +// initialization +void cpu_65c02_init( + struct cpu_65c02 *self, + uint8_t (*read_byte)(void *context, uint16_t addr), + void *read_byte_context, + void (*write_byte)(void *context, uint16_t addr, uint8_t data), + void *write_byte_context +) { + memset(self, 0, sizeof(struct cpu_65c02)); + self->regs.byte.p = 0x30; // unused bits are hard coded to 1 + self->read_byte = read_byte; + self->read_byte_context = read_byte_context; + self->write_byte = write_byte; + self->write_byte_context = write_byte_context; +} + +void cpu_65c02_reset(struct cpu_65c02 *self) { + self->regs.word.pc = cpu_65c02_read_word(self, CPU_65C02_RESET_VECTOR); + self->regs.byte.iflags = 0; + self->regs.bit._if = true; + self->regs.bit.df = false; +} + +// instruction decode +void cpu_65c02_execute(struct cpu_65c02 *self) { + if (self->regs.bit.stp_flag) { + ++self->cycles; + return; + } + + if (self->regs.bit.nmi_pending) { + self->regs.bit.nmi_pending = false; + self->regs.bit.wai_flag = false; + cpu_65c02_irq(self, false, CPU_65C02_NMI_VECTOR); + return; + } + + if (self->regs.bit.irq_pending) { + if (self->regs.bit._if == 0) { + self->regs.bit.irq_pending = false; + self->regs.bit.wai_flag = false; + cpu_65c02_irq(self, false, CPU_65C02_IRQ_VECTOR); + return; + } + if (self->regs.bit.wai_flag) { + self->regs.bit.irq_pending = false; + self->regs.bit.wai_flag = false; + } + } + else if (self->regs.bit.wai_flag) { + ++self->cycles; + return; + } + + switch (cpu_65c02_fetch_byte(self)) { + case 0x00: + ++self->regs.word.pc; + cpu_65c02_irq(self, true, CPU_65C02_IRQ_VECTOR); + break; + case 0x01: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0x02: + cpu_65c02_illegal_opcode22(self); + break; + case 0x03: + cpu_65c02_illegal_opcode11(self); + break; + case 0x04: + cpu_65c02_tsb(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x05: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0x06: + cpu_65c02_asl(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x07: + cpu_65c02_rmb(self, 0, cpu_65c02_ea_zero_page(self)); + break; + case 0x08: + cpu_65c02_ph(self, self->regs.byte.p); + break; + case 0x09: + cpu_65c02_ora(self, cpu_65c02_fetch_byte(self)); + break; + case 0x0a: + cpu_65c02_asl(self, CPU_65C02_EA_A); + break; + case 0x0b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x0c: + cpu_65c02_tsb(self, cpu_65c02_ea_absolute(self)); + break; + case 0x0d: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0x0e: + cpu_65c02_asl(self, cpu_65c02_ea_absolute(self)); + break; + case 0x0f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !(rvalue & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x10: + cpu_65c02_bra(self, !self->regs.bit.nf, cpu_65c02_ea_relative(self)); + break; + case 0x11: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0x12: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0x13: + cpu_65c02_illegal_opcode11(self); + break; + case 0x14: + cpu_65c02_trb(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x15: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0x16: + cpu_65c02_asl(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x17: + cpu_65c02_rmb(self, 1, cpu_65c02_ea_zero_page(self)); + break; + case 0x18: + cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_C); + break; + case 0x19: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0x1a: + cpu_65c02_inc(self, CPU_65C02_EA_A); + break; + case 0x1b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x1c: + cpu_65c02_trb(self, cpu_65c02_ea_absolute(self)); + break; + case 0x1d: + cpu_65c02_ora(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0x1e: + cpu_65c02_asl(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x1f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 1) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x20: + cpu_65c02_jsr(self, cpu_65c02_ea_absolute(self)); + break; + case 0x21: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0x22: + cpu_65c02_illegal_opcode22(self); + break; + case 0x23: + cpu_65c02_illegal_opcode11(self); + break; + case 0x24: + cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0x25: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0x26: + cpu_65c02_rol(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x27: + cpu_65c02_rmb(self, 2, cpu_65c02_ea_zero_page(self)); + break; + case 0x28: + cpu_65c02_plp(self); + break; + case 0x29: + cpu_65c02_and(self, cpu_65c02_fetch_byte(self)); + break; + case 0x2a: + cpu_65c02_rol(self, CPU_65C02_EA_A); + break; + case 0x2b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x2c: + cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0x2d: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0x2e: + cpu_65c02_rol(self, cpu_65c02_ea_absolute(self)); + break; + case 0x2f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 2) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x30: + cpu_65c02_bra(self, self->regs.bit.nf, cpu_65c02_ea_relative(self)); + break; + case 0x31: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0x32: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0x33: + cpu_65c02_illegal_opcode11(self); + break; + case 0x34: + cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0x35: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0x36: + cpu_65c02_rol(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x37: + cpu_65c02_rmb(self, 3, cpu_65c02_ea_zero_page(self)); + break; + case 0x38: + cpu_65c02_se(self, CPU_65C02_REG_P_BIT_C); + break; + case 0x39: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0x3a: + cpu_65c02_dec(self, CPU_65C02_EA_A); + break; + case 0x3b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x3c: + cpu_65c02_bit(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0x3d: + cpu_65c02_and(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0x3e: + cpu_65c02_rol(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x3f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 3) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x40: + cpu_65c02_rti(self); + break; + case 0x41: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0x42: + cpu_65c02_illegal_opcode22(self); + break; + case 0x43: + cpu_65c02_illegal_opcode11(self); + break; + case 0x44: + cpu_65c02_illegal_opcode23(self); + break; + case 0x45: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0x46: + cpu_65c02_lsr(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x47: + cpu_65c02_rmb(self, 4, cpu_65c02_ea_zero_page(self)); + break; + case 0x48: + cpu_65c02_ph(self, self->regs.byte.a); + break; + case 0x49: + cpu_65c02_eor(self, cpu_65c02_fetch_byte(self)); + break; + case 0x4a: + cpu_65c02_lsr(self, CPU_65C02_EA_A); + break; + case 0x4b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x4c: + cpu_65c02_jmp(self, cpu_65c02_ea_absolute(self)); + break; + case 0x4d: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0x4e: + cpu_65c02_lsr(self, cpu_65c02_ea_absolute(self)); + break; + case 0x4f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 4) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x50: + cpu_65c02_bra(self, !self->regs.bit.vf, cpu_65c02_ea_relative(self)); + break; + case 0x51: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0x52: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0x53: + cpu_65c02_illegal_opcode11(self); + break; + case 0x54: + cpu_65c02_illegal_opcode24(self); + break; + case 0x55: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0x56: + cpu_65c02_lsr(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x57: + cpu_65c02_rmb(self, 5, cpu_65c02_ea_zero_page(self)); + break; + case 0x58: + cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_I); + break; + case 0x59: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0x5a: + cpu_65c02_ph(self, self->regs.byte.y); + break; + case 0x5b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x5c: + cpu_65c02_illegal_opcode38(self); + break; + case 0x5d: + cpu_65c02_eor(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0x5e: + cpu_65c02_lsr(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x5f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 5) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x60: + cpu_65c02_rts(self); + break; + case 0x61: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0x62: + cpu_65c02_illegal_opcode22(self); + break; + case 0x63: + cpu_65c02_illegal_opcode11(self); + break; + case 0x64: + cpu_65c02_st(self, 0, cpu_65c02_ea_zero_page(self)); + break; + case 0x65: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0x66: + cpu_65c02_ror(self, cpu_65c02_ea_zero_page(self)); + break; + case 0x67: + cpu_65c02_rmb(self, 6, cpu_65c02_ea_zero_page(self)); + break; + case 0x68: + cpu_65c02_pl(self, CPU_65C02_EA_A); + break; + case 0x69: + cpu_65c02_adc(self, cpu_65c02_fetch_byte(self)); + break; + case 0x6a: + cpu_65c02_ror(self, CPU_65C02_EA_A); + break; + case 0x6b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x6c: + cpu_65c02_jmp(self, cpu_65c02_ea_absolute_indirect(self)); + break; + case 0x6d: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0x6e: + cpu_65c02_ror(self, cpu_65c02_ea_absolute(self)); + break; + case 0x6f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 6) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x70: + cpu_65c02_bra(self, self->regs.bit.vf, cpu_65c02_ea_relative(self)); + break; + case 0x71: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0x72: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0x73: + cpu_65c02_illegal_opcode11(self); + break; + case 0x74: + cpu_65c02_st(self, 0, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x75: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0x76: + cpu_65c02_ror(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x77: + cpu_65c02_rmb(self, 7, cpu_65c02_ea_zero_page(self)); + break; + case 0x78: + cpu_65c02_se(self, CPU_65C02_REG_P_BIT_I); + break; + case 0x79: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0x7a: + cpu_65c02_pl(self, CPU_65C02_EA_Y); + break; + case 0x7b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x7c: + cpu_65c02_jmp(self, cpu_65c02_ea_absolute_indexed_indirect(self, self->regs.byte.x)); + break; + case 0x7d: + cpu_65c02_adc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0x7e: + cpu_65c02_ror(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x7f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, !((rvalue >> 7) & 1), cpu_65c02_ea_relative(self)); + } + break; + case 0x80: + cpu_65c02_bra(self, true, cpu_65c02_ea_relative(self)); + break; + case 0x81: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x)); + break; + case 0x82: + cpu_65c02_illegal_opcode22(self); + break; + case 0x83: + cpu_65c02_illegal_opcode11(self); + break; + case 0x84: + cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_zero_page(self)); + break; + case 0x85: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page(self)); + break; + case 0x86: + cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_zero_page(self)); + break; + case 0x87: + cpu_65c02_smb(self, 0, cpu_65c02_ea_zero_page(self)); + break; + case 0x88: + cpu_65c02_dec(self, CPU_65C02_EA_Y); + break; + case 0x89: + cpu_65c02_bit_imm(self, cpu_65c02_fetch_byte(self)); + break; + case 0x8a: + cpu_65c02_ld(self, CPU_65C02_EA_A, self->regs.byte.x); + break; + case 0x8b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x8c: + cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_absolute(self)); + break; + case 0x8d: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_absolute(self)); + break; + case 0x8e: + cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_absolute(self)); + break; + case 0x8f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, rvalue & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0x90: + cpu_65c02_bra(self, !self->regs.bit.cf, cpu_65c02_ea_relative(self)); + break; + case 0x91: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y)); + break; + case 0x92: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indirect(self)); + break; + case 0x93: + cpu_65c02_illegal_opcode11(self); + break; + case 0x94: + cpu_65c02_st(self, self->regs.byte.y, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x95: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0x96: + cpu_65c02_st(self, self->regs.byte.x, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.y)); + break; + case 0x97: + cpu_65c02_smb(self, 1, cpu_65c02_ea_zero_page(self)); + break; + case 0x98: + cpu_65c02_ld(self, CPU_65C02_EA_A, self->regs.byte.y); + break; + case 0x99: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y)); + break; + case 0x9a: + cpu_65c02_st(self, self->regs.byte.x, CPU_65C02_EA_S); + break; + case 0x9b: + cpu_65c02_illegal_opcode11(self); + break; + case 0x9c: + cpu_65c02_st(self, 0, cpu_65c02_ea_absolute(self)); + break; + case 0x9d: + cpu_65c02_st(self, self->regs.byte.a, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x9e: + cpu_65c02_st(self, 0, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0x9f: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 1) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xa0: + cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_fetch_byte(self)); + break; + case 0xa1: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0xa2: + cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_fetch_byte(self)); + break; + case 0xa3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xa4: + cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xa5: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xa6: + cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xa7: + cpu_65c02_smb(self, 2, cpu_65c02_ea_zero_page(self)); + break; + case 0xa8: + cpu_65c02_ld(self, CPU_65C02_EA_Y, self->regs.byte.a); + break; + case 0xa9: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_fetch_byte(self)); + break; + case 0xaa: + cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.a); + break; + case 0xab: + cpu_65c02_illegal_opcode11(self); + break; + case 0xac: + cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xad: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xae: + cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xaf: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 2) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xb0: + cpu_65c02_bra(self, self->regs.bit.cf, cpu_65c02_ea_relative(self)); + break; + case 0xb1: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0xb2: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0xb3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xb4: + cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0xb5: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0xb6: + cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.y))); + break; + case 0xb7: + cpu_65c02_smb(self, 3, cpu_65c02_ea_zero_page(self)); + break; + case 0xb8: + cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_V); + break; + case 0xb9: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0xba: + cpu_65c02_ld(self, CPU_65C02_EA_X, self->regs.byte.s); + break; + case 0xbb: + cpu_65c02_illegal_opcode11(self); + break; + case 0xbc: + cpu_65c02_ld(self, CPU_65C02_EA_Y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0xbd: + cpu_65c02_ld(self, CPU_65C02_EA_A, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0xbe: + cpu_65c02_ld(self, CPU_65C02_EA_X, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0xbf: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 3) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xc0: + cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_fetch_byte(self)); + break; + case 0xc1: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0xc2: + cpu_65c02_illegal_opcode22(self); + break; + case 0xc3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xc4: + cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xc5: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xc6: + cpu_65c02_dec(self, cpu_65c02_ea_zero_page(self)); + break; + case 0xc7: + cpu_65c02_smb(self, 4, cpu_65c02_ea_zero_page(self)); + break; + case 0xc8: + cpu_65c02_inc(self, CPU_65C02_EA_Y); + break; + case 0xc9: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_fetch_byte(self)); + break; + case 0xca: + cpu_65c02_dec(self, CPU_65C02_EA_X); + break; + case 0xcb: + cpu_65c02_wai(self); + break; + case 0xcc: + cpu_65c02_cmp(self, self->regs.byte.y, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xcd: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xce: + cpu_65c02_dec(self, cpu_65c02_ea_absolute(self)); + break; + case 0xcf: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 4) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xd0: + cpu_65c02_bra(self, !self->regs.bit.zf, cpu_65c02_ea_relative(self)); + break; + case 0xd1: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0xd2: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0xd3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xd4: + cpu_65c02_illegal_opcode24(self); + break; + case 0xd5: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0xd6: + cpu_65c02_dec(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0xd7: + cpu_65c02_smb(self, 5, cpu_65c02_ea_zero_page(self)); + break; + case 0xd8: + cpu_65c02_cl(self, CPU_65C02_REG_P_BIT_D); + break; + case 0xd9: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0xda: + cpu_65c02_ph(self, self->regs.byte.x); + break; + case 0xdb: + cpu_65c02_illegal_opcode11(self); + break; + case 0xdc: + cpu_65c02_illegal_opcode34(self); + break; + case 0xdd: + cpu_65c02_cmp(self, self->regs.byte.a, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0xde: + cpu_65c02_dec(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0xdf: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 5) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xe0: + cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_fetch_byte(self)); + break; + case 0xe1: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed_indirect(self, self->regs.byte.x))); + break; + case 0xe2: + cpu_65c02_illegal_opcode22(self); + break; + case 0xe3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xe4: + cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xe5: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self))); + break; + case 0xe6: + cpu_65c02_inc(self, cpu_65c02_ea_zero_page(self)); + break; + case 0xe7: + cpu_65c02_smb(self, 6, cpu_65c02_ea_zero_page(self)); + break; + case 0xe8: + cpu_65c02_inc(self, CPU_65C02_EA_X); + break; + case 0xe9: + cpu_65c02_sbc(self, cpu_65c02_fetch_byte(self)); + break; + case 0xea: + cpu_65c02_nop(self); + break; + case 0xeb: + cpu_65c02_illegal_opcode11(self); + break; + case 0xec: + cpu_65c02_cmp(self, self->regs.byte.x, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xed: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute(self))); + break; + case 0xee: + cpu_65c02_inc(self, cpu_65c02_ea_absolute(self)); + break; + case 0xef: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 6) & 1, cpu_65c02_ea_relative(self)); + } + break; + case 0xf0: + cpu_65c02_bra(self, self->regs.bit.zf, cpu_65c02_ea_relative(self)); + break; + case 0xf1: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect_indexed(self, self->regs.byte.y))); + break; + case 0xf2: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indirect(self))); + break; + case 0xf3: + cpu_65c02_illegal_opcode11(self); + break; + case 0xf4: + cpu_65c02_illegal_opcode24(self); + break; + case 0xf5: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x))); + break; + case 0xf6: + cpu_65c02_inc(self, cpu_65c02_ea_zero_page_indexed(self, self->regs.byte.x)); + break; + case 0xf7: + cpu_65c02_smb(self, 7, cpu_65c02_ea_zero_page(self)); + break; + case 0xf8: + cpu_65c02_se(self, CPU_65C02_REG_P_BIT_D); + break; + case 0xf9: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.y))); + break; + case 0xfa: + cpu_65c02_pl(self, CPU_65C02_EA_X); + break; + case 0xfb: + cpu_65c02_illegal_opcode11(self); + break; + case 0xfc: + cpu_65c02_illegal_opcode34(self); + break; + case 0xfd: + cpu_65c02_sbc(self, cpu_65c02_read_byte(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x))); + break; + case 0xfe: + cpu_65c02_inc(self, cpu_65c02_ea_absolute_indexed(self, self->regs.byte.x)); + break; + case 0xff: + { + int rvalue = cpu_65c02_read_byte(self, cpu_65c02_ea_zero_page(self)); + cpu_65c02_bra(self, (rvalue >> 7) & 1, cpu_65c02_ea_relative(self)); + } + break; + } +} diff --git a/star_blazer_emu/cpu_65c02.h b/star_blazer_emu/cpu_65c02.h new file mode 100644 index 0000000..0a506db --- /dev/null +++ b/star_blazer_emu/cpu_65c02.h @@ -0,0 +1,535 @@ +#ifndef _CPU_65C02_H +#define _CPU_65C02_H + +#include +#include +#include + +// gcc specific +#ifndef ALWAYS_INLINE +#define ALWAYS_INLINE __attribute__((always_inline)) +#endif + +#define CPU_65C02_NMI_VECTOR 0xfffa +#define CPU_65C02_RESET_VECTOR 0xfffc +#define CPU_65C02_IRQ_VECTOR 0xfffe + +// bits within REG_P +#define CPU_65C02_REG_P_BIT_C 0 +#define CPU_65C02_REG_P_BIT_Z 1 +#define CPU_65C02_REG_P_BIT_I 2 +#define CPU_65C02_REG_P_BIT_D 3 +#define CPU_65C02_REG_P_BIT_B 4 +#define CPU_65C02_REG_P_BIT_V 6 +#define CPU_65C02_REG_P_BIT_N 7 + +// special memory locations (negative address) +#define CPU_65C02_EA_PC (-8) +#define CPU_65C02_EA_A (-6) +#define CPU_65C02_EA_X (-5) +#define CPU_65C02_EA_Y (-4) +#define CPU_65C02_EA_S (-3) +#define CPU_65C02_EA_P (-2) +#define CPU_65C02_EA_IFLAGS (-1) + +// registers, in same order as special memory locations, but reversed on +// big endian hardware where special memory address will be complemented +// (this allows special memory to always look like it is little endian) +union cpu_65c02_regs { +#if __BYTE_ORDER == __BIG_ENDIAN + struct { + uint8_t _fill_iflags : 4; + uint8_t stp_flag : 1; + uint8_t wai_flag : 1; + uint8_t irq_pending : 1; + uint8_t nmi_pending : 1; + uint8_t nf : 1; + uint8_t vf : 1; + uint8_t _fill_5f: 1; + uint8_t _fill_4f: 1; + uint8_t df : 1; + uint8_t _if : 1; + uint8_t zf : 1; + uint8_t cf : 1; + uint8_t _fill_s; + uint8_t _fill_y; + uint8_t _fill_x; + uint8_t _fill_a; + uint16_t _fill_pc; + } bit; + struct { + uint8_t iflags; + uint8_t p; + uint8_t s; + uint8_t y; + uint8_t x; + uint8_t a; + uint16_t _fill_pc; + } byte; + struct { + uint8_t _fill_iflags; + uint8_t _fill_p; + uint8_t _fill_s; + uint8_t _fill_y; + uint8_t _fill_x; + uint8_t _fill_a; + uint16_t pc; + } word; + uint8_t mem_be[8]; +#else + struct { + uint16_t _fill_pc; + uint8_t _fill_a; + uint8_t _fill_x; + uint8_t _fill_y; + uint8_t _fill_s; + uint8_t cf : 1; + uint8_t zf : 1; + uint8_t _if : 1; + uint8_t df : 1; + uint8_t _fill_4f: 1; + uint8_t _fill_5f: 1; + uint8_t vf : 1; + uint8_t nf : 1; + uint8_t nmi_pending : 1; + uint8_t irq_pending : 1; + uint8_t wai_flag : 1; + uint8_t stp_flag : 1; + uint8_t _fill_iflags : 4; + } bit; + struct { + uint16_t _fill_pc; + uint8_t a; + uint8_t x; + uint8_t y; + uint8_t s; + uint8_t p; + uint8_t iflags; + } byte; + struct { + uint16_t pc; + uint8_t _fill_a; + uint8_t _fill_x; + uint8_t _fill_y; + uint8_t _fill_s; + uint8_t _fill_p; + uint8_t _fill_iflags; + } word; + uint8_t mem_le[8]; +#endif +}; + +struct cpu_65c02 { + int cycles; + uint8_t (*read_byte)(void *context, uint16_t addr); + void *read_byte_context; + void (*write_byte)(void *context, uint16_t addr, uint8_t data); + void *write_byte_context; + union cpu_65c02_regs regs; +}; + +// memory or special memory access +static ALWAYS_INLINE uint8_t cpu_65c02_read_byte(struct cpu_65c02 *self, int32_t addr) { + if (addr < 0) +#if __BYTE_ORDER == __BIG_ENDIAN + return self->regs.mem_be[~addr]; +#else + return self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr]; +#endif + self->cycles += 1; + return self->read_byte(self->read_byte_context, addr & 0xffff); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_read_word(struct cpu_65c02 *self, int32_t addr) { + int data = cpu_65c02_read_byte(self, addr); + return data | (cpu_65c02_read_byte(self, addr + 1) << 8); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_read_word_zero_page(struct cpu_65c02 *self, uint8_t addr) { + int data = cpu_65c02_read_byte(self, addr & 0xff); + return data | (cpu_65c02_read_byte(self, (addr + 1) & 0xff) << 8); +} + +static ALWAYS_INLINE void cpu_65c02_write_byte(struct cpu_65c02 *self, int32_t addr, uint8_t data) { + self->cycles += 1; + if (addr < 0) +#if __BYTE_ORDER == __BIG_ENDIAN + self->regs.mem_be[~addr] = data; +#else + self->regs.mem_le[sizeof(union cpu_65c02_regs) + addr] = data; +#endif + else + self->write_byte(self->write_byte_context, addr, data); +} + +static ALWAYS_INLINE void cpu_65c02_write_word(struct cpu_65c02 *self, int32_t addr, uint16_t data) { + cpu_65c02_write_byte(self, addr, data & 0xff); + cpu_65c02_write_byte(self, addr + 1, data >> 8); +} + +static ALWAYS_INLINE uint8_t cpu_65c02_fetch_byte(struct cpu_65c02 *self) { + int data = cpu_65c02_read_byte(self, self->regs.word.pc++); + return data; +} + +static ALWAYS_INLINE uint16_t cpu_65c02_fetch_word(struct cpu_65c02 *self) { + int data = cpu_65c02_fetch_byte(self); + return data | (cpu_65c02_fetch_byte(self) << 8); +} + +static ALWAYS_INLINE void cpu_65c02_push_byte(struct cpu_65c02 *self, uint8_t data) { + cpu_65c02_write_byte(self, self->regs.byte.s-- | 0x100, data); +} + +static ALWAYS_INLINE void cpu_65c02_push_word(struct cpu_65c02 *self, uint16_t data) { + cpu_65c02_push_byte(self, data >> 8); + cpu_65c02_push_byte(self, data & 0xff); +} + +static ALWAYS_INLINE uint8_t cpu_65c02_pop_byte(struct cpu_65c02 *self) { + return cpu_65c02_read_byte(self, ++self->regs.byte.s | 0x100); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_pop_word(struct cpu_65c02 *self) { + int data = cpu_65c02_pop_byte(self); + return data | (cpu_65c02_pop_byte(self) << 8); +} + +// effective address calculation +static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute(struct cpu_65c02 *self) { + return cpu_65c02_fetch_word(self); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indexed(struct cpu_65c02 *self, uint8_t rvalue) { + int addr = cpu_65c02_ea_absolute(self); + self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8; + return addr + rvalue; +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indexed_indirect(struct cpu_65c02 *self, uint8_t rvalue) { + return cpu_65c02_read_word(self, cpu_65c02_ea_absolute_indexed(self, rvalue)); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_absolute_indirect(struct cpu_65c02 *self) { + return cpu_65c02_read_word(self, cpu_65c02_ea_absolute(self)); +} + +static ALWAYS_INLINE int8_t cpu_65c02_ea_relative(struct cpu_65c02 *self) { + return (int8_t)cpu_65c02_fetch_byte(self); +} + +static ALWAYS_INLINE uint8_t cpu_65c02_ea_zero_page(struct cpu_65c02 *self) { + return cpu_65c02_fetch_byte(self); +} + +static ALWAYS_INLINE uint8_t cpu_65c02_ea_zero_page_indexed(struct cpu_65c02 *self, uint8_t rvalue) { + return (cpu_65c02_ea_zero_page(self) + rvalue) & 0xff; +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indexed_indirect(struct cpu_65c02 *self, uint8_t rvalue) { + return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page_indexed(self, rvalue)); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indirect(struct cpu_65c02 *self) { + return cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self)); +} + +static ALWAYS_INLINE uint16_t cpu_65c02_ea_zero_page_indirect_indexed(struct cpu_65c02 *self, uint8_t rvalue) { + int addr = cpu_65c02_read_word_zero_page(self, cpu_65c02_ea_zero_page(self)); + self->cycles += ((addr & 0xff) + (rvalue & 0xff)) >> 8; + return addr + rvalue; +} + +// instruction execute +static ALWAYS_INLINE void cpu_65c02_adc(struct cpu_65c02 *self, uint8_t rvalue) { + int result0, result1, result2; + if (self->regs.bit.df) { + result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf); + if (result0 >= 0xa) + result0 = (result0 + 6) & 0x1f; + result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70); + result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80); + result2 = result1; + if (result2 >= 0xa0) + result2 = (result2 + 0x60) & 0x1ff; + } + else { + result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f); + result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80); + result2 = result1; + } + self->regs.byte.a = result2 & 0xff; + self->regs.bit.cf = result2 >> 8; + self->regs.bit.zf = (result2 & 0xff) == 0; + self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1; + self->regs.bit.nf = (result2 >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_and(struct cpu_65c02 *self, uint8_t rvalue) { + int result = self->regs.byte.a & rvalue; + self->regs.byte.a = result; + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_asl(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue) << 1; + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result & 0xff); + self->regs.bit.cf = result >> 8; + self->regs.bit.zf = (result & 0xff) == 0; + self->regs.bit.nf = (result >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_bit(struct cpu_65c02 *self, uint8_t rvalue) { + int result = self->regs.byte.a & rvalue; + self->regs.bit.zf = result == 0; + self->regs.bit.vf = (rvalue >> 6) & 1; + self->regs.bit.nf = (rvalue >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_bit_imm(struct cpu_65c02 *self, uint8_t rvalue) { + int result = self->regs.byte.a & rvalue; + self->regs.bit.zf = result == 0; +} + +static ALWAYS_INLINE void cpu_65c02_bra(struct cpu_65c02 *self, bool pred, int8_t rvalue) { + if (pred) { + self->cycles += ((self->regs.word.pc & 0xff) + (rvalue & 0xff)) >> 8; + self->regs.word.pc += rvalue; + } +} + +static ALWAYS_INLINE void cpu_65c02_cl(struct cpu_65c02 *self, int n) { + self->regs.byte.p &= ~(1 << n); +} + +static ALWAYS_INLINE void cpu_65c02_cmp(struct cpu_65c02 *self, uint8_t rvalue0, uint8_t rvalue1) { + rvalue1 ^= 0xff; + int result = 1 + rvalue0 + rvalue1; + self->regs.bit.cf = result >> 8; + self->regs.bit.zf = (result & 0xff) == 0; + self->regs.bit.nf = (result >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_dec(struct cpu_65c02 *self, int32_t lvalue) { + int result = (cpu_65c02_read_byte(self, lvalue) - 1) & 0xff; + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result); + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_eor(struct cpu_65c02 *self, uint8_t rvalue) { + int result = self->regs.byte.a ^ rvalue; + self->regs.byte.a = result; + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode11(struct cpu_65c02 *self) { +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode22(struct cpu_65c02 *self) { + ++self->cycles; + self->regs.word.pc += 1; +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode23(struct cpu_65c02 *self) { + self->cycles += 2; + self->regs.word.pc += 1; +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode24(struct cpu_65c02 *self) { + self->cycles += 3; + self->regs.word.pc += 1; +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode34(struct cpu_65c02 *self) { + self->cycles += 3; + self->regs.word.pc += 2; +} + +static ALWAYS_INLINE void cpu_65c02_illegal_opcode38(struct cpu_65c02 *self) { + self->cycles += 7; + self->regs.word.pc += 2; +} + +static ALWAYS_INLINE void cpu_65c02_inc(struct cpu_65c02 *self, int32_t lvalue) { + int result = (cpu_65c02_read_byte(self, lvalue) + 1) & 0xff; + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result); + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_irq(struct cpu_65c02 *self, bool brk, int32_t lvalue) { + ++self->cycles; + cpu_65c02_push_word(self, self->regs.word.pc); + cpu_65c02_push_byte( + self, + ((self->regs.byte.p) & ~(1 << CPU_65C02_REG_P_BIT_B)) | + (brk << CPU_65C02_REG_P_BIT_B) + ); + self->regs.word.pc = cpu_65c02_read_word(self, lvalue); + self->regs.bit._if = true; + self->regs.bit.df = false; +} + +static ALWAYS_INLINE void cpu_65c02_jmp(struct cpu_65c02 *self, int32_t lvalue) { + self->regs.word.pc = lvalue; +} + +static ALWAYS_INLINE void cpu_65c02_jsr(struct cpu_65c02 *self, int32_t lvalue) { + cpu_65c02_push_word(self, (self->regs.word.pc - 1) & 0xffff); + self->regs.word.pc = lvalue; +} + +static ALWAYS_INLINE void cpu_65c02_ld(struct cpu_65c02 *self, int32_t lvalue, uint8_t rvalue) { + cpu_65c02_write_byte(self, lvalue, rvalue); + self->regs.bit.zf = rvalue == 0; + self->regs.bit.nf = (rvalue >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_lsr(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result >> 1); + self->regs.bit.cf = result & 1; + self->regs.bit.zf = (result & 0xfe) == 0; + self->regs.bit.nf = false; +} + +static ALWAYS_INLINE void cpu_65c02_nop(struct cpu_65c02 *self) { +} + +static ALWAYS_INLINE void cpu_65c02_ora(struct cpu_65c02 *self, uint8_t rvalue) { + int result = self->regs.byte.a | rvalue; + self->regs.byte.a = result; + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_ph(struct cpu_65c02 *self, uint8_t rvalue) { + cpu_65c02_push_byte(self, rvalue); +} + +static ALWAYS_INLINE void cpu_65c02_pl(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_pop_byte(self); + cpu_65c02_write_byte(self, lvalue, result); + self->regs.bit.zf = result == 0; + self->regs.bit.nf = result >> 7; +} + +static ALWAYS_INLINE void cpu_65c02_plp(struct cpu_65c02 *self) { + self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30; +} + +static ALWAYS_INLINE void cpu_65c02_rmb(struct cpu_65c02 *self, int n, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue) & ~(1 << n); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result); +} + +static ALWAYS_INLINE void cpu_65c02_rol(struct cpu_65c02 *self, int32_t lvalue) { + int result = self->regs.bit.cf | (cpu_65c02_read_byte(self, lvalue) << 1); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result & 0xff); + self->regs.bit.cf = result >> 8; + self->regs.bit.zf = (result & 0xff) == 0; + self->regs.bit.nf = (result >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_ror(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue) | (self->regs.bit.cf << 8); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result >> 1); + self->regs.bit.cf = result & 1; + self->regs.bit.zf = (result & 0x1fe) == 0; + self->regs.bit.nf = (result >> 8) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_rti(struct cpu_65c02 *self) { + self->regs.byte.p = cpu_65c02_pop_byte(self) | 0x30; + self->regs.word.pc = cpu_65c02_pop_word(self); +} + +static ALWAYS_INLINE void cpu_65c02_rts(struct cpu_65c02 *self) { + self->regs.word.pc = (cpu_65c02_pop_word(self) + 1) & 0xffff; +} + +static ALWAYS_INLINE void cpu_65c02_sbc(struct cpu_65c02 *self, uint8_t rvalue) { + rvalue ^= 0xff; + int result0, result1, result2; + if (self->regs.bit.df) { + result0 = self->regs.bit.cf + (self->regs.byte.a & 0xf) + (rvalue & 0xf); + if (result0 < 0x10) + result0 = (result0 - 6) & 0x1f; + result0 += (self->regs.byte.a & 0x70) + (rvalue & 0x70); + result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80); + result2 = result1; + if (result2 < 0x100) + result2 = (result2 - 0x60) & 0x1ff; + } + else { + result0 = self->regs.bit.cf + (self->regs.byte.a & 0x7f) + (rvalue & 0x7f); + result1 = result0 + (self->regs.byte.a & 0x80) + (rvalue & 0x80); + result2 = result1; + } + self->regs.byte.a = result2 & 0xff; + self->regs.bit.cf = result2 >> 8; + self->regs.bit.zf = (result2 & 0xff) == 0; + self->regs.bit.vf = ((result0 >> 7) ^ (result1 >> 8)) & 1; + self->regs.bit.nf = (result2 >> 7) & 1; +} + +static ALWAYS_INLINE void cpu_65c02_se(struct cpu_65c02 *self, int n) { + self->regs.byte.p |= 1 << n; +} + +static ALWAYS_INLINE void cpu_65c02_smb(struct cpu_65c02 *self, int n, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue) | (1 << n); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result); +} + +static ALWAYS_INLINE void cpu_65c02_st(struct cpu_65c02 *self, uint8_t rvalue, int32_t lvalue) { + cpu_65c02_write_byte(self, lvalue, rvalue); +} + +static ALWAYS_INLINE void cpu_65c02_stp(struct cpu_65c02 *self) { + self->regs.bit.stp_flag = true; +} + +static ALWAYS_INLINE void cpu_65c02_trb(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result & ~self->regs.byte.a); + result &= self->regs.byte.a; + self->regs.bit.zf = result == 0; +} + +static ALWAYS_INLINE void cpu_65c02_tsb(struct cpu_65c02 *self, int32_t lvalue) { + int result = cpu_65c02_read_byte(self, lvalue); + ++self->cycles; + cpu_65c02_write_byte(self, lvalue, result | self->regs.byte.a); + result &= self->regs.byte.a; + self->regs.bit.zf = result == 0; +} + +static ALWAYS_INLINE void cpu_65c02_wai(struct cpu_65c02 *self) { + self->regs.bit.wai_flag = true; +} + +// prototypes +void cpu_65c02_init( + struct cpu_65c02 *self, + uint8_t (*read_byte)(void *context, uint16_t addr), + void *read_byte_context, + void (*write_byte)(void *context, uint16_t addr, uint8_t data), + void *write_byte_context +); +void cpu_65c02_reset(struct cpu_65c02 *self); +void cpu_65c02_execute(struct cpu_65c02 *self); + +#endif diff --git a/star_blazer_emu/star_blazer_emu.c b/star_blazer_emu/star_blazer_emu.c index d7b0d1a..4bc35d5 100644 --- a/star_blazer_emu/star_blazer_emu.c +++ b/star_blazer_emu/star_blazer_emu.c @@ -70,10 +70,8 @@ uint32_t palette[0x10] = { 0xffffffff, }; -// can make this green or amber to be more realistic -uint32_t mono_palette[2] = {0xff000000, 0xffffffff}; - -VrEmu6502 *cpu; +struct cpu_65c02 cpu; +bool jam_flag; #define MEM_SIZE 0x10000 uint8_t mem[MEM_SIZE]; @@ -367,7 +365,7 @@ int load(char *name) { exit(EXIT_FAILURE); } -uint8_t mem_read(uint16_t addr/*, bool isDbg*/) { +uint8_t read_byte(void *context, uint16_t addr) { // for joystick, for now count memory accesses as proxy for cycles if (joystick_count < JOYSTICK_COUNT) { ++joystick_count; @@ -386,10 +384,10 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) { //if (addr >= 0x8c08 && addr < 0x8e00) { // data fetch //if (addr >= 0x9580 && addr < 0x9600) { // data fetch if (addr >= 0x5c00 && addr < 0x5c1b) { // data fetch - int pc = vrEmu6502GetPC(cpu); + int pc = cpu.regs.word.pc; fprintf(stderr, "pc=%04x addr=%04x\n", pc, addr); exit_flag = 0x101; - vrEmu6502Jam(cpu); + jam_flag = true; } #endif @@ -411,12 +409,12 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) { #if 0 // start at mission if (addr == 0x1726) // opcode fetch - vrEmu6502SetX(cpu, start_at_mission); + cpu.regs.byte.x = start_at_mission; #endif #if MEM_TRACE { - int pc = cpu ? vrEmu6502GetPC(cpu) : 0; + int pc = cpu ? cpu.regs.word.pc : 0; fprintf(stderr, "pc=%04x addr=%05x rd=%02x\n", pc, addr, mem[addr]); } #endif @@ -450,7 +448,7 @@ uint8_t mem_read(uint16_t addr/*, bool isDbg*/) { return 0xff; } -void mem_write(uint16_t addr, uint8_t val) { +void write_byte(void *context, uint16_t addr, uint8_t data) { // for joystick, for now count memory accesses as proxy for cycles if (joystick_count < JOYSTICK_COUNT) { ++joystick_count; @@ -467,11 +465,11 @@ void mem_write(uint16_t addr, uint8_t val) { if ((addr & 0xff00) != IO_PAGE) { #if MEM_TRACE { - int pc = cpu ? vrEmu6502GetPC(cpu) : 0; - fprintf(stderr, "pc=%04x addr=%05x wr=%02x\n", pc, addr, val); + int pc = cpu ? cpu.regs.word.pc : 0; + fprintf(stderr, "pc=%04x addr=%05x wr=%02x\n", pc, addr, data); } #endif - mem[addr] = val; + mem[addr] = data; return; } @@ -507,12 +505,6 @@ int main(int argc, char **argv) { entry_point = load(p); } - // do this before creating the CPU - if (entry_point != -1) { - mem[RESET_VECTOR] = (uint8_t)(entry_point & 0xff); - mem[RESET_VECTOR + 1] = (uint8_t)(entry_point >> 8); - } - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { fprintf(stderr, "SDL_Init(): %s\n\n", SDL_GetError()); exit(EXIT_FAILURE); @@ -603,11 +595,10 @@ int main(int argc, char **argv) { joystick_axes[i] = JOYSTICK_COUNT >> 1; } - cpu = vrEmu6502New(CPU_65C02, mem_read, mem_write); - if (cpu == NULL) { - perror("malloc()"); - exit(EXIT_FAILURE); - } + cpu_65c02_init(&cpu, read_byte, NULL, write_byte, NULL); + cpu_65c02_reset(&cpu); + if (entry_point != -1) + cpu.regs.word.pc = entry_point; // main loop int update_count = 0; @@ -842,11 +833,15 @@ int main(int argc, char **argv) { SDL_Delay(1); } else { - for (int j = 0; j < CYCLES_PER_SAMPLE; ) - j += execute(cpu); + for (cpu.cycles = 0; cpu.cycles < CYCLES_PER_SAMPLE; ) { + cpu_65c02_execute(&cpu); + if (jam_flag) { + jam_flag = false; + break; + } + } if (exit_flag) break; - vrEmu6502Unjam(cpu); // sample tape and speaker outputs at CYCLES_PER_SAMPLE rate #if 0 @@ -866,8 +861,6 @@ int main(int argc, char **argv) { } quit: - vrEmu6502Destroy(cpu); - if (joystick) SDL_JoystickClose(joystick); SDL_CloseAudioDevice(audio_device_id); diff --git a/utils/disasm_to_c.py b/utils/disasm_to_c.py index be6836c..f10eea6 100755 --- a/utils/disasm_to_c.py +++ b/utils/disasm_to_c.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 import bisect +import py65.devices.mpu65c02 +import py65.disassembler import re import sys from intelhex import IntelHex @@ -28,303 +30,6 @@ item_types = { 'code_m1': ITEM_CODE_M1, } -# from vrEmu6502.c -opcodes = [ - # 0x00 - ('brk', 'imp', 7), - ('ora', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('tsb', 'zp', 5), - ('ora', 'zp', 3), - ('asl', 'zp', 5), - ('nop', 'imp', 1), - ('php', 'imp', 3), - ('ora', 'imm', 2), - ('asl', 'acc', 2), - ('nop', 'imp', 1), - ('tsb', 'ab', 6), - ('ora', 'ab', 4), - ('asl', 'ab', 6), - ('nop', 'imp', 1), - # 0x10 - ('bpl', 'rel', 2), - ('ora', 'yip', 5), - ('ora', 'zpi', 5), - ('nop', 'imp', 1), - ('trb', 'zp', 5), - ('ora', 'zpx', 4), - ('asl', 'zpx', 6), - ('nop', 'imp', 1), - ('clc', 'imp', 2), - ('ora', 'ayp', 4), - ('inc', 'acc', 2), - ('nop', 'imp', 1), - ('trb', 'ab', 6), - ('ora', 'axp', 4), - ('asl', 'axp', 6), - ('nop', 'imp', 1), - # 0x20 - ('jsr', 'ab', 6), - ('and', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('bit', 'zp', 3), - ('and', 'zp', 3), - ('rol', 'zp', 5), - ('nop', 'imp', 1), - ('plp', 'imp', 4), - ('and', 'imm', 2), - ('rol', 'acc', 2), - ('nop', 'imp', 1), - ('bit', 'ab', 4), - ('and', 'ab', 4), - ('rol', 'ab', 6), - ('nop', 'imp', 1), - # 0x30 - ('bmi', 'rel', 2), - ('and', 'yip', 5), - ('and', 'zpi', 5), - ('nop', 'imp', 1), - ('bit', 'zpx', 4), - ('and', 'zpx', 4), - ('rol', 'zpx', 6), - ('nop', 'imp', 1), - ('sec', 'imp', 2), - ('and', 'ayp', 4), - ('dec', 'acc', 2), - ('nop', 'imp', 1), - ('bit', 'abx', 4), - ('and', 'axp', 4), - ('rol', 'axp', 6), - ('nop', 'imp', 1), - # 0x40 - ('rti', 'imp', 6), - ('eor', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('ldd', 'zp', 3), - ('eor', 'zp', 3), - ('lsr', 'zp', 5), - ('nop', 'imp', 1), - ('pha', 'imp', 3), - ('eor', 'imm', 2), - ('lsr', 'acc', 2), - ('nop', 'imp', 1), - ('jmp', 'ab', 3), - ('eor', 'ab', 4), - ('lsr', 'ab', 6), - ('nop', 'imp', 1), - # 0x50 - ('bvc', 'rel', 2), - ('eor', 'yip', 5), - ('eor', 'zpi', 5), - ('nop', 'imp', 1), - ('ldd', 'zpx', 4), - ('eor', 'zpx', 4), - ('lsr', 'zpx', 6), - ('nop', 'imp', 1), - ('cli', 'imp', 2), - ('eor', 'ayp', 4), - ('phy', 'imp', 3), - ('nop', 'imp', 1), - ('ldd', 'ab', 8), - ('eor', 'axp', 4), - ('lsr', 'axp', 6), - ('nop', 'imp', 1), - # 0x60 - ('rts', 'imp', 6), - ('adc', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('stz', 'zp', 3), - ('adc', 'zp', 3), - ('ror', 'zp', 5), - ('nop', 'imp', 1), - ('pla', 'imp', 4), - ('adc', 'imm', 2), - ('ror', 'acc', 2), - ('nop', 'imp', 1), - ('jmp', 'ind', 6), - ('adc', 'ab', 4), - ('ror', 'ab', 6), - ('nop', 'imp', 1), - # 0x70 - ('bvs', 'rel', 2), - ('adc', 'yip', 5), - ('adc', 'zpi', 5), - ('nop', 'imp', 1), - ('stz', 'zpx', 4), - ('adc', 'zpx', 4), - ('ror', 'zpx', 6), - ('nop', 'imp', 1), - ('sei', 'imp', 2), - ('adc', 'ayp', 4), - ('ply', 'imp', 4), - ('nop', 'imp', 1), - ('jmp', 'indx', 6), - ('adc', 'axp', 4), - ('ror', 'axp', 6), - ('nop', 'imp', 1), - # 0x80 - ('bra', 'rel', 2), - ('sta', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('sty', 'zp', 3), - ('sta', 'zp', 3), - ('stx', 'zp', 3), - ('nop', 'imp', 1), - ('dey', 'imp', 2), - ('bit', 'imm', 2), - ('txa', 'imp', 2), - ('nop', 'imp', 1), - ('sty', 'ab', 4), - ('sta', 'ab', 4), - ('stx', 'ab', 4), - ('nop', 'imp', 1), - # 0x90 - ('bcc', 'rel', 2), - ('sta', 'yin', 6), - ('sta', 'zpi', 5), - ('nop', 'imp', 1), - ('sty', 'zpx', 4), - ('sta', 'zpx', 4), - ('stx', 'zpy', 4), - ('nop', 'imp', 1), - ('tya', 'imp', 2), - ('sta', 'aby', 5), - ('txs', 'imp', 2), - ('nop', 'imp', 1), - ('stz', 'ab', 4), - ('sta', 'abx', 5), - ('stz', 'abx', 5), - ('nop', 'imp', 1), - # 0xa0 - ('ldy', 'imm', 2), - ('lda', 'xin', 6), - ('ldx', 'imm', 2), - ('nop', 'imp', 1), - ('ldy', 'zp', 3), - ('lda', 'zp', 3), - ('ldx', 'zp', 3), - ('nop', 'imp', 1), - ('tay', 'imp', 2), - ('lda', 'imm', 2), - ('tax', 'imp', 2), - ('nop', 'imp', 1), - ('ldy', 'ab', 4), - ('lda', 'ab', 4), - ('ldx', 'ab', 4), - ('nop', 'imp', 1), - # 0xb0 - ('bcs', 'rel', 2), - ('lda', 'yip', 5), - ('lda', 'zpi', 5), - ('nop', 'imp', 1), - ('ldy', 'zpx', 4), - ('lda', 'zpx', 4), - ('ldx', 'zpy', 4), - ('nop', 'imp', 1), - ('clv', 'imp', 2), - ('lda', 'ayp', 4), - ('tsx', 'imp', 2), - ('nop', 'imp', 1), - ('ldy', 'axp', 4), - ('lda', 'axp', 4), - ('ldx', 'ayp', 4), - ('nop', 'imp', 1), - # 0xc0 - ('cpy', 'imm', 2), - ('cmp', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('cpy', 'zp', 3), - ('cmp', 'zp', 3), - ('dec', 'zp', 5), - ('nop', 'imp', 1), - ('iny', 'imp', 2), - ('cmp', 'imm', 2), - ('dex', 'imp', 2), - ('nop', 'imp', 1), - ('cpy', 'ab', 4), - ('cmp', 'ab', 4), - ('dec', 'ab', 6), - ('nop', 'imp', 1), - # 0xd0 - ('bne', 'rel', 2), - ('cmp', 'yip', 5), - ('cmp', 'zpi', 5), - ('nop', 'imp', 1), - ('ldd', 'zpx', 4), - ('cmp', 'zpx', 4), - ('dec', 'zpx', 6), - ('nop', 'imp', 1), - ('cld', 'imp', 2), - ('cmp', 'ayp', 4), - ('phx', 'imp', 3), - ('nop', 'imp', 1), - ('ldd', 'ab', 4), - ('cmp', 'axp', 4), - ('dec', 'abx', 7), - ('nop', 'imp', 1), - # 0xe0 - ('cpx', 'imm', 2), - ('sbc', 'xin', 6), - ('ldd', 'imm', 2), - ('nop', 'imp', 1), - ('cpx', 'zp', 3), - ('sbc', 'zp', 3), - ('inc', 'zp', 5), - ('nop', 'imp', 1), - ('inx', 'imp', 2), - ('sbc', 'imm', 2), - ('nop', 'imp', 2), - ('nop', 'imp', 1), - ('cpx', 'ab', 4), - ('sbc', 'ab', 4), - ('inc', 'ab', 6), - ('nop', 'imp', 1), - # 0xf0 - ('beq', 'rel', 2), - ('sbc', 'yip', 5), - ('sbc', 'zpi', 5), - ('nop', 'imp', 1), - ('ldd', 'zpx', 4), - ('sbc', 'zpx', 4), - ('inc', 'zpx', 6), - ('nop', 'imp', 1), - ('sed', 'imp', 2), - ('sbc', 'ayp', 4), - ('plx', 'imp', 4), - ('nop', 'imp', 1), - ('ldd', 'ab', 4), - ('sbc', 'axp', 4), - ('inc', 'abx', 7), - ('nop', 'imp', 1), -] -# instruction length is looked up from addressing mode -addr_modes = { - 'ab': 3, - 'abx': 3, - 'aby': 3, - 'acc': 1, - 'axp': 1, - 'ayp': 1, - 'imm': 2, - 'imp': 1, - 'ind': 3, - 'indx': 3, - 'rel': 2, - 'xin': 2, - 'yin': 2, - 'yip': 2, - 'zp': 2, - 'zpi': 2, - 'zpx': 2, - 'zpy': 2, -} - if len(sys.argv) < 5: print(f'usage: {sys.argv[0]:s} in_addrs.txt in.ihx out.c out.h') sys.exit(EXIT_FAILURE) @@ -333,6 +38,25 @@ in_ihx = sys.argv[2] out_c = sys.argv[3] out_h = sys.argv[4] +with open('cpu_65c02.c') as fin: + for line in fin: + line = line.rstrip() + if line == ' switch (cpu_65c02_fetch_byte(self)) {': + break + else: + assert False + + opcodes = [] + for line in fin: + line = line.rstrip() + if line == ' }': + break + if line[:9] == ' case 0x' and line[11:] == ':': + assert len(opcodes) == int(line[9:11], 16) + opcodes.append('') + else: + opcodes[-1] += line.replace('self', 'cpu') + '\n' + class AreaInfo: def __init__(self, size, name, _type, comment): self.size = size @@ -479,13 +203,17 @@ for i in range(0, len(segments), 2): print(f'[{addr0:04x}, {addr1:04x})') mem[addr0:addr1] = list(intelhex.tobinstr(addr0, addr1 - 1)) +mpu = py65.devices.mpu65c02.MPU(mem, 0) +disassembler = py65.disassembler.Disassembler(mpu) + with open(out_c, 'w') as fout: fout.write( - f'''#include "rassert.h" + f'''#include +#include "rassert.h" #include "{out_h:s}" -int execute(VrEmu6502 *cpu) {{ - switch (cpu->pc) {{ +void execute(struct cpu_65c02 *cpu) {{ + switch (cpu->regs.word.pc) {{ ''' ) @@ -513,16 +241,12 @@ int execute(VrEmu6502 *cpu) {{ item_info[item].type == ITEM_CODE_IGN ): opcode = mem[addr] - op, addr_mode, cycles = opcodes[opcode] - n = addr_modes[addr_mode] + n, _ = disassembler.instruction_at(i) fout.write( f''' case 0x{addr:04x}: - rassert(cpu->readFn(0x{addr:04x}) == 0x{opcode:02x}); - cpu->pc = 0x{(addr + 1) & 0xffff:04x}; - cpu->step = {cycles:d}; - {op:s}(cpu, {addr_mode:s}); - return cpu->step; -''' + rassert(cpu->read_byte(cpu->read_byte_context, 0x{addr:04x}) == 0x{opcode:02x}); + cpu->regs.word.pc = 0x{(addr + 1) & 0xffff:04x}; +{opcodes[opcode]:s}''' ) elif item_info[item].type == ITEM_WORD: if addr + 1 >= item_addr[item] + item_info[item].size: @@ -570,9 +294,9 @@ with open(out_h, 'w') as fout: f'''#ifndef {include_guard:s} #define {include_guard:s} -#include "vrEmu6502/src/vrEmu6502.h" +#include "cpu_65c02.h" -int execute(VrEmu6502 *cpu); +void execute(struct cpu_65c02 *cpu); #endif '''