2023-03-11 00:44:57 +00:00
|
|
|
#ifndef VBAPI
|
|
|
|
#define VBAPI
|
2022-04-21 03:37:05 +00:00
|
|
|
#endif
|
2021-08-30 02:14:06 +00:00
|
|
|
#include <vb.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/***************************** Utility Functions *****************************/
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Select the lesser of two unsigned numbers */
|
|
|
|
static uint32_t Min(uint32_t a, uint32_t b) {
|
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* 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
|
2021-08-30 02:14:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/**************************** Sub-Module Imports *****************************/
|
2021-08-30 02:14:06 +00:00
|
|
|
|
|
|
|
#include "bus.c"
|
2021-09-19 01:31:40 +00:00
|
|
|
#include "cpu.c"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************** Module Functions ******************************/
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Process a simulation for a given number of clocks */
|
2023-03-11 01:00:45 +00:00
|
|
|
static int sysEmulate(VB *sim, uint32_t clocks) {
|
2023-03-11 00:44:57 +00:00
|
|
|
return
|
2023-03-11 01:00:45 +00:00
|
|
|
cpuEmulate(sim, clocks)
|
2023-03-11 00:44:57 +00:00
|
|
|
;
|
2021-09-19 01:31:40 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Determine how many clocks can be simulated without a breakpoint */
|
2023-03-11 01:00:45 +00:00
|
|
|
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
|
|
|
clocks = cpuUntil(sim, clocks);
|
2021-09-19 01:31:40 +00:00
|
|
|
return clocks;
|
|
|
|
}
|
2021-08-30 02:14:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/************************************ API ************************************/
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Process a simulation */
|
2023-03-11 01:00:45 +00:00
|
|
|
int vbEmulate(VB *sim, uint32_t *clocks) {
|
2023-03-11 00:44:57 +00:00
|
|
|
int brk; /* A break was requested */
|
|
|
|
uint32_t until; /* Number of clocks during which no break will occur */
|
2022-04-15 01:51:09 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Process all clocks */
|
|
|
|
for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
|
2023-03-11 01:00:45 +00:00
|
|
|
until = sysUntil (sim, *clocks);
|
|
|
|
brk = sysEmulate(sim, until );
|
2022-04-15 01:51:09 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
return brk;
|
2022-04-15 01:51:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Process multiple simulations */
|
2023-03-11 01:00:45 +00:00
|
|
|
int vbEmulateEx(VB **sims, int count, uint32_t *clocks) {
|
2023-03-11 00:44:57 +00:00
|
|
|
int brk; /* A break was requested */
|
|
|
|
uint32_t until; /* Number of clocks during which no break will occur */
|
2022-04-15 01:51:09 +00:00
|
|
|
int x; /* Iterator */
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Process all clocks */
|
|
|
|
for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
|
2022-04-15 01:51:09 +00:00
|
|
|
until = *clocks;
|
|
|
|
for (x = 0; x < count; x++)
|
2023-03-11 01:00:45 +00:00
|
|
|
until = sysUntil (sims[x], until);
|
2022-04-15 01:51:09 +00:00
|
|
|
for (x = 0; x < count; x++)
|
2023-03-11 01:00:45 +00:00
|
|
|
brk |= sysEmulate(sims[x], until);
|
2021-09-30 17:33:55 +00:00
|
|
|
}
|
2022-04-21 03:37:05 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
return brk;
|
2021-09-30 17:33:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Retrieve a current breakpoint handler */
|
2023-03-11 01:00:45 +00:00
|
|
|
void* vbGetCallback(VB *sim, int id) {
|
2023-03-11 00:44:57 +00:00
|
|
|
switch (id) {
|
2023-03-11 01:00:45 +00:00
|
|
|
case VB_ONEXCEPTION: return *(void **)&sim->onException;
|
|
|
|
case VB_ONEXECUTE : return *(void **)&sim->onExecute;
|
|
|
|
case VB_ONFETCH : return *(void **)&sim->onFetch;
|
|
|
|
case VB_ONREAD : return *(void **)&sim->onRead;
|
|
|
|
case VB_ONWRITE : return *(void **)&sim->onWrite;
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Retrieve the value of a register */
|
2023-03-11 01:00:45 +00:00
|
|
|
int32_t vbGetRegister(VB *sim, int type, int id) {
|
2023-03-11 00:44:57 +00:00
|
|
|
switch (type) {
|
|
|
|
case VB_PROGRAM:
|
2023-03-11 01:00:45 +00:00
|
|
|
return id < 0 || id > 31 ? 0 : sim->cpu.program[id];
|
2023-03-11 00:44:57 +00:00
|
|
|
case VB_SYSTEM:
|
2023-03-11 01:00:45 +00:00
|
|
|
return cpuGetSystemRegister(sim, id);
|
2023-03-11 00:44:57 +00:00
|
|
|
case VB_OTHER:
|
|
|
|
switch (id) {
|
2023-03-11 01:00:45 +00:00
|
|
|
case VB_PC: return sim->cpu.pc;
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; /* Invalid type */
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Retrieve a handle to the current cartridge ROM data */
|
2023-03-11 01:00:45 +00:00
|
|
|
uint8_t* vbGetROM(VB *sim, uint32_t *size) {
|
2021-08-30 13:58:40 +00:00
|
|
|
if (size != NULL)
|
2023-03-11 01:00:45 +00:00
|
|
|
*size = sim->cart.romSize;
|
|
|
|
return sim->cart.rom;
|
2021-08-30 13:58:40 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Retrieve a handle to the current cartridge RAM data */
|
2023-03-11 01:00:45 +00:00
|
|
|
uint8_t* vbGetSRAM(VB *sim, uint32_t *size) {
|
2021-08-30 13:58:40 +00:00
|
|
|
if (size != NULL)
|
2023-03-11 01:00:45 +00:00
|
|
|
*size = sim->cart.ramSize;
|
|
|
|
return sim->cart.ram;
|
2021-08-30 13:58:40 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Prepare a simulation instance for use */
|
2023-03-11 01:00:45 +00:00
|
|
|
void vbInit(VB *sim) {
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Breakpoint handlers */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->onException = NULL;
|
|
|
|
sim->onExecute = NULL;
|
|
|
|
sim->onFetch = NULL;
|
|
|
|
sim->onRead = NULL;
|
|
|
|
sim->onWrite = NULL;
|
2021-08-30 13:58:40 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Game pak */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cart.ram = NULL;
|
|
|
|
sim->cart.ramSize = 0;
|
|
|
|
sim->cart.rom = NULL;
|
|
|
|
sim->cart.romSize = 0;
|
2021-09-19 01:31:40 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Hardware reset */
|
2023-03-11 01:00:45 +00:00
|
|
|
vbReset(sim);
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|
2021-08-30 13:58:40 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Read a value from memory */
|
2023-03-11 01:00:45 +00:00
|
|
|
int32_t vbRead(VB *sim, uint32_t address, int type) {
|
|
|
|
return busRead(sim, address, type);
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Read multiple bytes from memory */
|
2023-03-11 01:00:45 +00:00
|
|
|
void vbReadEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) {
|
|
|
|
while (length--) *buffer++ = busRead(sim, address++, VB_U8);
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Simulate a hardware reset */
|
2023-03-11 01:00:45 +00:00
|
|
|
void vbReset(VB *sim) {
|
2023-03-11 00:44:57 +00:00
|
|
|
int x; /* Iterator */
|
2021-09-02 00:16:22 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Reset WRAM (the hardware does not do this) */
|
2021-08-30 02:14:06 +00:00
|
|
|
for (x = 0; x < 0x10000; x++)
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->wram[x] = 0x00;
|
2023-03-11 00:44:57 +00:00
|
|
|
|
|
|
|
/* CPU (normal) */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.pc = 0xFFFFFFF0;
|
|
|
|
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
|
|
|
cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1);
|
2023-03-11 00:44:57 +00:00
|
|
|
for (x = 0; x < 5; x++)
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.irq[x] = 0;
|
2023-03-11 00:44:57 +00:00
|
|
|
|
|
|
|
/* CPU (extra, hardware doesn't do this) */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.adtre = 0x00000000;
|
|
|
|
sim->cpu.eipc = 0x00000000;
|
|
|
|
sim->cpu.eipsw = 0x00000000;
|
|
|
|
sim->cpu.fepc = 0x00000000;
|
|
|
|
sim->cpu.fepsw = 0x00000000;
|
|
|
|
sim->cpu.sr29 = 0x00000000;
|
|
|
|
sim->cpu.sr31 = 0x00000000;
|
|
|
|
cpuSetSystemRegister(sim, VB_CHCW, 0x00000000, 1);
|
2023-03-11 00:44:57 +00:00
|
|
|
for (x = 0; x < 32; x++)
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.program[x] = 0x00000000;
|
2023-03-11 00:44:57 +00:00
|
|
|
|
|
|
|
/* CPU (internal) */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.bitstring = 0;
|
|
|
|
sim->cpu.clocks = 0;
|
|
|
|
sim->cpu.exception = 0;
|
|
|
|
sim->cpu.stage = CPU_FETCH;
|
|
|
|
sim->cpu.step = 0;
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Specify a breakpoint handler */
|
2023-03-11 01:00:45 +00:00
|
|
|
void* vbSetCallback(VB *sim, int id, void *proc) {
|
|
|
|
void *prev = vbGetCallback(sim, id);
|
2023-03-11 00:44:57 +00:00
|
|
|
switch (id) {
|
2023-03-11 01:00:45 +00:00
|
|
|
case VB_ONEXCEPTION: *(void **)&sim->onException = proc; break;
|
|
|
|
case VB_ONEXECUTE : *(void **)&sim->onExecute = proc; break;
|
|
|
|
case VB_ONFETCH : *(void **)&sim->onFetch = proc; break;
|
|
|
|
case VB_ONREAD : *(void **)&sim->onRead = proc; break;
|
|
|
|
case VB_ONWRITE : *(void **)&sim->onWrite = proc; break;
|
2021-09-30 17:33:55 +00:00
|
|
|
}
|
2022-04-21 03:37:05 +00:00
|
|
|
return prev;
|
2021-09-30 17:33:55 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Specify a value for a register */
|
2023-03-11 01:00:45 +00:00
|
|
|
int32_t vbSetRegister(VB *sim, int type, int id, int32_t value) {
|
2023-03-11 00:44:57 +00:00
|
|
|
switch (type) {
|
|
|
|
case VB_PROGRAM:
|
2023-03-11 01:00:45 +00:00
|
|
|
return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value);
|
2023-03-11 00:44:57 +00:00
|
|
|
case VB_SYSTEM:
|
2023-03-11 01:00:45 +00:00
|
|
|
return cpuSetSystemRegister(sim, id, value, 1);
|
2023-03-11 00:44:57 +00:00
|
|
|
case VB_OTHER:
|
|
|
|
switch (id) {
|
|
|
|
case VB_PC:
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cpu.bitstring = 0;
|
|
|
|
sim->cpu.clocks = 0;
|
|
|
|
sim->cpu.exception = 0;
|
|
|
|
sim->cpu.stage = CPU_FETCH;
|
|
|
|
return sim->cpu.pc = value & 0xFFFFFFFE;
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0; /* Invalid type or ID */
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Specify a cartridge ROM buffer */
|
2023-03-11 01:00:45 +00:00
|
|
|
int vbSetROM(VB *sim, uint8_t *data, uint32_t size) {
|
2023-03-11 00:44:57 +00:00
|
|
|
|
|
|
|
/* Specifying no ROM */
|
|
|
|
if (data == NULL) {
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cart.rom = NULL;
|
|
|
|
sim->cart.romSize = 0;
|
2023-03-11 00:44:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Error checking */
|
|
|
|
if (
|
|
|
|
size < 4 ||
|
|
|
|
size > 0x1000000 ||
|
|
|
|
(size & (size - 1)) /* Power of 2 */
|
|
|
|
) return 1;
|
|
|
|
|
|
|
|
/* Register the ROM data */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cart.rom = data;
|
|
|
|
sim->cart.romSize = size;
|
2023-03-11 00:44:57 +00:00
|
|
|
return 0;
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Specify a cartridge RAM buffer */
|
2023-03-11 01:00:45 +00:00
|
|
|
int vbSetSRAM(VB *sim, uint8_t *data, uint32_t size) {
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Specifying no SRAM */
|
|
|
|
if (data == NULL) {
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cart.ram = NULL;
|
|
|
|
sim->cart.ramSize = 0;
|
2021-08-30 02:14:06 +00:00
|
|
|
return 0;
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Error checking */
|
|
|
|
if (
|
|
|
|
size < 4 ||
|
|
|
|
size > 0x1000000 ||
|
|
|
|
(size & (size - 1)) /* Power of 2 */
|
|
|
|
) return 1;
|
|
|
|
|
|
|
|
/* Register the SRAM data */
|
2023-03-11 01:00:45 +00:00
|
|
|
sim->cart.ram = data;
|
|
|
|
sim->cart.ramSize = size;
|
2023-03-11 00:44:57 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2021-08-30 02:14:06 +00:00
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Write a value to memory */
|
2023-03-11 01:00:45 +00:00
|
|
|
void vbWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
|
|
|
busWrite(sim, address, type, value, 1);
|
2021-08-30 02:14:06 +00:00
|
|
|
}
|
|
|
|
|
2023-03-11 00:44:57 +00:00
|
|
|
/* Write multiple values to memory */
|
2023-03-11 01:00:45 +00:00
|
|
|
void vbWriteEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) {
|
|
|
|
while (length--) busWrite(sim, address++, VB_U8, *buffer++, 1);
|
2023-03-11 00:44:57 +00:00
|
|
|
}
|