#ifndef VBAPI #define VBAPI #endif #include /*********************************** Types ***********************************/ /* Simulation state */ struct VB { /* Game Pak */ struct { uint8_t *ram; /* Save RAM */ uint8_t *rom; /* Program ROM */ uint32_t ramMask; /* Size of SRAM - 1 */ uint32_t romMask; /* Size of ROM - 1 */ } cart; /* CPU */ struct { /* Cache Control Word */ struct { uint8_t ice; /* Instruction Cache Enable */ } chcw; /* Exception Cause Register */ struct { uint16_t eicc; /* Exception/Interrupt Cause Code */ uint16_t fecc; /* Fatal Error Cause Code */ } ecr; /* Program Status Word */ struct { uint8_t ae; /* Address Trap Enable */ uint8_t cy; /* Carry */ uint8_t ep; /* Exception Pending */ uint8_t fiv; /* Floating Invalid */ uint8_t fov; /* Floating Overflow */ uint8_t fpr; /* Floading Precision */ uint8_t fro; /* Floating Reserved Operand */ uint8_t fud; /* Floading Underflow */ uint8_t fzd; /* Floating Zero Divide */ uint8_t i; /* Interrupt Level */ uint8_t id; /* Interrupt Disable */ uint8_t np; /* NMI Pending */ uint8_t ov; /* Overflow */ uint8_t s; /* Sign */ uint8_t z; /* Zero */ } psw; /* Other registers */ uint32_t adtre; /* Address Trap Register for Execution */ uint32_t eipc; /* Exception/Interrupt PC */ uint32_t eipsw; /* Exception/Interrupt PSW */ uint32_t fepc; /* Fatal Error PC */ uint32_t fepsw; /* Fatal Error PSW */ uint32_t pc; /* Program Counter */ int32_t program[32]; /* Program registers */ uint32_t sr29; /* System register 29 */ uint32_t sr31; /* System register 31 */ /* Working data */ union { struct { uint32_t address; int32_t value; } data; } aux; /* Other state */ uint32_t clocks; /* Master clocks to wait */ uint16_t code[2]; /* Instruction code units */ uint16_t exception; /* Exception cause code */ uint16_t irq; /* Interrupt request lines */ int length; /* Instruction code length */ uint32_t nextPC; /* Address of next instruction */ int operation; /* Current operation ID */ int step; /* Operation sub-task ID */ } cpu; /* Other system state */ uint8_t wram[0x10000]; /* System RAM */ /* Application data */ vbOnExecute onExecute; /* CPU instruction execute */ vbOnFetch onFetch; /* CPU instruction fetch */ vbOnRead onRead; /* CPU instruction read */ vbOnWrite onWrite; /* CPU instruction write */ void *tag; /* User data */ }; /***************************** Library Functions *****************************/ /* Sign-extend an integer of variable width */ static int32_t SignExtend(int32_t value, int32_t bits) { #ifndef VB_SIGNED_PROPAGATE value &= ~((uint32_t) 0xFFFFFFFF << bits); bits = (int32_t) 1 << (bits - (int32_t) 1); return (value ^ bits) - bits; #else return value << (32 - bits) >> (32 - bits); #endif } /******************************** Sub-Modules ********************************/ #include "bus.c" #include "cpu.c" /***************************** Library Functions *****************************/ /* Process a simulation for a given number of clocks */ static int sysEmulate(VB *sim, uint32_t clocks) { return cpuEmulate(sim, clocks) ; } /* Determine how many clocks are guaranteed to process */ static uint32_t sysUntil(VB *sim, uint32_t clocks) { clocks = cpuUntil(sim, clocks); return clocks; } /******************************* API Commands ********************************/ /* Process one simulation */ VBAPI int vbEmulate(VB *sim, uint32_t *clocks) { int brk; /* A callback requested a break */ uint32_t until; /* Clocks guaranteed to process */ while (*clocks != 0) { until = sysUntil(sim, *clocks); brk = sysEmulate(sim, until); *clocks -= until; if (brk) return brk; /* TODO: return 1 */ } return 0; } /* Process multiple simulations */ VBAPI int vbEmulateEx(VB **sims, int count, uint32_t *clocks) { int brk; /* A callback requested a break */ uint32_t until; /* Clocks guaranteed to process */ int x; /* Iterator */ while (*clocks != 0) { until = *clocks; for (x = count - 1; x >= 0; x--) until = sysUntil(sims[x], until); brk = 0; for (x = count - 1; x >= 0; x--) brk |= sysEmulate(sims[x], until); *clocks -= until; if (brk) return brk; /* TODO: return 1 */ } return 0; } /* Retrieve the game pack RAM buffer */ VBAPI void* vbGetCartRAM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.ram == NULL ? 0 : sim->cart.ramMask + 1; return sim->cart.ram; } /* Retrieve the game pack ROM buffer */ VBAPI void* vbGetCartROM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.rom == NULL ? 0 : sim->cart.romMask + 1; return sim->cart.rom; } /* Retrieve the execute callback handle */ VBAPI vbOnExecute vbGetExecuteCallback(VB *sim) { return sim->onExecute; } /* Retrieve the fetch callback handle */ VBAPI vbOnFetch vbGetFetchCallback(VB *sim) { return sim->onFetch; } /* Retrieve the value of the program counter */ VBAPI uint32_t vbGetProgramCounter(VB *sim) { return sim->cpu.pc; } /* Retrieve the value in a program register */ VBAPI int32_t vbGetProgramRegister(VB *sim, int index) { return index < 1 || index > 31 ? 0 : sim->cpu.program[index]; } /* Retrieve the read callback handle */ VBAPI vbOnRead vbGetReadCallback(VB *sim) { return sim->onRead; } /* Retrieve the value in a system register */ VBAPI uint32_t vbGetSystemRegister(VB *sim, int index) { return index < 0 || index > 31 ? 0 : cpuGetSystemRegister(sim, index); } /* Retrieve a simulation's userdata pointer */ VBAPI void* vbGetUserData(VB *sim) { return sim->tag; } /* Retrieve the write callback handle */ VBAPI vbOnWrite vbGetWriteCallback(VB *sim) { return sim->onWrite; } /* Initialize a simulation instance */ VBAPI VB* vbInit(VB *sim) { sim->cart.ram = NULL; sim->cart.rom = NULL; sim->onExecute = NULL; sim->onFetch = NULL; sim->onRead = NULL; sim->onWrite = NULL; vbReset(sim); return sim; } /* Read a value from the memory bus */ VBAPI int32_t vbRead(VB *sim, uint32_t address, int type) { int32_t value; if (type < 0 || type > 4) return 0; busRead(sim, address, type, &value); return value; } /* Simulate a hardware reset */ VBAPI VB* vbReset(VB *sim) { uint32_t x; /* Iterator */ /* WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) sim->wram[x] = 0x00; /* CPU (normal) */ sim->cpu.exception = 0; sim->cpu.irq = 0; sim->cpu.pc = 0xFFFFFFF0; cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1); cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1); /* CPU (extra, hardware does not do this) */ sim->cpu.adtre = 0x00000000; sim->cpu.eipc = 0x00000000; sim->cpu.eipsw = 0x00000000; sim->cpu.fepc = 0x00000000; sim->cpu.fepsw = 0x00000000; sim->cpu.sr29 = 0x00000000; sim->cpu.sr31 = 0x00000000; cpuSetSystemRegister(sim, VB_CHCW, 0x00000000, 1); for (x = 0; x < 32; x++) sim->cpu.program[x] = 0x00000000; /* CPU (other) */ sim->cpu.clocks = 0; sim->cpu.nextPC = 0xFFFFFFF0; sim->cpu.operation = CPU_FETCH; sim->cpu.step = 0; return sim; } /* Specify a game pak RAM buffer */ VBAPI int vbSetCartRAM(VB *sim, void *sram, uint32_t size) { if (sram != NULL) { if (size < 16 || size > 0x1000000 || (size & (size - 1)) != 0) return 1; sim->cart.ramMask = size - 1; } sim->cart.ram = sram; return 0; } /* Specify a game pak ROM buffer */ VBAPI int vbSetCartROM(VB *sim, void *rom, uint32_t size) { if (rom != NULL) { if (size < 16 || size > 0x1000000 || (size & (size - 1)) != 0) return 1; sim->cart.romMask = size - 1; } sim->cart.rom = rom; return 0; } /* Specify a new execute callback handle */ VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback) { vbOnExecute prev = sim->onExecute; sim->onExecute = callback; return prev; } /* Specify a new fetch callback handle */ VBAPI vbOnFetch vbSetFetchCallback(VB *sim, vbOnFetch callback) { vbOnFetch prev = sim->onFetch; sim->onFetch = callback; return prev; } /* Specify a new value for the program counter */ VBAPI uint32_t vbSetProgramCounter(VB *sim, uint32_t value) { sim->cpu.operation = CPU_FETCH; sim->cpu.pc = sim->cpu.nextPC = value & 0xFFFFFFFE; sim->cpu.step = 0; return sim->cpu.pc; } /* Specify a new value for a program register */ VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value) { return index < 1 || index > 31 ? 0 : (sim->cpu.program[index] = value); } /* Specify a new read callback handle */ VBAPI vbOnRead vbSetReadCallback(VB *sim, vbOnRead callback) { vbOnRead prev = sim->onRead; sim->onRead = callback; return prev; } /* Specify a new value for a system register */ VBAPI uint32_t vbSetSystemRegister(VB *sim, int index, uint32_t value) { return index < 0 || index > 31 ? 0 : cpuSetSystemRegister(sim, index, value, 1); } /* Specify a new write callback handle */ VBAPI vbOnWrite vbSetWriteCallback(VB *sim, vbOnWrite callback) { vbOnWrite prev = sim->onWrite; sim->onWrite = callback; return prev; } /* Determine the size of a simulation instance */ VBAPI size_t vbSizeOf() { return sizeof (VB); } /* Specify a simulation's userdata pointer */ VBAPI void* vbSetUserData(VB *sim, void *tag) { void *prev = sim->tag; sim->tag = tag; return prev; } /* Write a value to the memory bus */ VBAPI int32_t vbWrite(VB *sim, uint32_t address, int type, int32_t value) { if (type < 0 || type > 4) return 0; busWrite(sim, address, type, value, 1); return vbRead(sim, address, type); }