/* * lib65816/dispatch.c Release 1p1 * See LICENSE for more details. * * Code originally from XGS: Apple IIGS Emulator (dispatch.c) * * Originally written and Copyright (C)1996 by Joshua M. Thompson * Copyright (C) 2006 by Samuel A. Falvo II * * Modified for greater portability and virtual hardware independence. * * Copyright (C) 2024 by Rebecca Buckingham * highly modified to integrate with bsx emulator. */ #define CPU_DISPATCH #include "cpu.h" #include "cpumicro.h" #include "util.h" #include int dispatch_quit = 0; dualw A; /* Accumulator */ dualw D; /* Direct Page Register */ byte P; /* Processor Status Register */ int E; /* Emulation Mode Flag */ dualw S; /* Stack Pointer */ dualw X; /* X Index Register */ dualw Y; /* Y Index Register */ byte DB; /* Data Bank Register */ union { #ifdef WORDS_BIGENDIAN struct { byte Z,PB,H,L; } B; struct { word16 Z,PC; } W; #else struct { byte L,H,PB,Z; } B; struct { word16 PC,Z; } W; #endif word32 A; } PC; duala atmp,opaddr; dualw wtmp,otmp,operand; int a1,a2,a3,a4,o1,o2,o3,o4; void (**cpu_curr_opcode_table)(); extern int cpu_reset,cpu_abort,cpu_nmi,cpu_irq,cpu_stop,cpu_wait,cpu_trace; extern int cpu_irne64,cpu_irqt5; extern int cpu_update_period; extern void (*cpu_opcode_table[1310])(); uint64_t last_update, next_update; #define RESET_OP 256 #define ABORT_OP 257 #define NMI_OP 258 #define IRQ_OP 259 #define IRNE64_OP 260 #define IRQT5_OP 261 void handleSignal(int type) { (**cpu_curr_opcode_table[type])(); } void doUpdate() { E_UPDATE(cpu_cycle_count); last_update = cpu_cycle_count; next_update = last_update + cpu_update_period; } void CPU_init(void) { last_update = 0; next_update = cpu_update_period; cpu_cycle_count = 0; E = 1; F_setM(1); F_setX(1); CPU_modeSwitch(); } void CPU_step(void) { if (cpu_cycle_count >= next_update) doUpdate(); int opcode = M_READ_OPCODE(PC.A); PC.W.PC++; (**cpu_curr_opcode_table[opcode])(); } void CPU_run(void) { while (!dispatch_quit) { if (cpu_trace) CPU_debug(); if (cpu_reset) { handleSignal(RESET_OP); continue; } if (cpu_abort) { handleSignal(ABORT_OP); continue; } if (cpu_nmi) { handleSignal(NMI_OP); continue; } if (cpu_irq) { handleSignal(IRQ_OP); continue; } if (cpu_irne64) { handleSignal(IRNE64_OP); continue; } if (cpu_irqt5) { handleSignal(IRQT5_OP); continue; } if (cpu_wait) { cpu_cycle_count++; continue; } if (cpu_stop) continue; CPU_step(); } } // void old_CPU_run(void) // { // word32 last_update,next_update; // int opcode; // #ifdef LIMIT_INSTRUCTION_COUNT // long instructionCount = 0; // #endif // cpu_cycle_count = 0; // last_update = 0; // next_update = cpu_update_period; // E = 1; // F_setM(1); // F_setX(1); // CPU_modeSwitch(); // dispatch: // // CPUEvent_elapse( cpu_cycle_count ); // // cpu_cycle_count = 0; // if (dispatch_quit) // return; // // TODO remove this. // #ifdef LIMIT_INSTRUCTION_COUNT // instructionCount++; // if (instructionCount > LIMIT_INSTRUCTION_COUNT) // return; // #endif // // #ifdef E_UPDATE // if (cpu_cycle_count >= next_update) goto update; // update_resume: // // #endif // #ifdef DEBUG // if (cpu_trace) goto debug; // debug_resume: // #endif // if (cpu_reset) goto reset; // if (cpu_stop) goto dispatch; // if (cpu_abort) goto abort; // if (cpu_nmi) goto nmi; // if (cpu_irq) goto irq; // if (cpu_irne64) goto irne64; // if (cpu_irqt5) goto irqt5; // irq_return: // if (cpu_wait) { cpu_cycle_count++; goto dispatch; } // opcode = M_READ_OPCODE(PC.A); // PC.W.PC++; // #ifdef OLDCYCLES // cpu_cycle_count += cpu_curr_cycle_table[opcode]; // #endif // (**cpu_curr_opcode_table[opcode])(); // goto dispatch; // /* Special cases. Since these don't happen a lot more often than they */ // /* do happen, accessing them this way means most of the time the */ // /* generated code is _not_ branching. Only during the special cases do */ // /* we take the branch penalty (if there is one). */ // // #ifdef E_UPDATE // update: // E_UPDATE(cpu_cycle_count); // last_update = cpu_cycle_count; // next_update = last_update + cpu_update_period; // goto update_resume; // // #endif // #ifdef DEBUG // debug: // CPU_debug(); // goto debug_resume; // #endif // reset: // (**cpu_curr_opcode_table[256])(); // goto dispatch; // abort: // (**cpu_curr_opcode_table[257])(); // goto dispatch; // nmi: // (**cpu_curr_opcode_table[258])(); // goto dispatch; // irq: // if (P & 0x04) goto irq_return; // (**cpu_curr_opcode_table[259])(); // goto dispatch; // irne64: // if (P & 0x04) goto irq_return; // (**cpu_curr_opcode_table[260])(); // goto dispatch; // irqt5: // if (P & 0x04) goto irq_return; // (**cpu_curr_opcode_table[261])(); // goto dispatch; // } /* Recalculate opcode_offset based on the new processor mode */ void CPU_modeSwitch(void) { int opcode_offset; if (E) { opcode_offset = 1048; } else { if (F_getX) { X.B.H = 0; Y.B.H = 0; } opcode_offset = ((~P >> 4) & 0x03) * 262; } #ifdef OLDCYCLES cpu_curr_cycle_table = cpu_cycle_table + opcode_offset; #endif cpu_curr_opcode_table = cpu_opcode_table + opcode_offset; }