|
- #include "e6502.h"
-
- #ifdef E6502_DEBUG
- #include <stdio.h>
- #include "opcodes.h"
- #endif
-
- // Instruction Addressing
-
- #ifdef E6502_POLL_MEM
-
- typedef uint8_t* e6502_Address;
-
- static inline e6502_Address e6502_mem_adr(e6502_Core* core,
- e6502_Mem_Addr adr) {
- return &core->memory[adr];
- }
-
- static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core,
- e6502_Address adr) {
- return (adr - core->memory);
- }
-
- static inline uint8_t e6502_adr_r8(e6502_Core* core,
- e6502_Address adr) {
- return adr[0];
- }
-
- static inline uint8_t e6502_adr_r16(e6502_Core* core,
- e6502_Address adr) {
- return (adr[0] | ((uint16_t)adr[1] << 8));
- }
-
- static inline void e6502_adr_w8(e6502_Core* core,
- e6502_Address adr,
- uint8_t val) {
- adr[0] = val;
- }
-
- static inline void e6502_adr_w16(e6502_Core* core,
- e6502_Address adr,
- uint16_t val) {
- adr[0] = val;
- adr[1] = val >> 8;
- }
-
- #else // !E6502_POLL_MEM
-
- typedef uint16_t e6502_Address;
-
- static inline e6502_Address e6502_mem_adr(e6502_Core* core,
- e6502_Mem_Addr adr) {
- return adr;
- }
-
- static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core,
- e6502_Address adr) {
- return adr;
- }
-
- static inline uint8_t e6502_adr_r8(e6502_Core* core,
- e6502_Address adr) {
- return e6502_r8(core, adr);
- }
-
- static inline void e6502_adr_w8(e6502_Core* core,
- e6502_Address adr,
- uint8_t val) {
- e6502_w8(core, adr, val);
- }
-
- #endif // !E6502_POLL_MEM
-
-
- // Read values after opcodes
-
- static inline uint8_t arg8(e6502_Core* core) {
- return e6502_r8(core, core->registers.PC++);
- }
-
- static inline uint16_t arg16(e6502_Core* core) {
- return (arg8(core) | ((uint16_t)arg8(core) << 8));
- }
-
-
- // Interpret opcode values
-
- static inline e6502_Address adr_imp(e6502_Core* core) {
- return 0;
- }
-
- static inline e6502_Address adr_acc(e6502_Core* core) {
- return 0;
- }
-
- static inline e6502_Address adr_ind(e6502_Core* core) {
- return e6502_mem_adr(core, e6502_r16(core, arg16(core)));
- }
-
- static inline e6502_Address adr_ind_x(e6502_Core* core) {
- return e6502_mem_adr(core, e6502_r16(
- core,
- (uint8_t)(core->registers.X + arg8(core))
- ));
- }
-
- static inline e6502_Address adr_ind_y(e6502_Core* core) {
- uint16_t zp_adr = e6502_r16(core, arg8(core));
- uint8_t old_page = zp_adr >> 8;
- uint16_t new_adr = core->registers.Y + zp_adr;
- if (new_adr >> 8 != old_page) core->cycle++;
- return e6502_mem_adr(core, new_adr);
- }
-
- static inline e6502_Address adr_abs_i(e6502_Core* core,
- uint8_t i) {
- uint16_t abs_adr = arg16(core);
- uint8_t old_page = abs_adr >> 8;
- uint16_t new_adr = i + abs_adr;
- if (new_adr >> 8 != old_page) core->cycle++;
- return e6502_mem_adr(core, new_adr);
- }
-
- static inline e6502_Address adr_abs_x(e6502_Core* core) {
- return adr_abs_i(core, core->registers.X);
- }
-
- static inline e6502_Address adr_abs_y(e6502_Core* core) {
- return adr_abs_i(core, core->registers.Y);
- }
-
- static inline e6502_Address adr_zp(e6502_Core* core) {
- return e6502_mem_adr(core, arg8(core));
- }
-
- static inline e6502_Address adr_zp_x(e6502_Core* core) {
- return e6502_mem_adr(
- core, (uint8_t)(arg8(core) + core->registers.X)
- );
- }
-
- static inline e6502_Address adr_zp_y(e6502_Core* core) {
- return e6502_mem_adr(
- core, (uint8_t)(arg8(core) + core->registers.Y)
- );
- }
-
- static inline e6502_Address adr_abs(e6502_Core* core) {
- return e6502_mem_adr(core, arg16(core));
- }
-
- static inline e6502_Address adr_imm(e6502_Core* core) {
- return e6502_mem_adr(core, core->registers.PC++);
- }
-
- static inline e6502_Address adr_rel(e6502_Core* core) {
- return e6502_mem_adr(
- core, (int8_t)arg8(core) + core->registers.PC
- );
- }
-
-
- // Instructions
-
- static inline void nop(e6502_Core* core, e6502_Address adr) {
- // NOP
- }
-
- static inline void brk(e6502_Core *core, e6502_Address adr) {
- e6502_push16(core, core->registers.PC + 1);
- e6502_push8(core, core->registers.P |
- e6502_Status_1 |
- e6502_Status_B);
- core->registers.P |= e6502_Status_I;
- core->registers.PC = e6502_r16(core, e6502_IRQ_Vec);
- }
-
- static inline void rti(e6502_Core *core, e6502_Address adr) {
- core->registers.P = e6502_pop8(core) |
- e6502_Status_1 |
- e6502_Status_B;
- core->registers.PC = e6502_pop16(core);
- }
-
- static inline void ora(e6502_Core *core, e6502_Address adr) {
- core->registers.A |= e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (core->registers.A & e6502_Status_N);
- if (!core->registers.A) core->registers.P |= e6502_Status_Z;
- }
-
- static inline void eor(e6502_Core *core, e6502_Address adr) {
- core->registers.A ^= e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (core->registers.A & e6502_Status_N);
- if (!core->registers.A) core->registers.P |= e6502_Status_Z;
- }
-
- static inline void asl(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- if (val & 0x80) core->registers.P |= e6502_Status_C;
- val <<= 1;
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void asl_a(e6502_Core *core, e6502_Address adr) {
- uint8_t val = core->registers.A;
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- if (val & 0x80) core->registers.P |= e6502_Status_C;
- val <<= 1;
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.A = val;
- }
-
- static inline void lsr(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= (val & e6502_Status_C);
- val >>= 1;
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void lsr_a(e6502_Core *core, e6502_Address adr) {
- uint8_t val = core->registers.A;
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= (val & e6502_Status_C);
- val >>= 1;
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.A = val;
- }
-
- static inline void rol(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr);
- uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0;
- val <<= 1;
- val |= (core->registers.P & e6502_Status_C);
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= new_c;
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (val & e6502_Status_N);
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void rol_a(e6502_Core *core, e6502_Address adr) {
- uint8_t val = core->registers.A;
- uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0;
- val <<= 1;
- val |= (core->registers.P & e6502_Status_C);
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= new_c;
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (val & e6502_Status_N);
- core->registers.A = val;
- }
-
- static inline void ror(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr);
- uint8_t new_c = (val & e6502_Status_C);
- val >>= 1;
- if (core->registers.P & e6502_Status_C) val |= e6502_Status_N;
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= new_c;
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (val & e6502_Status_N);
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void ror_a(e6502_Core *core, e6502_Address adr) {
- uint8_t val = core->registers.A;
- uint8_t new_c = (val & e6502_Status_C);
- val >>= 1;
- if (core->registers.P & e6502_Status_C) val |= e6502_Status_N;
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- core->registers.P |= new_c;
- if (!val) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (val & e6502_Status_N);
- core->registers.A = val;
- }
-
- static inline void pha(e6502_Core *core, e6502_Address adr) {
- e6502_push8(core, core->registers.A);
- }
-
- static inline void php(e6502_Core *core, e6502_Address adr) {
- e6502_push8(core, core->registers.P |
- e6502_Status_1 |
- e6502_Status_B);
- }
-
- static inline void pla(e6502_Core *core, e6502_Address adr) {
- core->registers.A = e6502_pop8(core);
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- if (!core->registers.A) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (core->registers.A & e6502_Status_N);
- }
-
- static inline void plp(e6502_Core *core, e6502_Address adr) {
- core->registers.P = (e6502_pop8(core) |
- e6502_Status_1 |
- e6502_Status_B);
- }
-
- static inline void b(e6502_Core *core, e6502_Address adr) {
- uint8_t old_page = core->registers.PC >> 8;
- uint16_t new_addr = e6502_adr_mem(core, adr);
- if (old_page != (new_addr >> 8)) core->cycle++;
- core->registers.PC = new_addr;
- core->cycle++;
- }
-
- static inline void bpl(e6502_Core *core, e6502_Address adr) {
- if (!(core->registers.P & e6502_Status_N)) {
- b(core, adr);
- }
- }
-
- static inline void bmi(e6502_Core *core, e6502_Address adr) {
- if (core->registers.P & e6502_Status_N) {
- b(core, adr);
- }
- }
-
- static inline void bcc(e6502_Core *core, e6502_Address adr) {
- if (!(core->registers.P & e6502_Status_C)) {
- b(core, adr);
- }
- }
-
- static inline void bcs(e6502_Core *core, e6502_Address adr) {
- if (core->registers.P & e6502_Status_C) {
- b(core, adr);
- }
- }
-
- static inline void bvc(e6502_Core *core, e6502_Address adr) {
- if (!(core->registers.P & e6502_Status_V)) {
- b(core, adr);
- }
- }
-
- static inline void bvs(e6502_Core *core, e6502_Address adr) {
- if (core->registers.P & e6502_Status_V) {
- b(core, adr);
- }
- }
-
- static inline void bne(e6502_Core *core, e6502_Address adr) {
- if (!(core->registers.P & e6502_Status_Z)) {
- b(core, adr);
- }
- }
-
- static inline void beq(e6502_Core *core, e6502_Address adr) {
- if (core->registers.P & e6502_Status_Z) {
- b(core, adr);
- }
- }
-
- static inline void clc(e6502_Core *core, e6502_Address adr) {
- core->registers.P &= ~e6502_Status_C;
- }
-
- static inline void cli(e6502_Core *core, e6502_Address adr) {
- core->registers.P &= ~e6502_Status_I;
- }
-
- static inline void cld(e6502_Core *core, e6502_Address adr) {
- core->registers.P &= ~e6502_Status_D;
- }
-
- static inline void clv(e6502_Core *core, e6502_Address adr) {
- core->registers.P &= ~e6502_Status_V;
- }
-
- static inline void sec(e6502_Core *core, e6502_Address adr) {
- core->registers.P |= e6502_Status_C;
- }
-
- static inline void sei(e6502_Core *core, e6502_Address adr) {
- core->registers.P |= e6502_Status_I;
- }
-
- static inline void sed(e6502_Core *core, e6502_Address adr) {
- core->registers.P |= e6502_Status_D;
- }
-
- static inline void jsr(e6502_Core *core, e6502_Address adr) {
- e6502_push16(core, core->registers.PC - 1);
- core->registers.PC = e6502_adr_mem(core, adr);
- }
-
- static inline void jmp(e6502_Core *core, e6502_Address adr) {
- core->registers.PC = e6502_adr_mem(core, adr);
- }
-
- static inline void rts(e6502_Core *core, e6502_Address adr) {
- core->registers.PC = e6502_pop16(core) + 1;
- }
-
- static inline void bit(e6502_Core *core, e6502_Address adr) {
- uint8_t val = e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_Z |
- e6502_Status_V |
- e6502_Status_N);
- core->registers.P |= (val & (e6502_Status_V |
- e6502_Status_N));
- if (!(val & core->registers.A)) {
- core->registers.P |= e6502_Status_Z;
- }
- }
-
- static inline void cmp(e6502_Core *core,
- e6502_Address adr,
- uint8_t minuend) {
- uint8_t val = e6502_adr_r8(core, adr);
- uint8_t diff = minuend - val;
- core->registers.P &= ~(e6502_Status_C |
- e6502_Status_Z |
- e6502_Status_N);
- if (minuend >= val) core->registers.P |= e6502_Status_C;
- if (diff == 0) core->registers.P |= e6502_Status_Z;
- core->registers.P |= (diff & e6502_Status_N);
- }
-
- static inline void cpa(e6502_Core *core, e6502_Address adr) {
- cmp(core, adr, core->registers.A);
- }
-
- static inline void cpx(e6502_Core *core, e6502_Address adr) {
- cmp(core, adr, core->registers.X);
- }
-
- static inline void cpy(e6502_Core *core, e6502_Address adr) {
- cmp(core, adr, core->registers.Y);
- }
-
- static inline void and(e6502_Core *core, e6502_Address adr) {
- core->registers.A &= e6502_adr_r8(core, adr);
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (core->registers.A & e6502_Status_N);
- if (!core->registers.A) core->registers.P |= e6502_Status_Z;
- }
-
- static inline void adc(e6502_Core *core, e6502_Address adr) {
- uint8_t addend = e6502_adr_r8(core, adr);
- uint32_t sum = core->registers.A +
- addend +
- (core->registers.P & e6502_Status_C);
- core->registers.P &= ~(e6502_Status_C | e6502_Status_Z |
- e6502_Status_V | e6502_Status_N);
- if (sum > 0xFF) core->registers.P |= e6502_Status_C;
- if (!(uint8_t)sum) core->registers.P |= e6502_Status_Z;
- if ( (addend & 0x80) == (core->registers.A & 0x80) &&
- (sum & 0x80) != (addend & 0x80)) {
- core->registers.P |= e6502_Status_V;
- }
- core->registers.P |= (sum & e6502_Status_N);
- core->registers.A = sum;
- }
-
- static inline void sbc(e6502_Core *core, e6502_Address adr) {
- uint8_t addend = e6502_adr_r8(core, adr);
- uint32_t sum = core->registers.A -
- addend -
- (1 - (core->registers.P & e6502_Status_C));
- core->registers.P &= ~(e6502_Status_C | e6502_Status_Z |
- e6502_Status_V | e6502_Status_N);
- if (sum < 0x100) core->registers.P |= e6502_Status_C;
- if (!(uint8_t)sum) core->registers.P |= e6502_Status_Z;
- if ( (sum & 0x80) != (core->registers.A & 0x80) &&
- (addend & 0x80) != (core->registers.A & 0x80)) {
- core->registers.P |= e6502_Status_V;
- }
- core->registers.P |= (sum & e6502_Status_N);
- core->registers.A = sum;
- }
-
- static inline void inc(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr);
- e6502_adr_w8(core, adr, val);
- val += 1;
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void ini(e6502_Core *core, uint8_t* reg) {
- uint8_t val = *reg + 1;
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- *reg = val;
- }
-
- static inline void inx(e6502_Core *core, e6502_Address adr) {
- ini(core, &core->registers.X);
- }
-
- static inline void iny(e6502_Core *core, e6502_Address adr) {
- ini(core, &core->registers.Y);
- }
-
- static inline void dec(e6502_Core *core, e6502_Address adr) {
- // TODO: Emulate double-read or double-write
- uint8_t val = e6502_adr_r8(core, adr) - 1;
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- e6502_adr_w8(core, adr, val);
- }
-
- static inline void dei(e6502_Core *core, uint8_t* reg) {
- uint8_t val = *reg - 1;
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- *reg = val;
- }
-
- static inline void dex(e6502_Core *core, e6502_Address adr) {
- return dei(core, &core->registers.X);
- }
-
- static inline void dey(e6502_Core *core, e6502_Address adr) {
- return dei(core, &core->registers.Y);
- }
-
- static inline void sta(e6502_Core *core, e6502_Address adr) {
- e6502_adr_w8(core, adr, core->registers.A);
- }
-
- static inline void stx(e6502_Core *core, e6502_Address adr) {
- e6502_adr_w8(core, adr, core->registers.X);
- }
-
- static inline void sty(e6502_Core *core, e6502_Address adr) {
- e6502_adr_w8(core, adr, core->registers.Y);
- }
-
- static inline void t(e6502_Core *core,
- uint8_t* reg,
- uint8_t val) {
- core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
- core->registers.P |= (val & e6502_Status_N);
- if (!val) core->registers.P |= e6502_Status_Z;
- *reg = val;
- }
-
- static inline void tax(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.X, core->registers.A);
- }
-
- static inline void tay(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.Y, core->registers.A);
- }
-
- static inline void txs(e6502_Core *core, e6502_Address adr) {
- core->registers.S = core->registers.X;
- }
-
- static inline void txa(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.A, core->registers.X);
- }
-
- static inline void tya(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.A, core->registers.Y);
- }
-
- static inline void tsx(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.X, core->registers.S);
- }
-
- static inline void lda(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.A, e6502_adr_r8(core, adr));
- }
-
- static inline void ldx(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.X, e6502_adr_r8(core, adr));
- }
-
- static inline void ldy(e6502_Core *core, e6502_Address adr) {
- t(core, &core->registers.Y, e6502_adr_r8(core, adr));
- }
-
-
- typedef struct {
- void(*operator)(e6502_Core*, e6502_Address);
- e6502_Address(*address)(e6502_Core*);
- uint16_t cycles;
- } e6502_Instruction;
-
- static const e6502_Instruction e6502_instructions[256] = {
- // 0x00
- [0b00000000] = {brk, adr_imp, 7},
-
- [0b00000001] = {ora, adr_ind_x, 6},
- [0b00000101] = {ora, adr_zp, 3},
- [0b00001001] = {ora, adr_imm, 2},
- [0b00001101] = {ora, adr_abs, 4},
-
- [0b00000110] = {asl, adr_zp, 5},
- [0b00001010] = {asl_a, adr_acc, 2},
- [0b00001110] = {asl, adr_abs, 6},
-
- [0b00001000] = {php, adr_imp, 3},
-
- // 0x10
- [0b00010000] = {bpl, adr_rel, 2},
-
- [0b00010001] = {ora, adr_ind_y, 5},
- [0b00010101] = {ora, adr_zp_x, 4},
- [0b00011001] = {ora, adr_abs_y, 4},
- [0b00011101] = {ora, adr_abs_x, 4},
-
- [0b00011000] = {clc, adr_imp, 2},
-
- [0b00010110] = {asl, adr_zp_x, 6},
- [0b00011110] = {asl, adr_abs_x, 7},
-
- // 0x20
- [0b00100000] = {jsr, adr_abs, 6},
-
- [0b00100100] = {bit, adr_zp, 3},
- [0b00101100] = {bit, adr_abs, 4},
-
- [0b00100001] = {and, adr_ind_x, 6},
- [0b00100101] = {and, adr_zp, 3},
- [0b00101001] = {and, adr_imm, 2},
- [0b00101101] = {and, adr_abs, 4},
-
- [0b00100110] = {rol, adr_zp, 5},
- [0b00101010] = {rol_a, adr_acc, 2},
- [0b00101110] = {rol, adr_abs, 6},
-
- [0b00101000] = {plp, adr_imp, 4},
-
- // 0x30
- [0b00110000] = {bmi, adr_rel, 2},
-
- [0b00110001] = {and, adr_ind_y, 5},
- [0b00110101] = {and, adr_zp_x, 4},
- [0b00111001] = {and, adr_abs_y, 3},
- [0b00111101] = {and, adr_abs_x, 3},
-
- [0b00110110] = {rol, adr_zp_x, 6},
- [0b00111110] = {rol, adr_abs_x, 7},
-
- [0b00111000] = {sec, adr_imp, 2},
-
- // 0x40
- [0b01000000] = {rti, adr_imp, 6},
-
- [0b01000001] = {eor, adr_ind_x, 6},
- [0b01000101] = {eor, adr_zp, 3},
- [0b01001001] = {eor, adr_imm, 2},
- [0b01001101] = {eor, adr_abs, 4},
-
- [0b01000110] = {lsr, adr_zp, 5},
- [0b01001010] = {lsr_a, adr_acc, 2},
- [0b01001110] = {lsr, adr_abs, 6},
-
- [0b01001000] = {pha, adr_imp, 3},
-
- [0b01001100] = {jmp, adr_abs, 3},
-
- // 0x50
- [0b01010000] = {bvc, adr_rel, 2},
-
- [0b01010001] = {eor, adr_ind_y, 5},
- [0b01010101] = {eor, adr_zp_x, 4},
- [0b01011001] = {eor, adr_abs_y, 4},
- [0b01011101] = {eor, adr_abs_x, 4},
-
- [0b01010110] = {lsr, adr_zp_x, 6},
- [0b01011110] = {lsr, adr_abs_x, 7},
-
- [0b01011000] = {cli, adr_imp, 2},
-
- // 0x60
- [0b01100000] = {rts, adr_imp, 6},
-
- [0b01100001] = {adc, adr_ind_x, 6},
- [0b01100101] = {adc, adr_zp, 3},
- [0b01101001] = {adc, adr_imm, 2},
- [0b01101101] = {adc, adr_abs, 4},
-
- [0b01100110] = {ror, adr_zp, 5},
- [0b01101010] = {ror_a, adr_acc, 2},
- [0b01101110] = {ror, adr_abs, 6},
-
- [0b01101000] = {pla, adr_imp, 4},
-
- [0b01101100] = {jmp, adr_ind, 5},
-
- // 0x70
- [0b01110000] = {bvs, adr_rel, 2},
-
- [0b01110001] = {adc, adr_ind_y, 5},
- [0b01110101] = {adc, adr_zp_x, 4},
- [0b01111001] = {adc, adr_abs_y, 4},
- [0b01111101] = {adc, adr_abs_x, 4},
-
- [0b01110110] = {ror, adr_zp_x, 6},
- [0b01111110] = {ror, adr_abs_x, 7},
-
- [0b01111000] = {sei, adr_imp, 2},
-
- // 0x80
- [0b10000001] = {sta, adr_ind_x, 6},
- [0b10000101] = {sta, adr_zp, 3},
- [0b10001101] = {sta, adr_abs, 4},
-
- [0b10000110] = {stx, adr_zp, 3},
- [0b10001110] = {stx, adr_abs, 4},
-
- [0b10000100] = {sty, adr_zp, 3},
- [0b10001100] = {sty, adr_abs, 4},
-
- [0b10001000] = {dey, adr_imp, 2},
-
- [0b10001010] = {txa, adr_imp, 2},
-
- // 0x90
- [0b10010000] = {bcc, adr_rel, 2},
-
- [0b10010001] = {sta, adr_ind_y, 6},
- [0b10010101] = {sta, adr_zp_x, 4},
- [0b10011001] = {sta, adr_abs_y, 5},
- [0b10011101] = {sta, adr_abs_x, 5},
-
- [0b10010110] = {stx, adr_zp_y, 4},
-
- [0b10010100] = {sty, adr_zp_x, 4},
-
- [0b10011000] = {tya, adr_imp, 2},
- [0b10011010] = {txs, adr_imp, 2},
-
- // 0xA0
- [0b10100001] = {lda, adr_ind_x, 6},
- [0b10100101] = {lda, adr_zp, 3},
- [0b10101001] = {lda, adr_imm, 2},
- [0b10101101] = {lda, adr_abs, 4},
-
- [0b10100010] = {ldx, adr_imm, 2},
- [0b10100110] = {ldx, adr_zp, 3},
- [0b10101110] = {ldx, adr_abs, 4},
-
- [0b10100000] = {ldy, adr_imm, 2},
- [0b10100100] = {ldy, adr_zp, 3},
- [0b10101100] = {ldy, adr_abs, 4},
-
- [0b10101010] = {tax, adr_imp, 2},
- [0b10101000] = {tay, adr_imp, 2},
-
- // 0xB0
- [0b10110000] = {bcs, adr_rel, 2},
-
- [0b10110001] = {lda, adr_ind_y, 5},
- [0b10110101] = {lda, adr_zp_x, 4},
- [0b10111001] = {lda, adr_abs_y, 4},
- [0b10111101] = {lda, adr_abs_x, 4},
-
- [0b10110110] = {ldx, adr_zp_y, 4},
- [0b10111110] = {ldx, adr_abs_y, 4},
-
- [0b10110100] = {ldy, adr_zp_x, 4},
- [0b10111100] = {ldy, adr_abs_x, 4},
-
- [0b10111000] = {clv, adr_imp, 2},
-
- [0b10111010] = {tsx, adr_imp, 2},
-
- // 0xC0
- [0b11000000] = {cpy, adr_imm, 2},
- [0b11000100] = {cpy, adr_zp, 3},
- [0b11001100] = {cpy, adr_abs, 4},
-
- [0b11000001] = {cpa, adr_ind_x, 6},
- [0b11000101] = {cpa, adr_zp, 3},
- [0b11001001] = {cpa, adr_imm, 2},
- [0b11001101] = {cpa, adr_abs, 4},
-
- [0b11001000] = {iny, adr_imp, 2},
-
- [0b11000110] = {dec, adr_zp, 5},
- [0b11001110] = {dec, adr_abs, 6},
- [0b11010110] = {dec, adr_zp_x, 6},
- [0b11011110] = {dec, adr_abs_x, 7},
-
- [0b11001010] = {dex, adr_imp, 2},
-
- // 0xD0
- [0b11010000] = {bne, adr_rel, 2},
-
- [0b11011000] = {cld, adr_imp, 2},
-
- [0b11010001] = {cpa, adr_ind_y, 5},
- [0b11010101] = {cpa, adr_zp_x, 4},
- [0b11011001] = {cpa, adr_abs_y, 4},
- [0b11011101] = {cpa, adr_abs_x, 4},
-
- // 0xE0
- [0b11100000] = {cpx, adr_imm, 2},
- [0b11100100] = {cpx, adr_zp, 3},
- [0b11101100] = {cpx, adr_abs, 4},
-
- [0b11100001] = {sbc, adr_ind_x, 6},
- [0b11100101] = {sbc, adr_zp, 3},
- [0b11101001] = {sbc, adr_imm, 2},
- [0b11101101] = {sbc, adr_abs, 4},
-
- [0b11100110] = {inc, adr_zp, 5},
- [0b11101110] = {inc, adr_abs, 6},
-
- [0b11101000] = {inx, adr_imp, 2},
-
- [0b11101010] = {nop, adr_imp, 2},
-
- // 0xF0
- [0b11110000] = {beq, adr_rel, 2},
-
- [0b11110001] = {sbc, adr_ind_y, 5},
- [0b11110101] = {sbc, adr_zp_x, 4},
- [0b11111001] = {sbc, adr_abs_y, 4},
- [0b11111101] = {sbc, adr_abs_x, 4},
-
- [0b11110110] = {inc, adr_zp_x, 6},
- [0b11111110] = {inc, adr_abs_x, 7},
-
- [0b11111000] = {sed, adr_imp, 2},
-
- };
-
- #ifdef E6502_DEBUG
- int e6502_instr_size(uint8_t opcode) {
- const e6502_Instruction* instr = &e6502_instructions[opcode];
- if ( instr->address == adr_imp ||
- instr->address == adr_acc) {
- return 1;
- } else if ( instr->address == adr_abs ||
- instr->address == adr_abs_x ||
- instr->address == adr_abs_y) {
- return 3;
- } else {
- return 2;
- }
- }
-
- void e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr,
- FILE* file) {
- uint8_t opcode = e6502_r8(core, addr);
- int size = e6502_instr_size(opcode);
- fprintf(file, "$%02x", opcode);
- if (size == 2) {
- fprintf(file, " $%02x", e6502_r8(core, addr + 1));
- } else if (size == 3) {
- fprintf(file, " $%04x", e6502_r16(core, addr + 1));
- }
- // fputc('\n', file);
- }
-
- void e6502_dump_regs(e6502_Core* core, FILE* file) {
- fprintf(file, "S:%02x A:%02x X:%02x Y:%02x P:%02x\n",
- core->registers.S, core->registers.A,
- core->registers.X, core->registers.Y,
- core->registers.P);
- }
- #endif
-
-
- static void e6502_irq(e6502_Core* core) {
- if (!(core->registers.P & e6502_Status_I)) {
- e6502_push16(core, core->registers.PC);
- e6502_push8(core, (core->registers.P & ~e6502_Status_B) |
- e6502_Status_1);
- core->registers.P |= e6502_Status_I;
- core->registers.PC = e6502_r16(core, e6502_IRQ_Vec);
- }
- }
-
- static void e6502_nmi(e6502_Core* core) {
- e6502_push16(core, core->registers.PC);
- e6502_push8(core, (core->registers.P & ~e6502_Status_B) |
- e6502_Status_1);
- core->registers.P |= e6502_Status_I;
- core->registers.PC = e6502_r16(core, e6502_NMI_Vec);
- }
-
- int e6502_step(e6502_Core* core) {
- core->cycle = 0;
-
- #ifdef E6502_DEBUG
- int last_pc = core->registers.PC;
- #endif
-
- uint8_t opcode = e6502_r8(core, core->registers.PC);
- const e6502_Instruction* instr =
- &e6502_instructions[opcode];
- if (!instr->operator) {
- #ifdef E6502_DEBUG
- fprintf(stdout, "$%04x: $%02x -> ILLEGAL\n", last_pc, opcode);
- #endif
- #ifndef E6502_ILLEGAL
- core->cycle = -1;
- #else
- core->registers.PC++;
- core->cycle += 1;
- #endif
-
- } else {
- core->registers.PC++;
- e6502_Address adr = instr->address(core);
- #ifdef E6502_DEBUG
- uint16_t size = core->registers.PC - last_pc;
- uint16_t val = 0;
- if (size > 1) {
- if (size == 2) val = e6502_r8(core, last_pc + 1);
- else val = e6502_r16(core, last_pc + 1);
- }
- e6502_dump_regs(core, stdout);
- fprintf(stdout, "$%04x: ", last_pc);
- e6502_dump_instr(core, last_pc, stdout);
- fputs(" -> ", stdout);
- e6502_fprintf_instr(stdout, opcode, (uint8_t*)&val);
- fputc('\n', stdout);
- #endif
- instr->operator(core, adr);
- core->cycle += instr->cycles;
-
- if ( (core->pins & e6502_Pin_NMI) &&
- !(core->pins & e6502_NMI_Serviced)) {
- core->pins |= e6502_NMI_Serviced;
- e6502_nmi(core);
- } else if ( (core->pins & e6502_Pin_IRQ) &&
- !(core->registers.P & e6502_Status_I)) {
- e6502_irq(core);
- }
- }
-
- return core->cycle;
- }
-
- int e6502_run(e6502_Core* core,
- int remaining,
- int* run,
- int instructions) {
- int status = 0;
- int count = 0;
- int last_pc = -1;
- (void)last_pc;
- while (count < remaining) {
- #ifdef E6502_HCF
- if (core->registers.PC == last_pc) {
- // Trapped.
- status = -2;
- break;
- }
- #endif
- last_pc = core->registers.PC;
- int cpu_cycles = e6502_step(core);
- if (cpu_cycles <= 0) {
- status = cpu_cycles;
- break;
- }
- count += (instructions ? 1 : cpu_cycles);
- }
- if (run) {
- *run = count;
- }
- return status;
- }
-
-
- #ifdef E6502_POLL_MEM
- void e6502_init(e6502_Core* core) { /* nuthin' */ }
- #else
- void e6502_init(e6502_Core* core, e6502_Read read,
- e6502_Write write, void* context) {
- core->bus_read = read;
- core->bus_write = write;
- core->bus_context = context;
- }
- #endif
-
- void e6502_reset(e6502_Core* core) {
- core->registers.PC = e6502_r16(core, e6502_Reset_Vec);
- core->registers.S -= 3;
- core->registers.P |= (e6502_Status_B | e6502_Status_1);
- }
-
- void e6502_set_nmi(e6502_Core* core, int active) {
- if (active) core->pins |= e6502_Pin_NMI;
- else core->pins &= ~(e6502_Pin_NMI | e6502_NMI_Serviced);
- }
-
- void e6502_set_irq(e6502_Core* core, int active) {
- if (active) core->pins |= e6502_Pin_IRQ;
- else core->pins &= ~e6502_Pin_IRQ;
- }
|