// cpu.c // // 20050125 Markku Alén #include "cpu.h" #define NMI_VECTOR 0xfffa #define RST_VECTOR 0xfffc #define IRQ_VECTOR 0xfffe static int (*read_bus)(int); static void (*write_bus)(int, int); static int (*read_page)(int); static void (*write_page)(int, int); static void (*jam_handler)(int, int); unsigned int cycles; void (*reset_cpu)(void); void (*raise_nmi)(void); void (*raise_irq)(void); void (*exec_cpu)(void); static trap_t *first_trap; static int ea, tmp1, tmp2; static int accumulator; static int register_x; static int register_y; static int pc, sp; static int sr, c, nz; #define FLAG_N 0x80 #define FLAG_V 0x40 #define FLAG_X 0x20 #define FLAG_B 0x10 #define FLAG_D 0x08 #define FLAG_I 0x04 #define FLAG_Z 0x02 #define FLAG_C 0x01 #define TEST_N() ((nz & 0x8080) != 0) #define TEST_V() ((sr & 0x40) != 0) #define TEST_X() ((sr & 0x20) != 0) #define TEST_B() ((sr & 0x10) != 0) #define TEST_D() ((sr & 0x08) != 0) #define TEST_I() ((sr & 0x04) != 0) #define TEST_Z() ((nz & 0xff) == 0) #define TEST_C() ((c & 0x100) != 0) #define SET_V() sr |= 0x40; #define SET_D() sr |= 0x08; #define SET_I() sr |= 0x04; #define SET_C() c = 0x100; #define CLEAR_V() sr &= 0xbf; #define CLEAR_D() sr &= 0xf7; #define CLEAR_I() sr &= 0xfb; #define CLEAR_C() c = 0; static const int z_tbl[4] = { 0xffff, 0xffff, 0x8000, 0x8000 }; #define get_sr() ((nz & 0x80) | ((nz & 0x8000) >> 8) | (sr & 0x7c) | ((((nz & 0xff) == 0) & 1) << 1) | ((c & 0x100) >> 8)) #define set_sr(SR) { c = sr = (SR); c <<= 8; nz = (sr | (c & 0x8000)) & z_tbl[sr & 0x02]; } #define DECL(NAME) static void NAME(void); #define BEGIN(NAME) static void NAME(void) { #define END exec_cpu = op_code[read_bus(pc++)]; } DECL(jam) DECL(nmi) DECL(rst) DECL(irq) DECL(brk_imm) DECL(nop) DECL(rti) DECL(rts) DECL(jsr_abs) DECL(jmp_abs) DECL(jmp_ind) DECL(php) DECL(plp) DECL(pha) DECL(pla) DECL(tax) DECL(txa) DECL(tay) DECL(tya) DECL(txs) DECL(tsx) DECL(clc) DECL(sec) DECL(cli) DECL(sei) DECL(clv) DECL(cld) DECL(sed) DECL(bpl) DECL(bmi) DECL(bvc) DECL(bvs) DECL(bcc) DECL(bcs) DECL(bne) DECL(beq) DECL(lda_imm) DECL(lda_zp) DECL(lda_zp_x) DECL(lda_abs) DECL(lda_abs_x) DECL(lda_abs_y) DECL(lda_ind_x) DECL(lda_ind_y) DECL(ldx_imm) DECL(ldx_zp) DECL(ldx_zp_y) DECL(ldx_abs) DECL(ldx_abs_y) DECL(ldy_imm) DECL(ldy_zp) DECL(ldy_zp_x) DECL(ldy_abs) DECL(ldy_abs_x) DECL(sta_zp) DECL(sta_zp_x) DECL(sta_abs) DECL(sta_abs_x) DECL(sta_abs_y) DECL(sta_ind_x) DECL(sta_ind_y) DECL(stx_zp) DECL(stx_zp_y) DECL(stx_abs) DECL(sty_zp) DECL(sty_zp_x) DECL(sty_abs) DECL(cmp_imm) DECL(cmp_zp) DECL(cmp_zp_x) DECL(cmp_abs) DECL(cmp_abs_x) DECL(cmp_abs_y) DECL(cmp_ind_x) DECL(cmp_ind_y) DECL(cpx_imm) DECL(cpx_zp) DECL(cpx_abs) DECL(cpy_imm) DECL(cpy_zp) DECL(cpy_abs) DECL(ora_imm) DECL(ora_zp) DECL(ora_zp_x) DECL(ora_abs) DECL(ora_abs_x) DECL(ora_abs_y) DECL(ora_ind_x) DECL(ora_ind_y) DECL(eor_imm) DECL(eor_zp) DECL(eor_zp_x) DECL(eor_abs) DECL(eor_abs_x) DECL(eor_abs_y) DECL(eor_ind_x) DECL(eor_ind_y) DECL(and_imm) DECL(and_zp) DECL(and_zp_x) DECL(and_abs) DECL(and_abs_x) DECL(and_abs_y) DECL(and_ind_x) DECL(and_ind_y) DECL(adc_imm) DECL(adc_zp) DECL(adc_zp_x) DECL(adc_abs) DECL(adc_abs_x) DECL(adc_abs_y) DECL(adc_ind_x) DECL(adc_ind_y) DECL(sbc_imm) DECL(sbc_zp) DECL(sbc_zp_x) DECL(sbc_abs) DECL(sbc_abs_x) DECL(sbc_abs_y) DECL(sbc_ind_x) DECL(sbc_ind_y) DECL(bit_zp) DECL(bit_abs) DECL(inc_zp) DECL(inc_zp_x) DECL(inc_abs) DECL(inc_abs_x) DECL(dec_zp) DECL(dec_zp_x) DECL(dec_abs) DECL(dec_abs_x) DECL(asl_a) DECL(asl_zp) DECL(asl_zp_x) DECL(asl_abs) DECL(asl_abs_x) DECL(lsr_a) DECL(lsr_zp) DECL(lsr_zp_x) DECL(lsr_abs) DECL(lsr_abs_x) DECL(rol_a) DECL(rol_zp) DECL(rol_zp_x) DECL(rol_abs) DECL(rol_abs_x) DECL(ror_a) DECL(ror_zp) DECL(ror_zp_x) DECL(ror_abs) DECL(ror_abs_x) DECL(inx) DECL(dex) DECL(iny) DECL(dey) static void (* const (op_code[256]))(void) = { brk_imm ,ora_ind_x ,jam ,jam ,jam ,ora_zp ,asl_zp ,jam , php ,ora_imm ,asl_a ,jam ,jam ,ora_abs ,asl_abs ,jam , bpl ,ora_ind_y ,jam ,jam ,jam ,ora_zp_x ,asl_zp_x ,jam , clc ,ora_abs_y ,jam ,jam ,jam ,ora_abs_x ,asl_abs_x ,jam , jsr_abs ,and_ind_x ,jam ,jam ,bit_zp ,and_zp ,rol_zp ,jam , plp ,and_imm ,rol_a ,jam ,bit_abs ,and_abs ,rol_abs ,jam , bmi ,and_ind_y ,jam ,jam ,jam ,and_zp_x ,rol_zp_x ,jam , sec ,and_abs_y ,jam ,jam ,jam ,and_abs_x ,rol_abs_x ,jam , rti ,eor_ind_x ,jam ,jam ,jam ,eor_zp ,lsr_zp ,jam , pha ,eor_imm ,lsr_a ,jam ,jmp_abs ,eor_abs ,lsr_abs ,jam , bvc ,eor_ind_y ,jam ,jam ,jam ,eor_zp_x ,lsr_zp_x ,jam , cli ,eor_abs_y ,jam ,jam ,jam ,eor_abs_x ,lsr_abs_x ,jam , rts ,adc_ind_x ,jam ,jam ,jam ,adc_zp ,ror_zp ,jam , pla ,adc_imm ,ror_a ,jam ,jmp_ind ,adc_abs ,ror_abs ,jam , bvs ,adc_ind_y ,jam ,jam ,jam ,adc_zp_x ,ror_zp_x ,jam , sei ,adc_abs_y ,jam ,jam ,jam ,adc_abs_x ,ror_abs_x ,jam , jam ,sta_ind_x ,jam ,jam ,sty_zp ,sta_zp ,stx_zp ,jam , dey ,jam ,txa ,jam ,sty_abs ,sta_abs ,stx_abs ,jam , bcc ,sta_ind_y ,jam ,jam ,sty_zp_x ,sta_zp_x ,stx_zp_y ,jam , tya ,sta_abs_y ,txs ,jam ,jam ,sta_abs_x ,jam ,jam , ldy_imm ,lda_ind_x ,ldx_imm ,jam ,ldy_zp ,lda_zp ,ldx_zp ,jam , tay ,lda_imm ,tax ,jam ,ldy_abs ,lda_abs ,ldx_abs ,jam , bcs ,lda_ind_y ,jam ,jam ,ldy_zp_x ,lda_zp_x ,ldx_zp_y ,jam , clv ,lda_abs_y ,tsx ,jam ,ldy_abs_x ,lda_abs_x ,ldx_abs_y ,jam , cpy_imm ,cmp_ind_x ,jam ,jam ,cpy_zp ,cmp_zp ,dec_zp ,jam , iny ,cmp_imm ,dex ,jam ,cpy_abs ,cmp_abs ,dec_abs ,jam , bne ,cmp_ind_y ,jam ,jam ,jam ,cmp_zp_x ,dec_zp_x ,jam , cld ,cmp_abs_y ,jam ,jam ,jam ,cmp_abs_x ,dec_abs_x ,jam , cpx_imm ,sbc_ind_x ,jam ,jam ,cpx_zp ,sbc_zp ,inc_zp ,jam , inx ,sbc_imm ,nop ,jam ,cpx_abs ,sbc_abs ,inc_abs ,jam , beq ,sbc_ind_y ,jam ,jam ,jam ,sbc_zp_x ,inc_zp_x ,jam , sed ,sbc_abs_y ,jam ,jam ,jam ,sbc_abs_x ,inc_abs_x ,jam , }; void set_c_flag(int enable) { int tmp; tmp = get_sr(); tmp &= ~FLAG_C; if(enable) tmp |= FLAG_C; set_sr(tmp); } void set_z_flag(int enable) { int tmp; tmp = get_sr(); tmp &= ~FLAG_Z; if(enable) tmp |= FLAG_Z; set_sr(tmp); } void set_pc(int addr) { pc = addr; } int get_pc(void) { return pc; } int get_a(void) { return accumulator; } int get_x(void) { return register_x; } int get_y(void) { return register_y; } void init_cpu(int (*cpu_read)(int), void (*cpu_write)(int, int), int (*cpu_read_page)(int), void (*cpu_write_page)(int, int), void (*cpu_jam)(int, int)) { read_bus = cpu_read; write_bus = cpu_write; read_page = cpu_read_page; write_page = cpu_write_page; jam_handler = cpu_jam; accumulator = 0; register_x = 0; register_y = 0; pc = sp = 0; set_sr(FLAG_X | FLAG_B | FLAG_I); cycles = 0; reset_cpu = rst; raise_nmi = nmi; raise_irq = irq; exec_cpu = jam; first_trap = 0; } static int trap(void) { trap_t *trap; for(trap = first_trap;trap != 0;trap = trap->next_trap) { if(trap->addr == (pc - 1)) return trap->handler(); } return -1; } static int install_trap(trap_t *trap, void (*poke)(int, int), int (*peek)(int)) { int i; for(i = sizeof(trap->org) / sizeof(trap->org[0]);i-- > 0;) { if(peek(trap->addr + i) != trap->org[i]) return -1; } poke(trap->addr, 0x00); trap->next_trap = first_trap; first_trap = trap; return 0; } void install_traps(int cnt, trap_t *tbl, void (*poke)(int, int), int (*peek)(int)) { while(cnt-- > 0) (void)install_trap(&tbl[cnt], poke, peek); } #define CYCLES(AMOUNT) cycles += AMOUNT; #define PUSH(DATA) { write_page(sp | 0x0100, DATA); sp = (sp - 1) & 0xff; } #define POP() read_page((sp = (sp + 1) & 0xff) | 0x0100) #define JMP_ABSOLUTE(EA) \ { \ (EA) = read_bus(tmp1 = pc); \ (EA) |= read_bus(tmp1 + 1) << 8; \ CYCLES(3); \ } #define JMP_INDIRECT(EA) \ { \ tmp2 = read_bus(pc++); \ tmp1 = read_bus(pc++) << 8; \ (EA) = read_bus(tmp2 | tmp1); \ (EA) |= read_bus((((tmp2 + 1) & 0x00ff) | tmp1)) << 8; \ CYCLES(5); \ } #define READ_IMMEDIATE(EA) \ { \ (EA) = pc++; \ CYCLES(2); \ } #define READ_ZERO_PAGE(EA) \ { \ (EA) = read_bus(pc++); \ CYCLES(3); \ } #define READ_ZERO_PAGE_X(EA) \ { \ (EA) = (read_bus(pc++) + register_x) & 0xff; \ CYCLES(4); \ } #define READ_ZERO_PAGE_Y(EA) \ { \ (EA) = (read_bus(pc++) + register_y) & 0xff; \ CYCLES(4); \ } #define READ_ABSOLUTE(EA) \ { \ tmp1 = read_bus(pc++); \ (EA) = tmp1 + (read_bus(pc++) << 8); \ CYCLES(4); \ } #define READ_ABSOLUTE_X(EA) \ { \ tmp1 = read_bus(pc++) + register_x; \ (EA) = tmp1 + (read_bus(pc++) << 8); \ CYCLES(tmp1 > 0xff ? 5 : 4); \ } #define READ_ABSOLUTE_Y(EA) \ { \ tmp1 = read_bus(pc++) + register_y; \ (EA) = tmp1 + (read_bus(pc++) << 8); \ CYCLES(tmp1 > 0xff ? 5 : 4); \ } #define READ_INDIRECT_X(EA) \ { \ tmp1 = read_bus(pc++) + register_x; \ (EA) = read_page(tmp1) + (read_page((tmp1 + 1) & 0xff) << 8); \ CYCLES(6); \ } #define READ_INDIRECT_Y(EA) \ { \ tmp1 = read_bus(pc++); \ tmp2 = read_page(tmp1++) + register_y; \ (EA) = tmp2 + ((read_page(tmp1 & 0xff)) << 8); \ CYCLES(tmp2 > 0xff ? 6 : 5); \ } #define WRITE_ZERO_PAGE(EA) READ_ZERO_PAGE(EA) #define WRITE_ZERO_PAGE_X(EA) READ_ZERO_PAGE_X(EA) #define WRITE_ZERO_PAGE_Y(EA) READ_ZERO_PAGE_Y(EA) #define WRITE_ABSOLUTE(EA) READ_ABSOLUTE(EA) #define WRITE_ABSOLUTE_X(EA) \ { \ tmp1 = read_bus(pc++) + register_x; \ (EA) = tmp1 + (read_bus(pc++) << 8); \ CYCLES(5); \ } #define WRITE_ABSOLUTE_Y(EA) \ { \ tmp1 = read_bus(pc++) + register_y; \ (EA) = tmp1 + (read_bus(pc++) << 8); \ CYCLES(5); \ } #define WRITE_INDIRECT_X(EA) READ_INDIRECT_X(EA) #define WRITE_INDIRECT_Y(EA) \ { \ tmp1 = read_bus(pc++); \ tmp2 = read_page(tmp1++) + register_y; \ (EA) = tmp2 + (read_page(tmp1 & 0xff) << 8); \ CYCLES(6); \ } #define RELATIVE(S) \ { \ tmp1 = read_bus(pc++); \ if((S) != 0) \ { \ if((tmp1 & 0x0080) != 0) tmp1 -= 0x100; \ CYCLES((((pc ^ (pc + tmp1)) & 0xff00) != 0) ? 4 : 3); \ pc += tmp1; \ } \ else \ { \ CYCLES(2); \ } \ } BEGIN(jam) --pc; if(jam_handler != 0) jam_handler(pc, read_bus(pc)); CYCLES(1); END BEGIN(nmi) --pc; PUSH(pc >> 8); PUSH(pc); PUSH(get_sr() & ~FLAG_B); pc = read_bus(NMI_VECTOR) | (read_bus(NMI_VECTOR + 1) << 8); CYCLES(7); END BEGIN(rst) PUSH(get_sr() & ~FLAG_B); pc = read_bus(RST_VECTOR) | (read_bus(RST_VECTOR + 1) << 8); CYCLES(5); END BEGIN(irq) if(TEST_I()) return; --pc; PUSH(pc >> 8); PUSH(pc); PUSH(get_sr() & ~FLAG_B); SET_I(); pc = read_bus(IRQ_VECTOR) | (read_bus(IRQ_VECTOR + 1) << 8); CYCLES(7); END BEGIN(brk_imm) if(trap() != 0) { pc++; PUSH(get_sr()); PUSH(pc >> 8); PUSH(pc); SET_I(); pc = read_bus(IRQ_VECTOR) | (read_bus(IRQ_VECTOR + 1) << 8); CYCLES(7); } END BEGIN(nop) CYCLES(2) END BEGIN(rti) set_sr(POP() | FLAG_B); tmp1 = POP(); pc = tmp1 | (POP() << 8); CYCLES(6); END BEGIN(rts) tmp1 = POP(); pc = (tmp1 | (POP() << 8)) + 1; CYCLES(6) END BEGIN(jsr_abs) tmp1 = read_bus(pc++); PUSH(pc >> 8); PUSH(pc); pc = tmp1 | (read_bus(pc++) << 8); CYCLES(6); END BEGIN(jmp_abs) JMP_ABSOLUTE(pc) END BEGIN(jmp_ind) JMP_INDIRECT(pc) END BEGIN(php) PUSH(get_sr()) CYCLES(3) END BEGIN(plp) set_sr(POP() | FLAG_B); CYCLES(4) END BEGIN(pha) PUSH(accumulator) CYCLES(3) END BEGIN(pla) nz = accumulator = POP(); CYCLES(4) END BEGIN(tax) nz = register_x = accumulator; CYCLES(2) END BEGIN(txa) nz = accumulator = register_x; CYCLES(2) END BEGIN(tay) nz = register_y = accumulator; CYCLES(2) END BEGIN(tya) nz = accumulator = register_y; CYCLES(2) END BEGIN(txs) sp = register_x; CYCLES(2) END BEGIN(tsx) nz = register_x = sp; CYCLES(2) END BEGIN(inx) nz = register_x = (register_x + 1) & 0xff; CYCLES(2) END BEGIN(dex) nz = register_x = (register_x - 1) & 0xff; CYCLES(2) END BEGIN(iny) nz = register_y = (register_y + 1) & 0xff; CYCLES(2) END BEGIN(dey) nz = register_y = (register_y - 1) & 0xff; CYCLES(2) END BEGIN(clc) CLEAR_C() CYCLES(2) END BEGIN(sec) SET_C() CYCLES(2) END BEGIN(cli) CLEAR_I() CYCLES(2) END BEGIN(sei) SET_I() CYCLES(2) END BEGIN(clv) CLEAR_V() CYCLES(2) END BEGIN(cld) CLEAR_D() CYCLES(2) END BEGIN(sed) SET_D() CYCLES(2) END BEGIN(bpl) RELATIVE(!TEST_N()) END BEGIN(bmi) RELATIVE(TEST_N()) END BEGIN(bvc) RELATIVE(!TEST_V()) END BEGIN(bvs) RELATIVE(TEST_V()) END BEGIN(bcc) RELATIVE(!TEST_C()) END BEGIN(bcs) RELATIVE(TEST_C()) END BEGIN(bne) RELATIVE(!TEST_Z()) END BEGIN(beq) RELATIVE(TEST_Z()) END BEGIN(lda_imm) READ_IMMEDIATE(ea) nz = accumulator = read_bus(ea); END BEGIN(lda_zp) READ_ZERO_PAGE(ea) nz = accumulator = read_page(ea); END BEGIN(lda_zp_x) READ_ZERO_PAGE_X(ea) nz = accumulator = read_page(ea); END BEGIN(lda_abs) READ_ABSOLUTE(ea) nz = accumulator = read_bus(ea); END BEGIN(lda_abs_x) READ_ABSOLUTE_X(ea) nz = accumulator = read_bus(ea); END BEGIN(lda_abs_y) READ_ABSOLUTE_Y(ea) nz = accumulator = read_bus(ea); END BEGIN(lda_ind_x) READ_INDIRECT_X(ea) nz = accumulator = read_bus(ea); END BEGIN(lda_ind_y) READ_INDIRECT_Y(ea) nz = accumulator = read_bus(ea); END BEGIN(ldx_imm) READ_IMMEDIATE(ea) nz = register_x = read_bus(ea); END BEGIN(ldx_zp) READ_ZERO_PAGE(ea) nz = register_x = read_page(ea); END BEGIN(ldx_zp_y) READ_ZERO_PAGE_Y(ea) nz = register_x = read_page(ea); END BEGIN(ldx_abs) READ_ABSOLUTE(ea) nz = register_x = read_bus(ea); END BEGIN(ldx_abs_y) READ_ABSOLUTE_Y(ea) nz = register_x = read_bus(ea); END BEGIN(ldy_imm) READ_IMMEDIATE(ea) nz = register_y = read_bus(ea); END BEGIN(ldy_zp) READ_ZERO_PAGE(ea) nz = register_y = read_page(ea); END BEGIN(ldy_zp_x) READ_ZERO_PAGE_X(ea) nz = register_y = read_page(ea); END BEGIN(ldy_abs) READ_ABSOLUTE(ea) nz = register_y = read_bus(ea); END BEGIN(ldy_abs_x) READ_ABSOLUTE_X(ea) nz = register_y = read_bus(ea); END BEGIN(sta_zp) WRITE_ZERO_PAGE(ea) write_page(ea, accumulator); END BEGIN(sta_zp_x) WRITE_ZERO_PAGE_X(ea) write_page(ea, accumulator); END BEGIN(sta_abs) WRITE_ABSOLUTE(ea) write_bus(ea, accumulator); END BEGIN(sta_abs_x) WRITE_ABSOLUTE_X(ea) write_bus(ea, accumulator); END BEGIN(sta_abs_y) WRITE_ABSOLUTE_Y(ea) write_bus(ea, accumulator); END BEGIN(sta_ind_x) WRITE_INDIRECT_X(ea) write_bus(ea, accumulator); END BEGIN(sta_ind_y) WRITE_INDIRECT_Y(ea) write_bus(ea, accumulator); END BEGIN(stx_zp) WRITE_ZERO_PAGE(ea) write_page(ea, register_x); END BEGIN(stx_zp_y) WRITE_ZERO_PAGE_Y(ea) write_page(ea, register_x); END BEGIN(stx_abs) WRITE_ABSOLUTE(ea) write_bus(ea, register_x); END BEGIN(sty_zp) WRITE_ZERO_PAGE(ea) write_page(ea, register_y); END BEGIN(sty_zp_x) WRITE_ZERO_PAGE_X(ea) write_page(ea, register_y); END BEGIN(sty_abs) WRITE_ABSOLUTE(ea) write_bus(ea, register_y); END #define COMPARE(A, B) \ { \ nz = ((A) & 0xff) - ((B) & 0xff); \ c = ~nz; \ nz &= 0xff;\ } BEGIN(cmp_imm) READ_IMMEDIATE(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_zp) READ_ZERO_PAGE(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_zp_x) READ_ZERO_PAGE_X(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_abs) READ_ABSOLUTE(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_abs_x) READ_ABSOLUTE_X(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_abs_y) READ_ABSOLUTE_Y(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_ind_x) READ_INDIRECT_X(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cmp_ind_y) READ_INDIRECT_Y(ea) COMPARE(accumulator, read_bus(ea)) END BEGIN(cpx_imm) READ_IMMEDIATE(ea) COMPARE(register_x, read_bus(ea)) END BEGIN(cpx_zp) READ_ZERO_PAGE(ea) COMPARE(register_x, read_bus(ea)) END BEGIN(cpx_abs) READ_ABSOLUTE(ea) COMPARE(register_x, read_bus(ea)) END BEGIN(cpy_imm) READ_IMMEDIATE(ea) COMPARE(register_y, read_bus(ea)) END BEGIN(cpy_zp) READ_ZERO_PAGE(ea) COMPARE(register_y, read_bus(ea)) END BEGIN(cpy_abs) READ_ABSOLUTE(ea) COMPARE(register_y, read_bus(ea)) END #define ORA(A, B) \ { \ (A) |= (B); \ nz = (A) & 0xff; \ } BEGIN(ora_imm) READ_IMMEDIATE(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_zp) READ_ZERO_PAGE(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_zp_x) READ_ZERO_PAGE_X(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_abs) READ_ABSOLUTE(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_abs_x) READ_ABSOLUTE_X(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_abs_y) READ_ABSOLUTE_Y(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_ind_x) READ_INDIRECT_X(ea) ORA(accumulator, read_bus(ea)) END BEGIN(ora_ind_y) READ_INDIRECT_Y(ea) ORA(accumulator, read_bus(ea)) END #define EOR(A, B) \ { \ (A) ^= (B); \ nz = (A) & 0xff; \ } BEGIN(eor_imm) READ_IMMEDIATE(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_zp) READ_ZERO_PAGE(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_zp_x) READ_ZERO_PAGE_X(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_abs) READ_ABSOLUTE(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_abs_x) READ_ABSOLUTE_X(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_abs_y) READ_ABSOLUTE_Y(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_ind_x) READ_INDIRECT_X(ea) EOR(accumulator, read_bus(ea)) END BEGIN(eor_ind_y) READ_INDIRECT_Y(ea) EOR(accumulator, read_bus(ea)) END #define AND(A, B) \ { \ (A) &= (B); \ nz = (A) & 0xff; \ } BEGIN(and_imm) READ_IMMEDIATE(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_zp) READ_ZERO_PAGE(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_zp_x) READ_ZERO_PAGE_X(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_abs) READ_ABSOLUTE(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_abs_x) READ_ABSOLUTE_X(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_abs_y) READ_ABSOLUTE_Y(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_ind_x) READ_INDIRECT_X(ea) AND(accumulator, read_bus(ea)) END BEGIN(and_ind_y) READ_INDIRECT_Y(ea) AND(accumulator, read_bus(ea)) END #define ADC(B)\ {\ tmp2 = (B) & 0xff;\ c = nz = tmp1 = (accumulator & 0xff) + tmp2 + ((c & 0x100) >> 8);\ sr = ((~(accumulator ^ tmp2)) & (accumulator ^ tmp1) & 0x80) ? sr | FLAG_V : sr & ~FLAG_V; \ accumulator = tmp1;\ nz &= 0xff;\ } BEGIN(adc_imm) READ_IMMEDIATE(ea) ADC(read_bus(ea)) END BEGIN(adc_zp) READ_ZERO_PAGE(ea) ADC(read_bus(ea)) END BEGIN(adc_zp_x) READ_ZERO_PAGE_X(ea) ADC(read_bus(ea)) END BEGIN(adc_abs) READ_ABSOLUTE(ea) ADC(read_bus(ea)) END BEGIN(adc_abs_x) READ_ABSOLUTE_X(ea) ADC(read_bus(ea)) END BEGIN(adc_abs_y) READ_ABSOLUTE_Y(ea) ADC(read_bus(ea)) END BEGIN(adc_ind_x) READ_INDIRECT_X(ea) ADC(read_bus(ea)) END BEGIN(adc_ind_y) READ_INDIRECT_Y(ea) ADC(read_bus(ea)) END #define SBC(B)\ {\ tmp2 = (B) & 0xff;\ c = nz = tmp1 = (accumulator & 0xff) - tmp2 - (((~c) & 0x100) >> 8);\ c = ~c;\ sr = ((accumulator ^ (B)) & (accumulator ^ tmp1) & 0x80) ? sr | FLAG_V : sr & ~FLAG_V; \ accumulator = tmp1;\ nz &= 0xff;\ } BEGIN(sbc_imm) READ_IMMEDIATE(ea) SBC(read_bus(ea)) END BEGIN(sbc_zp) READ_ZERO_PAGE(ea) SBC(read_bus(ea)) END BEGIN(sbc_zp_x) READ_ZERO_PAGE_X(ea) SBC(read_bus(ea)) END BEGIN(sbc_abs) READ_ABSOLUTE(ea) SBC(read_bus(ea)) END BEGIN(sbc_abs_x) READ_ABSOLUTE_X(ea) SBC(read_bus(ea)) END BEGIN(sbc_abs_y) READ_ABSOLUTE_Y(ea) SBC(read_bus(ea)) END BEGIN(sbc_ind_x) READ_INDIRECT_X(ea) SBC(read_bus(ea)) END BEGIN(sbc_ind_y) READ_INDIRECT_Y(ea) SBC(read_bus(ea)) END #define BIT(B) \ { \ tmp2 = (B);\ sr = get_sr();\ sr = (tmp2 & 0x40) != 0 ? sr | FLAG_V : sr & ~FLAG_V; \ sr = (tmp2 & 0x80) != 0 ? sr | FLAG_N : sr & ~FLAG_N; \ sr = ((accumulator & 0xff) & tmp2) == 0 ? sr | FLAG_Z : sr & ~FLAG_Z; \ set_sr(sr);\ } BEGIN(bit_zp) READ_ZERO_PAGE(ea) BIT(read_page(ea)) END BEGIN(bit_abs) READ_ABSOLUTE(ea) BIT(read_page(ea)) END BEGIN(inc_zp) READ_ZERO_PAGE(ea) nz = (read_page(ea) + 1) & 0xff; write_page(ea, nz); END BEGIN(inc_zp_x) READ_ZERO_PAGE_X(ea) nz = (read_page(ea) + 1) & 0xff; write_page(ea, nz); END BEGIN(inc_abs) READ_ABSOLUTE(ea) nz = (read_bus(ea) + 1) & 0xff; write_bus(ea, nz); END BEGIN(inc_abs_x) READ_ABSOLUTE_X(ea) nz = (read_bus(ea) + 1) & 0xff; write_bus(ea, nz); END BEGIN(dec_zp) READ_ZERO_PAGE(ea) nz = (read_page(ea) - 1) & 0xff; write_page(ea, nz); END BEGIN(dec_zp_x) READ_ZERO_PAGE_X(ea) nz = (read_page(ea) - 1) & 0xff; write_page(ea, nz); END BEGIN(dec_abs) READ_ABSOLUTE(ea) nz = (read_bus(ea) - 1) & 0xff; write_bus(ea, nz); END BEGIN(dec_abs_x) READ_ABSOLUTE_X(ea) nz = (read_bus(ea) - 1) & 0xff; write_bus(ea, nz); END #define ASL(A) \ {\ (A) = nz = c = (((A) & 0xff) << 1);\ nz &= 0xff;\ } BEGIN(asl_a) ASL(accumulator) CYCLES(2) END BEGIN(asl_zp) READ_ZERO_PAGE(ea) tmp1 = read_page(ea); ASL(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(asl_zp_x) READ_ZERO_PAGE_X(ea) tmp1 = read_page(ea); ASL(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(asl_abs) READ_ABSOLUTE(ea) tmp1 = read_bus(ea); ASL(tmp1) write_bus(ea, tmp1); CYCLES(2) END BEGIN(asl_abs_x) READ_ABSOLUTE_X(ea) tmp1 = read_bus(ea); ASL(tmp1) write_bus(ea, tmp1); CYCLES(2) END #define LSR(A)\ {\ nz = ((A) & 0xff);\ c = nz << 8;\ nz = (A) = nz >> 1;\ } BEGIN(lsr_a) LSR(accumulator) CYCLES(2) END BEGIN(lsr_zp) READ_ZERO_PAGE(ea) tmp1 = read_page(ea); LSR(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(lsr_zp_x) READ_ZERO_PAGE_X(ea) tmp1 = read_page(ea); LSR(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(lsr_abs) READ_ABSOLUTE(ea) tmp1 = read_bus(ea); LSR(tmp1) write_bus(ea, tmp1); CYCLES(2) END BEGIN(lsr_abs_x) READ_ABSOLUTE_X(ea) tmp1 = read_bus(ea); LSR(tmp1) write_bus(ea, tmp1); CYCLES(2) END #define ROL(A) \ {\ (A) = nz = c = (((A) & 0xff) << 1) | ((c & 0x100) >> 8);\ nz &= 0xff;\ } BEGIN(rol_a) ROL(accumulator) CYCLES(2) END BEGIN(rol_zp) READ_ZERO_PAGE(ea) tmp1 = read_page(ea); ROL(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(rol_zp_x) READ_ZERO_PAGE_X(ea) tmp1 = read_page(ea); ROL(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(rol_abs) READ_ABSOLUTE(ea) tmp1 = read_bus(ea); ROL(tmp1) write_bus(ea, tmp1); CYCLES(2) END BEGIN(rol_abs_x) READ_ABSOLUTE_X(ea) tmp1 = read_bus(ea); ROL(tmp1) write_bus(ea, tmp1); CYCLES(2) END #define ROR(A)\ {\ nz = ((A) & 0xff) | (c & 0x100);\ c = nz << 8; \ nz = (A) = nz >> 1;\ } BEGIN(ror_a) ROR(accumulator) CYCLES(2) END BEGIN(ror_zp) READ_ZERO_PAGE(ea) tmp1 = read_page(ea); ROR(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(ror_zp_x) READ_ZERO_PAGE_X(ea) tmp1 = read_page(ea); ROR(tmp1) write_page(ea, tmp1); CYCLES(2) END BEGIN(ror_abs) READ_ABSOLUTE(ea) tmp1 = read_bus(ea); ROR(tmp1) write_bus(ea, tmp1); CYCLES(2) END BEGIN(ror_abs_x) READ_ABSOLUTE_X(ea) tmp1 = read_bus(ea); ROR(tmp1) write_bus(ea, tmp1); CYCLES(2) END