From bfc2254b9e26d22be350f82b23d66632e3b55be3 Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Sun, 13 Oct 2024 13:06:49 -0500 Subject: [PATCH] Implement halt, exception, fatal --- core/cpu.c | 467 +++++++++++++++++++++++++++++++++-------------------- core/vb.c | 25 ++- core/vb.h | 67 ++++---- 3 files changed, 351 insertions(+), 208 deletions(-) diff --git a/core/cpu.c b/core/cpu.c index 29a934f..0cf65ec 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -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 */ diff --git a/core/vb.c b/core/vb.c index 88b1f11..2431fc5 100644 --- a/core/vb.c +++ b/core/vb.c @@ -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; diff --git a/core/vb.h b/core/vb.h index bad8d4e..962f78e 100644 --- a/core/vb.h +++ b/core/vb.h @@ -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);