#ifndef VBAPI #define VBAPI #endif #include /***************************** Utility Functions *****************************/ /* Select the lesser of two unsigned numbers */ static uint32_t Min(uint32_t a, uint32_t b) { return a < b ? a : b; } /* Sign-extend an integer, masking upper bits if positive */ #ifndef VB_SIGNED_PROPAGATE /* Generic implementation */ static int32_t SignExtend(int32_t value, int bits) { return value & 1 << (bits - 1) ? value | ~0 << bits : value & ((1 << bits) - 1) ; } #else /* Sign-propagating implementation */ #define SignExtend(v, b) ((int32_t) (v) << (32 - (b)) >> (32 - (b))) #endif /**************************** Sub-Module Imports *****************************/ #include "bus.c" #include "cpu.c" /***************************** Module 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 can be simulated without a breakpoint */ static uint32_t sysUntil(VB *sim, uint32_t clocks) { clocks = cpuUntil(sim, clocks); return clocks; } /************************************ API ************************************/ /* Process a simulation */ int vbEmulate(VB *sim, uint32_t *clocks) { int brk; /* A break was requested */ uint32_t until; /* Number of clocks during which no break will occur */ /* Process all clocks */ for (brk = 0; *clocks != 0 && !brk; *clocks -= until) { until = sysUntil (sim, *clocks); brk = sysEmulate(sim, until ); } return brk; } /* Process multiple simulations */ int vbEmulateEx(VB **sims, int count, uint32_t *clocks) { int brk; /* A break was requested */ uint32_t until; /* Number of clocks during which no break will occur */ int x; /* Iterator */ /* Process all clocks */ for (brk = 0; *clocks != 0 && !brk; *clocks -= until) { until = *clocks; for (x = 0; x < count; x++) until = sysUntil (sims[x], until); for (x = 0; x < count; x++) brk |= sysEmulate(sims[x], until); } return brk; } /* Retrieve a current breakpoint handler */ void* vbGetCallback(VB *sim, int id) { switch (id) { case VB_ONEXCEPTION: return *(void **)&sim->onException; case VB_ONEXECUTE : return *(void **)&sim->onExecute; case VB_ONFETCH : return *(void **)&sim->onFetch; case VB_ONREAD : return *(void **)&sim->onRead; case VB_ONWRITE : return *(void **)&sim->onWrite; } return NULL; } /* Retrieve the value of a register */ int32_t vbGetRegister(VB *sim, int type, int id) { switch (type) { case VB_PROGRAM: return id < 0 || id > 31 ? 0 : sim->cpu.program[id]; case VB_SYSTEM: return cpuGetSystemRegister(sim, id); case VB_OTHER: switch (id) { case VB_PC: return sim->cpu.pc; } } return 0; /* Invalid type */ } /* Retrieve a handle to the current cartridge ROM data */ uint8_t* vbGetROM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.romSize; return sim->cart.rom; } /* Retrieve a handle to the current cartridge RAM data */ uint8_t* vbGetSRAM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.ramSize; return sim->cart.ram; } /* Prepare a simulation instance for use */ void vbInit(VB *sim) { /* Breakpoint handlers */ sim->onException = NULL; sim->onExecute = NULL; sim->onFetch = NULL; sim->onRead = NULL; sim->onWrite = NULL; /* Game pak */ sim->cart.ram = NULL; sim->cart.ramSize = 0; sim->cart.rom = NULL; sim->cart.romSize = 0; /* Hardware reset */ vbReset(sim); } /* Read a value from memory */ int32_t vbRead(VB *sim, uint32_t address, int type) { return busRead(sim, address, type); } /* Read multiple bytes from memory */ void vbReadEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) { while (length--) *buffer++ = busRead(sim, address++, VB_U8); } /* Simulate a hardware reset */ void vbReset(VB *sim) { int x; /* Iterator */ /* Reset WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) sim->wram[x] = 0x00; /* CPU (normal) */ sim->cpu.pc = 0xFFFFFFF0; cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1); cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1); for (x = 0; x < 5; x++) sim->cpu.irq[x] = 0; /* CPU (extra, hardware doesn't 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 (internal) */ sim->cpu.bitstring = 0; sim->cpu.clocks = 0; sim->cpu.exception = 0; sim->cpu.stage = CPU_FETCH; sim->cpu.step = 0; } /* Specify a breakpoint handler */ void* vbSetCallback(VB *sim, int id, void *proc) { void *prev = vbGetCallback(sim, id); switch (id) { case VB_ONEXCEPTION: *(void **)&sim->onException = proc; break; case VB_ONEXECUTE : *(void **)&sim->onExecute = proc; break; case VB_ONFETCH : *(void **)&sim->onFetch = proc; break; case VB_ONREAD : *(void **)&sim->onRead = proc; break; case VB_ONWRITE : *(void **)&sim->onWrite = proc; break; } return prev; } /* Specify a value for a register */ int32_t vbSetRegister(VB *sim, int type, int id, int32_t value) { switch (type) { case VB_PROGRAM: return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value); case VB_SYSTEM: return cpuSetSystemRegister(sim, id, value, 1); case VB_OTHER: switch (id) { case VB_PC: sim->cpu.bitstring = 0; sim->cpu.clocks = 0; sim->cpu.exception = 0; sim->cpu.stage = CPU_FETCH; return sim->cpu.pc = value & 0xFFFFFFFE; } } return 0; /* Invalid type or ID */ } /* Specify a cartridge ROM buffer */ int vbSetROM(VB *sim, uint8_t *data, uint32_t size) { /* Specifying no ROM */ if (data == NULL) { sim->cart.rom = NULL; sim->cart.romSize = 0; return 0; } /* Error checking */ if ( size < 4 || size > 0x1000000 || (size & (size - 1)) /* Power of 2 */ ) return 1; /* Register the ROM data */ sim->cart.rom = data; sim->cart.romSize = size; return 0; } /* Specify a cartridge RAM buffer */ int vbSetSRAM(VB *sim, uint8_t *data, uint32_t size) { /* Specifying no SRAM */ if (data == NULL) { sim->cart.ram = NULL; sim->cart.ramSize = 0; return 0; } /* Error checking */ if ( size < 4 || size > 0x1000000 || (size & (size - 1)) /* Power of 2 */ ) return 1; /* Register the SRAM data */ sim->cart.ram = data; sim->cart.ramSize = size; return 0; } /* Write a value to memory */ void vbWrite(VB *sim, uint32_t address, int type, int32_t value) { busWrite(sim, address, type, value, 1); } /* Write multiple values to memory */ void vbWriteEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) { while (length--) busWrite(sim, address++, VB_U8, *buffer++, 1); }