#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 *vb, uint32_t clocks) { return cpuEmulate(vb, clocks) ; } /* Determine how many clocks can be simulated without a breakpoint */ static uint32_t sysUntil(VB *vb, uint32_t clocks) { clocks = cpuUntil(vb, clocks); return clocks; } /************************************ API ************************************/ /* Process a simulation */ int vbEmulate(VB *vb, 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 (vb, *clocks); brk = sysEmulate(vb, until ); } return brk; } /* Process multiple simulations */ int vbEmulateEx(VB **vbs, 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 (vbs[x], until); for (x = 0; x < count; x++) brk |= sysEmulate(vbs[x], until); } return brk; } /* Retrieve a current breakpoint handler */ void* vbGetCallback(VB *vb, int id) { switch (id) { case VB_ONEXCEPTION: return *(void **)&vb->onException; case VB_ONEXECUTE : return *(void **)&vb->onExecute; case VB_ONFETCH : return *(void **)&vb->onFetch; case VB_ONREAD : return *(void **)&vb->onRead; case VB_ONWRITE : return *(void **)&vb->onWrite; } return NULL; } /* Retrieve the value of a register */ int32_t vbGetRegister(VB *vb, int type, int id) { switch (type) { case VB_PROGRAM: return id < 0 || id > 31 ? 0 : vb->cpu.program[id]; case VB_SYSTEM: return cpuGetSystemRegister(vb, id); case VB_OTHER: switch (id) { case VB_PC: return vb->cpu.pc; } } return 0; /* Invalid type */ } /* Retrieve a handle to the current cartridge ROM data */ uint8_t* vbGetROM(VB *vb, uint32_t *size) { if (size != NULL) *size = vb->cart.romSize; return vb->cart.rom; } /* Retrieve a handle to the current cartridge RAM data */ uint8_t* vbGetSRAM(VB *vb, uint32_t *size) { if (size != NULL) *size = vb->cart.ramSize; return vb->cart.ram; } /* Prepare a simulation instance for use */ void vbInit(VB *vb) { /* Breakpoint handlers */ vb->onException = NULL; vb->onExecute = NULL; vb->onFetch = NULL; vb->onRead = NULL; vb->onWrite = NULL; /* Game pak */ vb->cart.ram = NULL; vb->cart.ramSize = 0; vb->cart.rom = NULL; vb->cart.romSize = 0; /* Hardware reset */ vbReset(vb); } /* Read a value from memory */ int32_t vbRead(VB *vb, uint32_t address, int type) { return busRead(vb, address, type); } /* Read multiple bytes from memory */ void vbReadEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) { while (length--) *buffer++ = busRead(vb, address++, VB_U8); } /* Simulate a hardware reset */ void vbReset(VB *vb) { int x; /* Iterator */ /* Reset WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) vb->wram[x] = 0x00; /* CPU (normal) */ vb->cpu.pc = 0xFFFFFFF0; cpuSetSystemRegister(vb, VB_ECR, 0x0000FFF0, 1); cpuSetSystemRegister(vb, VB_PSW, 0x00008000, 1); for (x = 0; x < 5; x++) vb->cpu.irq[x] = 0; /* CPU (extra, hardware doesn't do this) */ vb->cpu.adtre = 0x00000000; vb->cpu.eipc = 0x00000000; vb->cpu.eipsw = 0x00000000; vb->cpu.fepc = 0x00000000; vb->cpu.fepsw = 0x00000000; vb->cpu.sr29 = 0x00000000; vb->cpu.sr31 = 0x00000000; cpuSetSystemRegister(vb, VB_CHCW, 0x00000000, 1); for (x = 0; x < 32; x++) vb->cpu.program[x] = 0x00000000; /* CPU (internal) */ vb->cpu.bitstring = 0; vb->cpu.clocks = 0; vb->cpu.exception = 0; vb->cpu.stage = CPU_FETCH; vb->cpu.step = 0; } /* Specify a breakpoint handler */ void* vbSetCallback(VB *vb, int id, void *proc) { void *prev = vbGetCallback(vb, id); switch (id) { case VB_ONEXCEPTION: *(void **)&vb->onException = proc; break; case VB_ONEXECUTE : *(void **)&vb->onExecute = proc; break; case VB_ONFETCH : *(void **)&vb->onFetch = proc; break; case VB_ONREAD : *(void **)&vb->onRead = proc; break; case VB_ONWRITE : *(void **)&vb->onWrite = proc; break; } return prev; } /* Specify a value for a register */ int32_t vbSetRegister(VB *vb, int type, int id, int32_t value) { switch (type) { case VB_PROGRAM: return id < 1 || id > 31 ? 0 : (vb->cpu.program[id] = value); case VB_SYSTEM: return cpuSetSystemRegister(vb, id, value, 1); case VB_OTHER: switch (id) { case VB_PC: vb->cpu.bitstring = 0; vb->cpu.clocks = 0; vb->cpu.exception = 0; vb->cpu.stage = CPU_FETCH; return vb->cpu.pc = value & 0xFFFFFFFE; } } return 0; /* Invalid type or ID */ } /* Specify a cartridge ROM buffer */ int vbSetROM(VB *vb, uint8_t *data, uint32_t size) { /* Specifying no ROM */ if (data == NULL) { vb->cart.rom = NULL; vb->cart.romSize = 0; return 0; } /* Error checking */ if ( size < 4 || size > 0x1000000 || (size & (size - 1)) /* Power of 2 */ ) return 1; /* Register the ROM data */ vb->cart.rom = data; vb->cart.romSize = size; return 0; } /* Specify a cartridge RAM buffer */ int vbSetSRAM(VB *vb, uint8_t *data, uint32_t size) { /* Specifying no SRAM */ if (data == NULL) { vb->cart.ram = NULL; vb->cart.ramSize = 0; return 0; } /* Error checking */ if ( size < 4 || size > 0x1000000 || (size & (size - 1)) /* Power of 2 */ ) return 1; /* Register the SRAM data */ vb->cart.ram = data; vb->cart.ramSize = size; return 0; } /* Write a value to memory */ void vbWrite(VB *vb, uint32_t address, int type, int32_t value) { busWrite(vb, address, type, value, 1); } /* Write multiple values to memory */ void vbWriteEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) { while (length--) busWrite(vb, address++, VB_U8, *buffer++, 1); }