Implement halt, exception, fatal

This commit is contained in:
Guy Perfect 2024-10-13 13:06:49 -05:00
parent 7c25a4ac93
commit bfc2254b9e
3 changed files with 351 additions and 208 deletions

View File

@ -125,6 +125,12 @@ static const uint8_t INST_LENGTHS[] = {
2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2
};
/* Highest interrupt level by IRQ bit mask value */
static const int8_t IRQ_LEVELS[] = {
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
};
/********************************** Macros ***********************************/
@ -195,6 +201,18 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
/***************************** Callback Handlers *****************************/
/* Prepare to handle an exception */
#ifndef VB_DIRECT_EXCEPTION
#define VB_ON_EXCEPTION sim->onException
#else
extern int vbxOnException(VB *, uint16_t *);
#define VB_ON_EXCEPTION sim->onException
#endif
static int cpuOnException(VB *sim, uint16_t *cause) {
return sim->onException != NULL && VB_ON_EXCEPTION(sim, cause);
}
#undef VB_ON_EXCEPTION
/* Prepare to execute an instruction */
#ifndef VB_DIRECT_EXECUTE
#define VB_ON_EXECUTE sim->onExecute
@ -202,7 +220,7 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
extern int vbxOnExecute(VB *, uint32_t, const uint16_t *, int);
#define VB_ON_EXECUTE vbxOnExecute
#endif
static int cpuExecute(VB *sim) {
static int cpuOnExecute(VB *sim) {
return
sim->onExecute != NULL &&
VB_ON_EXECUTE(sim, sim->cpu.pc, sim->cpu.code, sim->cpu.length)
@ -289,160 +307,8 @@ static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
/****************************** Pipeline Stages ******************************/
/* Fetch the code bits for the next instruction */
static int cpuFetch(VB *sim) {
int32_t value;
switch (sim->cpu.step) {
case 0:
sim->cpu.pc = sim->cpu.nextPC;
/* Fallthrough */
case 1:
/* Retrieve the first code unit */
if (cpuReadFetch(sim, 0, sim->cpu.pc, &value)) {
sim->cpu.step = 1;
return 1;
}
/* Update state */
sim->cpu.code[0] = value;
sim->cpu.length = INST_LENGTHS[value >> 10 & 63];
sim->cpu.step = 3 - sim->cpu.length;
/* Wait any clocks taken */
if (sim->cpu.clocks != 0)
return 0;
/* Skip fetching a second code unit */
if (sim->cpu.length == 1)
goto Step3;
/* Fallthrough */
case 2:
/* Retrieve the second code unit */
if (cpuReadFetch(sim, 1, sim->cpu.pc + 2, &value))
return 1;
/* Update state */
sim->cpu.code[1] = value;
sim->cpu.step = 3;
/* Wait any clocks taken */
if (sim->cpu.clocks != 0)
return 0;
/* Fallthrough */
case 3: Step3:
/* Prepare to execute the instruction */
if (cpuExecute(sim))
return 1;
/* Select operation definition */
sim->cpu.operation = OPDEFS[sim->cpu.code[0] >> 10];
switch (sim->cpu.operation) {
case CPU_BITSTRING:
sim->cpu.operation =
OPDEFS_BITSTRING[sim->cpu.code[0] & 31];
break;
case CPU_FLOATENDO:
sim->cpu.operation =
OPDEFS_FLOATENDO[sim->cpu.code[1] >> 10];
}
/* Update state */
sim->cpu.step = 0;
}
return 0;
}
/**************************** Instruction Helpers ****************************/
/* Parse the immediate 4-bit condition value */
static int32_t cpuGetCond(VB *sim) {
return sim->cpu.code[0] >> 9 & 15;
}
/* Parse the 9-bit displacement value */
static int32_t cpuGetDisp9(VB *sim) {
return SignExtend(sim->cpu.code[0], 9);
}
/* Parse the 26-bit displacement value */
static int32_t cpuGetDisp26(VB *sim) {
return SignExtend((int32_t) sim->cpu.code[0] << 16 | sim->cpu.code[1], 26);
}
/* Parse the immediate 5-bit sign-extended value */
static int32_t cpuGetImm5S(VB *sim) {
return SignExtend(sim->cpu.code[0], 5);
}
/* Parse the immediate 5-bit zero-filled value */
static int32_t cpuGetImm5U(VB *sim) {
return sim->cpu.code[0] & 31;
}
/* Parse the immediate 16-bit sign-extended value */
static int32_t cpuGetImm16S(VB *sim) {
return SignExtend(sim->cpu.code[1], 16);
}
/* Parse the immediate 16-bit zero-filled value */
static int32_t cpuGetImm16U(VB *sim) {
return sim->cpu.code[1];
}
/* Resolve the operand value for reg1 */
static int32_t cpuGetReg1(VB *sim) {
return sim->cpu.program[sim->cpu.code[0] & 31];
}
/* Resolve the operand value for reg2 */
static int32_t cpuGetReg2(VB *sim) {
return sim->cpu.program[sim->cpu.code[0] >> 5 & 31];
}
/* Supply an operand value for reg2 */
static void cpuSetReg2(VB *sim, int32_t value) {
int reg2 = sim->cpu.code[0] >> 5 & 31;
if (reg2 != 0)
sim->cpu.program[reg2] = value;
}
/* Advance to the next instruction */
static void cpuAdvance(VB *sim, uint32_t clocks) {
sim->cpu.clocks += clocks;
sim->cpu.operation = CPU_FETCH;
sim->cpu.nextPC = sim->cpu.pc + (sim->cpu.length << 1);
sim->cpu.step = 0;
}
/* Interpret floating short bits as word integer bits */
static int32_t cpuFloatToWord(float x) {
return *(int32_t *) &x;
}
/* Raise an exception */
static int cpuThrow(VB *sim, uint16_t cause) {
sim->cpu.exception = cause;
sim->cpu.operation = CPU_EXCEPTION;
return 0;
}
/* Interpret word integer bits as floating short bits */
static float cpuWordToFloat(int32_t x) {
return *(float *) &x;
}
/* Retrieve the value of a system register */
static uint32_t cpuGetSystemRegister(VB *sim, int index) {
switch (index) {
@ -528,6 +394,260 @@ static uint32_t cpuSetSystemRegister(VB*sim,
return 0x00000000; /* All others */
}
/* Raise an exception */
static void cpuThrow(VB *sim, uint16_t cause) {
sim->cpu.exception = cause;
sim->cpu.operation = CPU_EXCEPTION;
sim->cpu.step = 0;
}
/* Check for an interrupt request */
static int cpuIRQ(VB *sim) {
int level;
if (sim->cpu.psw.id | sim->cpu.psw.ep | sim->cpu.psw.np)
return 0;
level = IRQ_LEVELS[sim->cpu.irq];
if (level > sim->cpu.psw.i)
return 0;
cpuThrow(sim, 0xFE00 | level << 4);
return 1;
}
/****************************** Pipeline Stages ******************************/
/* Handle an exception */
static int cpuException(VB *sim) {
uint16_t cause = sim->cpu.exception;
/* Invoke the exception callback */
if (sim->cpu.step == 0 && cpuOnException(sim, &cause))
return 1;
/* Fatal exception */
if (sim->cpu.psw.np) {
switch (sim->cpu.step) {
case 0:
auxData.value = 0xFFFF0000 | cause;
/* Fallthrough */
case 1:
if (cpuWrite(sim, 0x00000000, VB_S32, auxData.value)) {
sim->cpu.step = 1;
return 1;
}
auxData.value = cpuGetSystemRegister(sim, VB_PSW);
/* Fallthrough */
case 2:
if (cpuWrite(sim, 0x00000004, VB_S32, auxData.value)) {
sim->cpu.step = 2;
return 1;
}
/* Fallthrough */
case 3:
if (cpuWrite(sim, 0x00000008, VB_S32, sim->cpu.pc)) {
sim->cpu.step = 3;
return 1;
}
}
/* Enter fatal halting state */
sim->cpu.halt = 1;
sim->cpu.operation = CPU_FATAL;
return 0;
}
/* Duplexed exception */
if (sim->cpu.psw.ep) {
sim->cpu.ecr.fecc = cause;
sim->cpu.fepsw = cpuGetSystemRegister(sim, VB_PSW);
sim->cpu.fepc = sim->cpu.pc;
sim->cpu.psw.np = 1;
sim->cpu.nextPC = 0xFFFFFFD0;
}
/* Regular exception */
else {
/* Interrupts only */
if ((cause & 0xFF00) == 0xFE00) {
sim->cpu.psw.i = (cause >> 4 & 7) + 1;
if (sim->cpu.halt) {
sim->cpu.halt = 0;
sim->cpu.pc += 2;
}
}
/* All exceptions */
sim->cpu.ecr.eicc = cause;
sim->cpu.eipsw = cpuGetSystemRegister(sim, VB_PSW);
sim->cpu.eipc = sim->cpu.pc;
sim->cpu.psw.ep = 1;
sim->cpu.nextPC = 0xFFFF0000 |
((cause & 0xFFF0) == 0xFF60 ? 0xFF60 : cause & 0xFFF0);
}
/* All exceptions */
sim->cpu.psw.ae = 0;
sim->cpu.psw.id = 1;
sim->cpu.operation = CPU_FETCH;
/* TODO: Research clocks */
return 0;
}
/* Fetch the code bits for the next instruction */
static int cpuFetch(VB *sim) {
int32_t value;
switch (sim->cpu.step) {
case 0:
sim->cpu.pc = sim->cpu.nextPC;
if (cpuIRQ(sim))
return 0;
/* Fallthrough */
case 1:
/* Retrieve the first code unit */
if (cpuReadFetch(sim, 0, sim->cpu.pc, &value)) {
sim->cpu.step = 1;
return 1;
}
/* Update state */
sim->cpu.code[0] = value;
sim->cpu.length = INST_LENGTHS[value >> 10 & 63];
sim->cpu.step = 3 - sim->cpu.length;
/* Wait any clocks taken */
if (sim->cpu.clocks != 0)
return 0;
/* Skip fetching a second code unit */
if (sim->cpu.length == 1)
goto Step3;
/* Fallthrough */
case 2:
/* Retrieve the second code unit */
if (cpuReadFetch(sim, 1, sim->cpu.pc + 2, &value))
return 1;
/* Update state */
sim->cpu.code[1] = value;
sim->cpu.step = 3;
/* Wait any clocks taken */
if (sim->cpu.clocks != 0)
return 0;
/* Fallthrough */
case 3: Step3:
/* Prepare to execute the instruction */
if (cpuOnExecute(sim))
return 1;
/* Select operation definition */
sim->cpu.operation = OPDEFS[sim->cpu.code[0] >> 10];
switch (sim->cpu.operation) {
case CPU_BITSTRING:
sim->cpu.operation =
OPDEFS_BITSTRING[sim->cpu.code[0] & 31];
break;
case CPU_FLOATENDO:
sim->cpu.operation =
OPDEFS_FLOATENDO[sim->cpu.code[1] >> 10];
}
/* Update state */
sim->cpu.step = 0;
}
return 0;
}
/* HALT instruction is pending */
static int cpuHalt(VB *sim) {
/* TODO: Research clocks */
return !cpuIRQ(sim);
}
/**************************** Instruction Helpers ****************************/
/* Parse the immediate 4-bit condition value */
static int32_t cpuGetCond(VB *sim) {
return sim->cpu.code[0] >> 9 & 15;
}
/* Parse the 9-bit displacement value */
static int32_t cpuGetDisp9(VB *sim) {
return SignExtend(sim->cpu.code[0], 9);
}
/* Parse the 26-bit displacement value */
static int32_t cpuGetDisp26(VB *sim) {
return SignExtend((int32_t) sim->cpu.code[0] << 16 | sim->cpu.code[1], 26);
}
/* Parse the immediate 5-bit sign-extended value */
static int32_t cpuGetImm5S(VB *sim) {
return SignExtend(sim->cpu.code[0], 5);
}
/* Parse the immediate 5-bit zero-filled value */
static int32_t cpuGetImm5U(VB *sim) {
return sim->cpu.code[0] & 31;
}
/* Parse the immediate 16-bit sign-extended value */
static int32_t cpuGetImm16S(VB *sim) {
return SignExtend(sim->cpu.code[1], 16);
}
/* Parse the immediate 16-bit zero-filled value */
static int32_t cpuGetImm16U(VB *sim) {
return sim->cpu.code[1];
}
/* Resolve the operand value for reg1 */
static int32_t cpuGetReg1(VB *sim) {
return sim->cpu.program[sim->cpu.code[0] & 31];
}
/* Resolve the operand value for reg2 */
static int32_t cpuGetReg2(VB *sim) {
return sim->cpu.program[sim->cpu.code[0] >> 5 & 31];
}
/* Supply an operand value for reg2 */
static void cpuSetReg2(VB *sim, int32_t value) {
int reg2 = sim->cpu.code[0] >> 5 & 31;
if (reg2 != 0)
sim->cpu.program[reg2] = value;
}
/* Advance to the next instruction */
static void cpuAdvance(VB *sim, uint32_t clocks) {
sim->cpu.clocks += clocks;
sim->cpu.operation = CPU_FETCH;
sim->cpu.nextPC = sim->cpu.pc + (sim->cpu.length << 1);
sim->cpu.step = 0;
}
/* Interpret floating short bits as word integer bits */
static int32_t cpuFloatToWord(float x) {
return *(int32_t *) &x;
}
/* Interpret word integer bits as floating short bits */
static float cpuWordToFloat(int32_t x) {
return *(float *) &x;
}
/* Addition common processing */
static int32_t cpuAdd(VB *sim, int32_t a, int32_t b) {
int32_t c = a + b;
@ -649,7 +769,8 @@ static int32_t cpuShiftLeft(VB *sim, int32_t b) {
/* Logical right shift common processing */
static int32_t cpuShiftRight(VB *sim, int32_t b) {
int32_t a = cpuGetReg2(sim);
int32_t c = a >> b & (uint32_t) 0xFFFFFFFF << (32 - b);
int32_t c = b == 0 ? (uint32_t) a :
a >> b & ~((uint32_t) 0xFFFFFFFF << (32 - b));
sim->cpu.psw.cy = b == 0 ? 0 : a >> (b - 1) & 1;
sim->cpu.psw.ov = 0;
sim->cpu.psw.s = c < 0;
@ -1087,6 +1208,7 @@ static void cpuMOVHI(VB *sim) {
/* MPYHW */
static void cpuMPYHW(VB *sim) {
cpuSetReg2(sim, cpuGetReg2(sim) * SignExtend(cpuGetReg1(sim), 17));
cpuAdvance(sim, cpuClocks(9));
}
/* MUL */
@ -1120,14 +1242,14 @@ static void cpuMULF_S(VB *sim) {
/* MULU */
static void cpuMULU(VB *sim) {
uint64_t a = cpuGetReg2(sim);
uint64_t b = cpuGetReg1(sim);
int64_t c = a * b;
int32_t d = c;
uint64_t a = (uint32_t) cpuGetReg2(sim);
uint64_t b = (uint32_t) cpuGetReg1(sim);
uint64_t c = a * b;
uint32_t d = c;
sim->cpu.program[30] = c >> 32;
cpuSetReg2(sim, d);
sim->cpu.psw.ov = d != c;
sim->cpu.psw.s = d < 0;
sim->cpu.psw.s = (int32_t) d < 0;
sim->cpu.psw.z = d == 0;
cpuAdvance(sim, 13);
}
@ -1195,6 +1317,12 @@ static void cpuSARImm(VB *sim) {
cpuAdvance(sim, cpuClocks(1));
}
/* SAR register */
static void cpuSARReg(VB *sim) {
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1));
}
/* SEI */
static void cpuSEI(VB *sim) {
sim->cpu.psw.id = 1;
@ -1207,19 +1335,13 @@ static void cpuSETF(VB *sim) {
cpuAdvance(sim, cpuClocks(1));
}
/* SHR register */
static void cpuSARReg(VB *sim) {
cpuSetReg2(sim, cpuShiftArithmetic(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1));
}
/* SHL immediate */
static void cpuSHLImm(VB *sim) {
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetImm5U(sim)));
cpuAdvance(sim, cpuClocks(1));
}
/* SHR register */
/* SHL register */
static void cpuSHLReg(VB *sim) {
cpuSetReg2(sim, cpuShiftLeft(sim, cpuGetReg1(sim) & 31));
cpuAdvance(sim, cpuClocks(1));
@ -1281,9 +1403,8 @@ static void cpuSUBF_S(VB *sim) {
/* TRAP */
static void cpuTRAP(VB *sim) {
sim->cpu.clocks += cpuClocks(15);
sim->cpu.exception = 0xFFA0 + cpuGetImm5U(sim);
sim->cpu.operation = CPU_EXCEPTION;
sim->cpu.clocks += cpuClocks(15);
cpuThrow(sim, 0xFFA0 + cpuGetImm5U(sim));
}
/* TRNC.SW */
@ -1361,7 +1482,10 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
/* Processing by operation ID */
switch (sim->cpu.operation) {
case CPU_FETCH: brk = cpuFetch(sim); break;
case CPU_EXCEPTION: brk = cpuException(sim); break;
case CPU_FATAL : return 0;
case CPU_FETCH : brk = cpuFetch (sim); break;
case CPU_HALTING : if (cpuHalt(sim)) return 0; break;
case CPU_ADD_IMM: cpuADDImm (sim); break;
case CPU_ADD_REG: cpuADDReg (sim); break;
@ -1441,7 +1565,8 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
/* Determine how many clocks are guaranteed to process */
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
return sim->cpu.clocks < clocks ? sim->cpu.clocks : clocks;
return sim->cpu.halt || sim->cpu.clocks > clocks ?
clocks : sim->cpu.clocks;
}
#endif /* VBAPI */

View File

@ -75,6 +75,7 @@ struct VB {
uint32_t clocks; /* Master clocks to wait */
uint16_t code[2]; /* Instruction code units */
uint16_t exception; /* Exception cause code */
int halt; /* CPU is halting */
uint16_t irq; /* Interrupt request lines */
int length; /* Instruction code length */
uint32_t nextPC; /* Address of next instruction */
@ -86,11 +87,12 @@ struct VB {
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 */
vbOnException onException; /* CPU exception */
vbOnExecute onExecute; /* CPU instruction execute */
vbOnFetch onFetch; /* CPU instruction fetch */
vbOnRead onRead; /* CPU instruction read */
vbOnWrite onWrite; /* CPU instruction write */
void *tag; /* User data */
};
@ -185,6 +187,11 @@ VBAPI void* vbGetCartROM(VB *sim, uint32_t *size) {
return sim->cart.rom;
}
/* Retrieve the exception callback handle */
VBAPI vbOnException vbGetExceptionCallback(VB *sim) {
return sim->onException;
}
/* Retrieve the execute callback handle */
VBAPI vbOnExecute vbGetExecuteCallback(VB *sim) {
return sim->onExecute;
@ -256,6 +263,7 @@ VBAPI VB* vbReset(VB *sim) {
/* CPU (normal) */
sim->cpu.exception = 0;
sim->cpu.halt = 0;
sim->cpu.irq = 0;
sim->cpu.pc = 0xFFFFFFF0;
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
@ -304,6 +312,13 @@ VBAPI int vbSetCartROM(VB *sim, void *rom, uint32_t size) {
return 0;
}
/* Specify a new exception callback handle */
VBAPI vbOnException vbSetExceptionCallback(VB *sim, vbOnException callback) {
vbOnException prev = sim->onException;
sim->onException = callback;
return prev;
}
/* Specify a new execute callback handle */
VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback) {
vbOnExecute prev = sim->onExecute;

View File

@ -52,44 +52,47 @@ extern "C" {
typedef struct VB VB;
/* Callbacks */
typedef int (*vbOnExecute)(VB *sim, uint32_t address, const uint16_t *code, int length);
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
typedef int (*vbOnException)(VB *sim, uint16_t *cause);
typedef int (*vbOnExecute )(VB *sim, uint32_t address, const uint16_t *code, int length);
typedef int (*vbOnFetch )(VB *sim, int fetch, uint32_t address, int32_t *value, uint32_t *cycles);
typedef int (*vbOnRead )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles);
typedef int (*vbOnWrite )(VB *sim, uint32_t address, int type, int32_t *value, uint32_t *cycles, int *cancel);
/******************************* API Commands ********************************/
VBAPI int vbEmulate (VB *sim, uint32_t *clocks);
VBAPI int vbEmulateEx (VB **sims, int count, uint32_t *clocks);
VBAPI void* vbGetCallback (VB *sim, int id);
VBAPI void* vbGetCartRAM (VB *sim, uint32_t *size);
VBAPI void* vbGetCartROM (VB *sim, uint32_t *size);
VBAPI vbOnExecute vbGetExecuteCallback(VB *sim);
VBAPI vbOnFetch vbGetFetchCallback (VB *sim);
VBAPI uint32_t vbGetProgramCounter (VB *sim);
VBAPI int32_t vbGetProgramRegister(VB *sim, int index);
VBAPI vbOnRead vbGetReadCallback (VB *sim);
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
VBAPI void* vbGetUserData (VB *sim);
VBAPI vbOnWrite vbGetWriteCallback (VB *sim);
VBAPI VB* vbInit (VB *sim);
VBAPI int32_t vbRead (VB *sim, uint32_t address, int type);
VBAPI VB* vbReset (VB *sim);
VBAPI int vbSetCartRAM (VB *sim, void *sram, uint32_t size);
VBAPI int vbSetCartROM (VB *sim, void *rom, uint32_t size);
VBAPI vbOnExecute vbSetExecuteCallback(VB *sim, vbOnExecute callback);
VBAPI vbOnFetch vbSetFetchCallback (VB *sim, vbOnFetch callback);
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value);
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
VBAPI void* vbSetUserData (VB *sim, void *tag);
VBAPI vbOnWrite vbSetWriteCallback (VB *sim, vbOnWrite callback);
VBAPI size_t vbSizeOf ();
VBAPI int32_t vbWrite (VB *sim, uint32_t address, int type, int32_t value);
VBAPI int vbEmulate (VB *sim, uint32_t *clocks);
VBAPI int vbEmulateEx (VB **sims, int count, uint32_t *clocks);
VBAPI void* vbGetCallback (VB *sim, int id);
VBAPI void* vbGetCartRAM (VB *sim, uint32_t *size);
VBAPI void* vbGetCartROM (VB *sim, uint32_t *size);
VBAPI vbOnException vbGetExceptionCallback(VB *sim);
VBAPI vbOnExecute vbGetExecuteCallback (VB *sim);
VBAPI vbOnFetch vbGetFetchCallback (VB *sim);
VBAPI uint32_t vbGetProgramCounter (VB *sim);
VBAPI int32_t vbGetProgramRegister (VB *sim, int index);
VBAPI vbOnRead vbGetReadCallback (VB *sim);
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
VBAPI void* vbGetUserData (VB *sim);
VBAPI vbOnWrite vbGetWriteCallback (VB *sim);
VBAPI VB* vbInit (VB *sim);
VBAPI int32_t vbRead (VB *sim, uint32_t address, int type);
VBAPI VB* vbReset (VB *sim);
VBAPI int vbSetCartRAM (VB *sim, void *sram, uint32_t size);
VBAPI int vbSetCartROM (VB *sim, void *rom, uint32_t size);
VBAPI vbOnException vbSetExceptionCallback(VB *sim, vbOnException callback);
VBAPI vbOnExecute vbSetExecuteCallback (VB *sim, vbOnExecute callback);
VBAPI vbOnFetch vbSetFetchCallback (VB *sim, vbOnFetch callback);
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
VBAPI int32_t vbSetProgramRegister (VB *sim, int index, int32_t value);
VBAPI vbOnRead vbSetReadCallback (VB *sim, vbOnRead callback);
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
VBAPI void* vbSetUserData (VB *sim, void *tag);
VBAPI vbOnWrite vbSetWriteCallback (VB *sim, vbOnWrite callback);
VBAPI size_t vbSizeOf ();
VBAPI int32_t vbWrite (VB *sim, uint32_t address, int type, int32_t value);