#ifdef VB_EXPORT #define VBAPI VB_EXPORT #else #define VBAPI #endif /* Header includes */ #include #include /********************************* Constants *********************************/ /* Type sizes */ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; /********************************** Macros ***********************************/ /* Sign-extend a value of some number of bits to 32 bits */ #define SignExtend(v,b) \ ((v) | (((v) & (1 << ((b) - 1))) ? (uint32_t) 0xFFFFFFFF << (b) : 0)) /*************************** Subsystem Components ****************************/ /* Component includes */ #include "bus.c" #include "cpu.c" /***************************** Module Functions ******************************/ /* Process a simulation for some number of clocks */ static int sysEmulate(VB *sim, uint32_t clocks) { int broke; broke = cpuEmulate(sim, clocks); return broke; } /* Determine the number of clocks before a break condititon could occur */ static uint32_t sysUntil(VB *sim, uint32_t clocks) { clocks = cpuUntil(sim, clocks); return clocks; } /******************************* API Functions *******************************/ /* Associate two simulations as peers, or remove an association */ void vbConnect(VB *sim1, VB *sim2) { /* Disconnect */ if (sim2 == NULL) { if (sim1->peer != NULL) sim1->peer->peer = NULL; sim1->peer = NULL; return; } /* Disconnect any existing link associations */ if (sim1->peer != NULL && sim1->peer != sim2) sim1->peer->peer = NULL; if (sim2->peer != NULL && sim2->peer != sim1) sim2->peer->peer = NULL; /* Link the two simulations */ sim1->peer = sim2; sim2->peer = sim1; } /* Process one simulation */ int vbEmulate(VB *sim, uint32_t *clocks) { int broke; /* The simulation requested an application break */ uint32_t until; /* Maximum clocks before a break could happen */ /* Process the simulation until a break condition occurs */ do { until = *clocks; until = sysUntil (sim, until); broke = sysEmulate(sim, until); *clocks -= until; } while (!broke && *clocks > 0); return broke; } /* Process multiple simulations */ int vbEmulateMulti(VB **sims, int count, uint32_t *clocks) { int broke; /* The simulation requested an application break */ uint32_t until; /* Maximum clocks before a break could happen */ int x; /* Iterator */ /* Process simulations until a break condition occurs */ do { broke = 0; until = *clocks; for (x = 0; x < count; x++) until = sysUntil (sims[x], until); for (x = 0; x < count; x++) broke |= sysEmulate(sims[x], until); *clocks -= until; } while (!broke && *clocks > 0); return broke; } /* Retrieve a current breakpoint callback */ void* vbGetCallback(VB *sim, int type) { void **field; /* Pointer to field within simulation */ /* Select the field to update */ switch (type) { case VB_ONEXCEPTION: field = (void *) &sim->onException; break; case VB_ONEXECUTE : field = (void *) &sim->onExecute ; break; case VB_ONFETCH : field = (void *) &sim->onFetch ; break; case VB_ONREAD : field = (void *) &sim->onRead ; break; case VB_ONWRITE : field = (void *) &sim->onWrite ; break; default: return NULL; } /* Retrieve the simulation field */ return *field; } /* Retrieve the value of PC */ uint32_t vbGetProgramCounter(VB *sim) { return sim->cpu.pc; } /* Retrieve the value of a program register */ int32_t vbGetProgramRegister(VB *sim, int id) { return id < 1 || id > 31 ? 0 : sim->cpu.program[id]; } /* Retrieve the ROM buffer */ void* vbGetROM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.romSize; return sim->cart.rom; } /* Retrieve the SRAM buffer */ void* vbGetSRAM(VB *sim, uint32_t *size) { if (size != NULL) *size = sim->cart.sramSize; return sim->cart.sram; } /* Retrieve the value of a system register */ uint32_t vbGetSystemRegister(VB *sim, int id) { switch (id) { case VB_ADTRE: return sim->cpu.adtre; case VB_CHCW : return sim->cpu.chcw.ice << 1; case VB_EIPC : return sim->cpu.eipc; case VB_EIPSW: return sim->cpu.eipsw; case VB_FEPC : return sim->cpu.fepc; case VB_FEPSW: return sim->cpu.fepsw; case VB_PIR : return 0x00005346; case VB_TKCW : return 0x000000E0; case 29 : return sim->cpu.sr29; case 30 : return 0x00000004; case 31 : return sim->cpu.sr31; case VB_ECR : return (uint32_t) sim->cpu.ecr.fecc << 16 | sim->cpu.ecr.eicc; case VB_PSW : return (uint32_t) sim->cpu.psw.i << 16 | (uint32_t) sim->cpu.psw.np << 15 | (uint32_t) sim->cpu.psw.ep << 14 | (uint32_t) sim->cpu.psw.ae << 13 | (uint32_t) sim->cpu.psw.id << 12 | (uint32_t) sim->cpu.psw.fro << 9 | (uint32_t) sim->cpu.psw.fiv << 8 | (uint32_t) sim->cpu.psw.fzd << 7 | (uint32_t) sim->cpu.psw.fov << 6 | (uint32_t) sim->cpu.psw.fud << 5 | (uint32_t) sim->cpu.psw.fpr << 4 | (uint32_t) sim->cpu.psw.cy << 3 | (uint32_t) sim->cpu.psw.ov << 2 | (uint32_t) sim->cpu.psw.s << 1 | (uint32_t) sim->cpu.psw.z ; } return 0; } /* Prepare a simulation state instance for use */ void vbInit(VB *sim) { /* Breakpoint callbacks */ sim->onException = NULL; sim->onExecute = NULL; sim->onFetch = NULL; sim->onRead = NULL; sim->onWrite = NULL; /* System */ sim->peer = NULL; /* Cartridge */ sim->cart.rom = NULL; sim->cart.romSize = 0; sim->cart.sram = NULL; sim->cart.sramSize = 0; /* Everything else */ vbReset(sim); } /* Read a data unit from the bus */ int32_t vbRead(VB *sim, uint32_t address, int type, int debug) { return type < 0 || type >= (int) sizeof TYPE_SIZES ? 0 : busRead(sim, address, type, debug); } /* Simulate a hardware reset */ void vbReset(VB *sim) { uint32_t x; /* Iterator */ /* Subsystem components */ cpuReset(sim); /* WRAM (the hardware does not do this) */ for (x = 0; x < 0x10000; x++) sim->wram[x] = 0x00; } /* Specify a breakpoint callback */ void* vbSetCallback(VB *sim, int type, void *callback) { void **field; /* Pointer to field within simulation */ void *prev; /* Previous value within field */ /* Select the field to update */ switch (type) { case VB_ONEXCEPTION: field = (void *) &sim->onException; break; case VB_ONEXECUTE : field = (void *) &sim->onExecute ; break; case VB_ONFETCH : field = (void *) &sim->onFetch ; break; case VB_ONREAD : field = (void *) &sim->onRead ; break; case VB_ONWRITE : field = (void *) &sim->onWrite ; break; return NULL; } /* Update the simulation field */ prev = *field; *field = callback; return prev; } /* Specify a new value for PC */ uint32_t vbSetProgramCounter(VB *sim, uint32_t value) { value &= 0xFFFFFFFE; sim->cpu.busWait = 0; sim->cpu.causeCode = 0; sim->cpu.clocks = 0; sim->cpu.fetch = 0; sim->cpu.pc = value; sim->cpu.state = CPU_FETCH; sim->cpu.substring = 0; return value; } /* Specify a new value for a program register */ int32_t vbSetProgramRegister(VB *sim, int id, int32_t value) { return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value); } /* Supply a ROM buffer */ int vbSetROM(VB *sim, void *rom, uint32_t size) { /* Check the buffer size */ if (size < 1024 || size > 0x1000000 || ((size - 1) & size) != 0) return 0; /* Configure the ROM buffer */ sim->cart.rom = (uint8_t *) rom; sim->cart.romSize = size; return 1; } /* Supply an SRAM buffer */ int vbSetSRAM(VB *sim, void *sram, uint32_t size) { /* Check the buffer size */ if (size == 0 || ((size - 1) & size) != 0) return 0; /* Configure the SRAM buffer */ sim->cart.sram = (uint8_t *) sram; sim->cart.sramSize = size; return 1; } /* Specify a new value for a system register */ uint32_t vbSetSystemRegister(VB *sim, int id, uint32_t value) { return cpuSetSystemRegister(sim, id, value, 1); } /* Write a data unit to the bus */ void vbWrite(VB *sim, uint32_t address, int type, int32_t value, int debug) { if (type >= 0 && type < (int32_t) sizeof TYPE_SIZES) busWrite(sim, address, type, value, debug); }