forked from rebecca/BSX
226 lines
5.5 KiB
C
226 lines
5.5 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
|
|
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;
|
|
}
|