Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 32 additions & 24 deletions src/cpu/cpu650x.c
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,7 @@ void cpu_reset(void)
CPU.irq_pin = 1;
CPU.nmi_pin = 1;
CPU.nmi_trigger = 0;
CPU.exec_pending = 0;

/* Reset takes 8 clock cycles */
CPU.clock_rcycles = 8;
Expand Down Expand Up @@ -1401,32 +1402,15 @@ void cpu_clock(void)
return;
}

/* If some interrupt was triggered, it should wait for current
* instruction to finish in order to jump to server the interrupt.
* NMI has priority over masked interrupt.
/* Complete the instruction decoded on the previous boundary. Its cycle
* window has now passed, so its bus access (read/write) and execution
* is performed here, on the last cycle. This matches the real 6502,
* which performs the memory access on the last cycle rather than the
* first.
*/
if (CPU.nmi_trigger == 1) {
do_nmi();
} else if (CPU.irq_pin == 0 && !CPU.P.flags.I) {
do_irq();
} else {
/* Each instruction takes different amount of clock cycles to be
* executed. However, in this emulation the instruction will be
* executed at once and will do nothing on the remaining cycles.
*/
opcode = sbus_read(CPU.PC++);
addrmode = op_codes[opcode].mode;

/* Fetch operands and decode instruction */
cross = fetch_operand(op_codes[opcode].mode);
CPU.clock_rcycles = op_codes[opcode].clock_cycles;

/* Check if need to add a cycle */
if (cross && op_codes[opcode].add_cycles == 1)
CPU.clock_rcycles++;

/* Execute instruction */
if (CPU.exec_pending) {
op_codes[opcode].instruction();
CPU.exec_pending = 0;
if (cpu_debug_cb != NULL) {
state_info.opcode = opcode;
state_info.opcode_name = op_codes[opcode].name;
Expand All @@ -1441,6 +1425,30 @@ void cpu_clock(void)
fetched_data, fetched_addr);
#endif
}

/* Interrupts are polled at the instruction boundary, after the
* instruction that just finished and before fetching the next one.
* NMI has priority over the maskable interrupt.
*/
if (CPU.nmi_trigger == 1) {
do_nmi();
} else if (CPU.irq_pin == 0 && !CPU.P.flags.I) {
do_irq();
} else {
/* Decode the next instruction and reserve its cycles, but defer
* its execution to the end of the window.
*/
opcode = sbus_read(CPU.PC++);
addrmode = op_codes[opcode].mode;
cross = fetch_operand(op_codes[opcode].mode);
CPU.clock_rcycles = op_codes[opcode].clock_cycles;

/* Check if need to add a cycle */
if (cross && op_codes[opcode].add_cycles == 1)
CPU.clock_rcycles++;

CPU.exec_pending = 1;
}
}

CPU.clock_cycles++;
Expand Down
2 changes: 2 additions & 0 deletions src/cpu/include/cpu650x.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ struct _cpu650x {
uint8_t nmi_pin;
/** NMI signal edge detection */
uint8_t nmi_trigger;
/** Flag to execute decoded instruction */
uint8_t exec_pending;
/** CPU running state */
enum _CPU_STATE state;
};
Expand Down
Loading