287 lines
8.1 KiB
C
287 lines
8.1 KiB
C
#ifdef VB_EXPORT
|
|
#define VBAPI VB_EXPORT
|
|
#else
|
|
#define VBAPI
|
|
#endif
|
|
|
|
/* Header includes */
|
|
#include <float.h>
|
|
#include <vb.h>
|
|
|
|
|
|
|
|
/********************************* 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)
|