|
|
|
@@ -1,42 +1,51 @@ |
|
|
|
#include "e6502.h" |
|
|
|
|
|
|
|
#ifdef E6502_DEBUG |
|
|
|
#include <stdio.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
// Instruction Addressing |
|
|
|
|
|
|
|
typedef uint8_t* e6502_Address; |
|
|
|
typedef uint16_t e6502_Address; |
|
|
|
|
|
|
|
static inline e6502_Address e6502_mem_adr(e6502_Core* core, |
|
|
|
e6502_Mem_Addr adr) { |
|
|
|
return &core->memory[adr]; |
|
|
|
// return &core->memory[adr]; |
|
|
|
return adr; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core, |
|
|
|
e6502_Address adr) { |
|
|
|
return (adr - core->memory); |
|
|
|
// return (adr - core->memory); |
|
|
|
return adr; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static inline uint8_t e6502_adr_r8(e6502_Core*, |
|
|
|
static inline uint8_t e6502_adr_r8(e6502_Core* core, |
|
|
|
e6502_Address adr) { |
|
|
|
return *adr; |
|
|
|
// return *adr; |
|
|
|
return e6502_r8(core, adr); |
|
|
|
} |
|
|
|
|
|
|
|
static inline uint8_t e6502_adr_r16(e6502_Core*, |
|
|
|
static inline uint8_t e6502_adr_r16(e6502_Core* core, |
|
|
|
e6502_Address adr) { |
|
|
|
return *(uint16_t*)adr; |
|
|
|
// return *(uint16_t*)adr; |
|
|
|
return e6502_r16(core, adr); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void e6502_adr_w8(e6502_Core*, |
|
|
|
static inline void e6502_adr_w8(e6502_Core* core, |
|
|
|
e6502_Address adr, |
|
|
|
uint8_t val) { |
|
|
|
*adr = val; |
|
|
|
// *adr = val; |
|
|
|
e6502_w8(core, adr, val); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void e6502_adr_w16(e6502_Core*, |
|
|
|
static inline void e6502_adr_w16(e6502_Core* core, |
|
|
|
e6502_Address adr, |
|
|
|
uint16_t val) { |
|
|
|
*(uint16_t*)adr = val; |
|
|
|
// *(uint16_t*)adr = val; |
|
|
|
e6502_w16(core, adr,val); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@@ -53,7 +62,11 @@ static inline uint16_t arg16(e6502_Core* core) { |
|
|
|
|
|
|
|
// Interpret opcode values |
|
|
|
|
|
|
|
static inline e6502_Address adr_none(e6502_Core*) { |
|
|
|
static inline e6502_Address adr_imp(e6502_Core*) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_acc(e6502_Core* core) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
@@ -123,25 +136,6 @@ static inline e6502_Address adr_rel(e6502_Core* core) { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_a (e6502_Core* core) { |
|
|
|
return &core->registers.A; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_x (e6502_Core* core) { |
|
|
|
return &core->registers.X; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_y (e6502_Core* core) { |
|
|
|
return &core->registers.Y; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_s (e6502_Core* core) { |
|
|
|
return &core->registers.P; |
|
|
|
} |
|
|
|
|
|
|
|
static inline e6502_Address adr_reg_sp (e6502_Core* core) { |
|
|
|
return &core->registers.S; |
|
|
|
} |
|
|
|
|
|
|
|
// Instructions |
|
|
|
|
|
|
|
@@ -189,6 +183,18 @@ static inline void asl(e6502_Core *core, e6502_Address adr) { |
|
|
|
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) { |
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
core->registers.P &= ~(e6502_Status_C | |
|
|
|
@@ -201,6 +207,18 @@ static inline void lsr(e6502_Core *core, e6502_Address adr) { |
|
|
|
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) { |
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0; |
|
|
|
@@ -215,6 +233,20 @@ static inline void rol(e6502_Core *core, e6502_Address adr) { |
|
|
|
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) { |
|
|
|
uint8_t val = e6502_adr_r8(core, adr); |
|
|
|
uint8_t new_c = (val & e6502_Status_C); |
|
|
|
@@ -229,6 +261,20 @@ static inline void ror(e6502_Core *core, e6502_Address adr) { |
|
|
|
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); |
|
|
|
} |
|
|
|
@@ -435,6 +481,22 @@ static inline void inc(e6502_Core *core, e6502_Address adr) { |
|
|
|
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) { |
|
|
|
ini(core, &core->registers.X); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void iny(e6502_Core *core, e6502_Address) { |
|
|
|
ini(core, &core->registers.Y); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void dec(e6502_Core *core, e6502_Address adr) { |
|
|
|
uint8_t val = e6502_adr_r8(core, adr) - 1; |
|
|
|
core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
@@ -443,6 +505,22 @@ static inline void dec(e6502_Core *core, e6502_Address adr) { |
|
|
|
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) { |
|
|
|
return dei(core, &core->registers.X); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void dey(e6502_Core *core, e6502_Address) { |
|
|
|
return dei(core, &core->registers.Y); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void sta(e6502_Core *core, e6502_Address adr) { |
|
|
|
e6502_adr_w8(core, adr, core->registers.A); |
|
|
|
} |
|
|
|
@@ -456,32 +534,36 @@ static inline void sty(e6502_Core *core, e6502_Address adr) { |
|
|
|
} |
|
|
|
|
|
|
|
static inline void t(e6502_Core *core, |
|
|
|
e6502_Address adr, |
|
|
|
uint8_t reg) { |
|
|
|
uint8_t* reg, |
|
|
|
uint8_t val) { |
|
|
|
core->registers.P &= ~(e6502_Status_Z | e6502_Status_N); |
|
|
|
core->registers.P |= (reg & e6502_Status_N); |
|
|
|
if (!reg) core->registers.P |= e6502_Status_Z; |
|
|
|
e6502_adr_w8(core, adr, reg); |
|
|
|
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) { |
|
|
|
t(core, &core->registers.X, core->registers.A); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void ta(e6502_Core *core, e6502_Address adr) { |
|
|
|
t(core, adr, core->registers.A); |
|
|
|
static inline void tay(e6502_Core *core, e6502_Address) { |
|
|
|
t(core, &core->registers.Y, core->registers.A); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void txs(e6502_Core *core, e6502_Address adr) { |
|
|
|
static inline void txs(e6502_Core *core, e6502_Address) { |
|
|
|
core->registers.S = core->registers.X; |
|
|
|
} |
|
|
|
|
|
|
|
static inline void txa(e6502_Core *core, e6502_Address adr) { |
|
|
|
static inline void txa(e6502_Core *core, e6502_Address) { |
|
|
|
t(core, &core->registers.A, core->registers.X); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void ty(e6502_Core *core, e6502_Address adr) { |
|
|
|
t(core, adr, core->registers.Y); |
|
|
|
static inline void tya(e6502_Core *core, e6502_Address) { |
|
|
|
t(core, &core->registers.A, core->registers.Y); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void ts(e6502_Core *core, e6502_Address adr) { |
|
|
|
t(core, adr, core->registers.S); |
|
|
|
static inline void tsx(e6502_Core *core, e6502_Address) { |
|
|
|
t(core, &core->registers.X, core->registers.S); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void lda(e6502_Core *core, e6502_Address adr) { |
|
|
|
@@ -503,9 +585,9 @@ typedef struct { |
|
|
|
uint16_t cycles; |
|
|
|
} e6502_Instruction; |
|
|
|
|
|
|
|
static e6502_Instruction e6502_instructions[256] = { |
|
|
|
static const e6502_Instruction e6502_instructions[256] = { |
|
|
|
// 0x00 |
|
|
|
[0b00000000] = {brk, adr_none, 7}, |
|
|
|
[0b00000000] = {brk, adr_imp, 7}, |
|
|
|
|
|
|
|
[0b00000001] = {ora, adr_ind_x, 6}, |
|
|
|
[0b00000101] = {ora, adr_zp, 3}, |
|
|
|
@@ -513,10 +595,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b00001101] = {ora, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b00000110] = {asl, adr_zp, 5}, |
|
|
|
[0b00001010] = {asl, adr_reg_a, 2}, |
|
|
|
[0b00001010] = {asl_a, adr_acc, 2}, |
|
|
|
[0b00001110] = {asl, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b00001000] = {php, adr_none, 3}, |
|
|
|
[0b00001000] = {php, adr_imp, 3}, |
|
|
|
|
|
|
|
// 0x10 |
|
|
|
[0b00010000] = {bpl, adr_rel, 2}, |
|
|
|
@@ -526,7 +608,7 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b00011001] = {ora, adr_abs_y, 4}, |
|
|
|
[0b00011101] = {ora, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b00011000] = {clc, adr_none, 2}, |
|
|
|
[0b00011000] = {clc, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b00010110] = {asl, adr_zp_x, 6}, |
|
|
|
[0b00011110] = {asl, adr_abs_x, 7}, |
|
|
|
@@ -543,10 +625,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b00101101] = {and, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b00100110] = {rol, adr_zp, 5}, |
|
|
|
[0b00101010] = {rol, adr_reg_a, 2}, |
|
|
|
[0b00101010] = {rol_a, adr_acc, 2}, |
|
|
|
[0b00101110] = {rol, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b00101000] = {plp, adr_none, 4}, |
|
|
|
[0b00101000] = {plp, adr_imp, 4}, |
|
|
|
|
|
|
|
// 0x30 |
|
|
|
[0b00110000] = {bmi, adr_rel, 2}, |
|
|
|
@@ -559,10 +641,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b00110110] = {rol, adr_zp_x, 6}, |
|
|
|
[0b00111110] = {rol, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b00111000] = {sec, adr_none, 2}, |
|
|
|
[0b00111000] = {sec, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x40 |
|
|
|
[0b01000000] = {rti, adr_none, 6}, |
|
|
|
[0b01000000] = {rti, adr_imp, 6}, |
|
|
|
|
|
|
|
[0b01000001] = {eor, adr_ind_x, 6}, |
|
|
|
[0b01000101] = {eor, adr_zp, 3}, |
|
|
|
@@ -570,10 +652,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b01001101] = {eor, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b01000110] = {lsr, adr_zp, 5}, |
|
|
|
[0b01001010] = {lsr, adr_reg_a, 2}, |
|
|
|
[0b01001010] = {lsr_a, adr_acc, 2}, |
|
|
|
[0b01001110] = {lsr, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b01001000] = {pha, adr_none, 3}, |
|
|
|
[0b01001000] = {pha, adr_imp, 3}, |
|
|
|
|
|
|
|
[0b01001100] = {jmp, adr_abs, 3}, |
|
|
|
|
|
|
|
@@ -588,10 +670,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b01010110] = {lsr, adr_zp_x, 6}, |
|
|
|
[0b01011110] = {lsr, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b01011000] = {cli, adr_none, 2}, |
|
|
|
[0b01011000] = {cli, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x60 |
|
|
|
[0b01100000] = {rts, adr_none, 6}, |
|
|
|
[0b01100000] = {rts, adr_imp, 6}, |
|
|
|
|
|
|
|
[0b01100001] = {adc, adr_ind_x, 6}, |
|
|
|
[0b01100101] = {adc, adr_zp, 3}, |
|
|
|
@@ -599,10 +681,10 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b01101101] = {adc, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b01100110] = {ror, adr_zp, 5}, |
|
|
|
[0b01101010] = {ror, adr_reg_a, 2}, |
|
|
|
[0b01101010] = {ror_a, adr_acc, 2}, |
|
|
|
[0b01101110] = {ror, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b01101000] = {pla, adr_none, 4}, |
|
|
|
[0b01101000] = {pla, adr_imp, 4}, |
|
|
|
|
|
|
|
[0b01101100] = {jmp, adr_ind, 5}, |
|
|
|
|
|
|
|
@@ -617,7 +699,7 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b01110110] = {ror, adr_zp_x, 6}, |
|
|
|
[0b01111110] = {ror, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b01111000] = {sei, adr_none, 2}, |
|
|
|
[0b01111000] = {sei, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x80 |
|
|
|
[0b10000001] = {sta, adr_ind_x, 6}, |
|
|
|
@@ -630,9 +712,9 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b10000100] = {sty, adr_zp, 3}, |
|
|
|
[0b10001100] = {sty, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10001000] = {dec, adr_reg_y, 2}, |
|
|
|
[0b10001000] = {dey, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b10001010] = {txa, adr_none, 2}, |
|
|
|
[0b10001010] = {txa, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0x90 |
|
|
|
[0b10010000] = {bcc, adr_rel, 2}, |
|
|
|
@@ -646,8 +728,8 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
|
|
|
|
[0b10010100] = {sty, adr_zp_x, 4}, |
|
|
|
|
|
|
|
[0b10011000] = {ty, adr_reg_a, 2}, |
|
|
|
[0b10011010] = {txs, adr_none, 2}, |
|
|
|
[0b10011000] = {tya, adr_imp, 2}, |
|
|
|
[0b10011010] = {txs, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xA0 |
|
|
|
[0b10100001] = {lda, adr_ind_x, 6}, |
|
|
|
@@ -663,8 +745,8 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b10100100] = {ldy, adr_zp, 3}, |
|
|
|
[0b10101100] = {ldy, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b10101010] = {ta, adr_reg_x, 2}, |
|
|
|
[0b10101000] = {ta, adr_reg_y, 2}, |
|
|
|
[0b10101010] = {tax, adr_imp, 2}, |
|
|
|
[0b10101000] = {tay, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xB0 |
|
|
|
[0b10110000] = {bcs, adr_rel, 2}, |
|
|
|
@@ -680,9 +762,9 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b10110100] = {ldy, adr_zp_x, 4}, |
|
|
|
[0b10111100] = {ldy, adr_abs_x, 4}, |
|
|
|
|
|
|
|
[0b10111000] = {clv, adr_none, 2}, |
|
|
|
[0b10111000] = {clv, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b10111010] = {ts, adr_reg_x, 2}, |
|
|
|
[0b10111010] = {tsx, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xC0 |
|
|
|
[0b11000000] = {cpy, adr_imm, 2}, |
|
|
|
@@ -694,19 +776,19 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b11001001] = {cpa, adr_imm, 2}, |
|
|
|
[0b11001101] = {cpa, adr_abs, 4}, |
|
|
|
|
|
|
|
[0b11001000] = {inc, adr_reg_y, 2}, |
|
|
|
[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] = {dec, adr_reg_x, 2}, |
|
|
|
[0b11001010] = {dex, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xD0 |
|
|
|
[0b11010000] = {bne, adr_rel, 2}, |
|
|
|
|
|
|
|
[0b11011000] = {cld, adr_none, 2}, |
|
|
|
[0b11011000] = {cld, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b11010001] = {cpa, adr_ind_y, 5}, |
|
|
|
[0b11010101] = {cpa, adr_zp_x, 4}, |
|
|
|
@@ -726,9 +808,9 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b11100110] = {inc, adr_zp, 5}, |
|
|
|
[0b11101110] = {inc, adr_abs, 6}, |
|
|
|
|
|
|
|
[0b11101000] = {inc, adr_reg_x, 2}, |
|
|
|
[0b11101000] = {inx, adr_imp, 2}, |
|
|
|
|
|
|
|
[0b11101010] = {nop, adr_none, 2}, |
|
|
|
[0b11101010] = {nop, adr_imp, 2}, |
|
|
|
|
|
|
|
// 0xF0 |
|
|
|
[0b11110000] = {beq, adr_rel, 2}, |
|
|
|
@@ -741,18 +823,15 @@ static e6502_Instruction e6502_instructions[256] = { |
|
|
|
[0b11110110] = {inc, adr_zp_x, 6}, |
|
|
|
[0b11111110] = {inc, adr_abs_x, 7}, |
|
|
|
|
|
|
|
[0b11111000] = {sed, adr_none, 2}, |
|
|
|
[0b11111000] = {sed, adr_imp, 2}, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
/* |
|
|
|
int e6502_instr_size(uint8_t opcode) { |
|
|
|
e6502_Instruction* instr = &e6502_instructions[opcode]; |
|
|
|
if ( instr->address == adr_none || |
|
|
|
instr->address == adr_reg_a || |
|
|
|
instr->address == adr_reg_x || |
|
|
|
instr->address == adr_reg_y || |
|
|
|
instr->address == adr_reg_s || |
|
|
|
instr->address == adr_reg_sp) { |
|
|
|
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 || |
|
|
|
@@ -763,7 +842,6 @@ int e6502_instr_size(uint8_t opcode) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr, |
|
|
|
FILE* file) { |
|
|
|
uint8_t opcode = e6502_r8(core, addr); |
|
|
|
@@ -776,24 +854,27 @@ int e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr, |
|
|
|
} |
|
|
|
fputc('\n', file); |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifdef E6502_DEBUG |
|
|
|
int 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 |
|
|
|
|
|
|
|
int e6502_run(e6502_Core* core, |
|
|
|
int remaining, |
|
|
|
int* run, |
|
|
|
int instructions) { |
|
|
|
int status = 0; |
|
|
|
int start = (instructions ? core->instr : core->cycle); |
|
|
|
int i_count = 0; |
|
|
|
int start = (instructions ? i_count : core->cycle); |
|
|
|
int end = start + remaining; |
|
|
|
int last_pc = -1; |
|
|
|
while ((instructions ? core->instr : core->cycle) < end) { |
|
|
|
while ((instructions ? i_count : core->cycle) < end) { |
|
|
|
if (core->registers.PC == last_pc) { |
|
|
|
// Trapped. |
|
|
|
status = -2; |
|
|
|
@@ -801,23 +882,24 @@ int e6502_run(e6502_Core* core, |
|
|
|
} |
|
|
|
last_pc = core->registers.PC; |
|
|
|
uint8_t opcode = e6502_r8(core, core->registers.PC); |
|
|
|
e6502_Instruction* instr = &e6502_instructions[opcode]; |
|
|
|
const e6502_Instruction* instr = |
|
|
|
&e6502_instructions[opcode]; |
|
|
|
if (!instr->operator) { |
|
|
|
/* |
|
|
|
#ifdef E6502_DEBUG |
|
|
|
fprintf(stdout, "$%04x: %02x\n", last_pc, opcode); |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
status = -1; |
|
|
|
break; |
|
|
|
} else { |
|
|
|
core->registers.PC++; |
|
|
|
e6502_Address adr = instr->address(core); |
|
|
|
/* |
|
|
|
#ifdef E6502_DEBUG |
|
|
|
uint16_t size = core->registers.PC - last_pc; |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
instr->operator(core, adr); |
|
|
|
core->cycle += instr->cycles; |
|
|
|
core->instr++; |
|
|
|
/* |
|
|
|
i_count++; |
|
|
|
#ifdef E6502_DEBUG |
|
|
|
fprintf(stdout, "$%04x: $%02x", last_pc, opcode); |
|
|
|
if (size == 2) { |
|
|
|
fprintf(stdout, " $%02x", e6502_r8(core, last_pc + 1)); |
|
|
|
@@ -826,11 +908,11 @@ int e6502_run(e6502_Core* core, |
|
|
|
} |
|
|
|
fputc('\n', stdout); |
|
|
|
e6502_dump_regs(core, stdout); |
|
|
|
*/ |
|
|
|
#endif |
|
|
|
} |
|
|
|
} |
|
|
|
if (run) { |
|
|
|
*run = (instructions ? core->instr : core->cycle) - start; |
|
|
|
*run = (instructions ? i_count : core->cycle) - start; |
|
|
|
} |
|
|
|
return status; |
|
|
|
} |
|
|
|
@@ -840,3 +922,10 @@ int e6502_reset(e6502_Core* core) { |
|
|
|
core->registers.S -= 3; |
|
|
|
core->registers.P |= (e6502_Status_B | e6502_Status_1); |
|
|
|
} |
|
|
|
|
|
|
|
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; |
|
|
|
} |