|
|
|
@@ -926,17 +926,62 @@ static void e6502_nmi(e6502_Core* core) { |
|
|
|
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\n", last_pc, opcode); |
|
|
|
#endif |
|
|
|
core->cycle = -1; |
|
|
|
|
|
|
|
} 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_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 i_count = 0; |
|
|
|
uint64_t start = (instructions ? i_count : core->cycle); |
|
|
|
uint64_t end = start + remaining; |
|
|
|
int count = 0; |
|
|
|
int last_pc = -1; |
|
|
|
while ((instructions ? i_count : core->cycle) < end) { |
|
|
|
(void)last_pc; |
|
|
|
while (count < remaining) { |
|
|
|
#ifdef E6502_HCF |
|
|
|
if (core->registers.PC == last_pc) { |
|
|
|
// Trapped. |
|
|
|
@@ -945,51 +990,20 @@ int e6502_run(e6502_Core* core, |
|
|
|
} |
|
|
|
#endif |
|
|
|
last_pc = core->registers.PC; |
|
|
|
(void)last_pc; |
|
|
|
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\n", last_pc, opcode); |
|
|
|
#endif |
|
|
|
status = -1; |
|
|
|
int cpu_cycles = e6502_step(core); |
|
|
|
if (cpu_cycles <= 0) { |
|
|
|
status = cpu_cycles; |
|
|
|
break; |
|
|
|
} 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_fprintf_instr(stdout, opcode, (uint8_t*)&val); |
|
|
|
fputc('\n', stdout); |
|
|
|
#endif |
|
|
|
instr->operator(core, adr); |
|
|
|
core->cycle += instr->cycles; |
|
|
|
i_count++; |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
count += (instructions ? 1 : cpu_cycles); |
|
|
|
} |
|
|
|
if (run) { |
|
|
|
*run = (instructions ? i_count : core->cycle) - start; |
|
|
|
*run = count; |
|
|
|
} |
|
|
|
return status; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef E6502_POLL_MEM |
|
|
|
void e6502_init(e6502_Core* core) { /* nuthin' */ } |
|
|
|
#else |
|
|
|
|