2024 reboot
This commit is contained in:
+99
-105
@@ -3,104 +3,73 @@
|
||||
|
||||
|
||||
|
||||
/***************************** Utility Functions *****************************/
|
||||
/********************************* Constants *********************************/
|
||||
|
||||
/* Memory access address masks by data type */
|
||||
static const uint32_t TYPE_MASKS[] = {
|
||||
0x07FFFFFF, /* S8 */
|
||||
0x07FFFFFF, /* U8 */
|
||||
0x07FFFFFE, /* S16 */
|
||||
0x07FFFFFE, /* U16 */
|
||||
0x07FFFFFC /* S32 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*************************** Sub-Module Functions ****************************/
|
||||
|
||||
/* Read a typed value from a buffer in host memory */
|
||||
static int32_t busReadBuffer(
|
||||
uint8_t *buffer, uint32_t size, uint32_t offset, int type) {
|
||||
static int32_t busReadBuffer(uint8_t *data, int type) {
|
||||
|
||||
/* There is no data */
|
||||
if (buffer == NULL)
|
||||
return 0;
|
||||
|
||||
/* Mirror the buffer across its address range */
|
||||
offset &= size - 1;
|
||||
|
||||
/* Processing by type */
|
||||
/* Processing by data type */
|
||||
switch (type) {
|
||||
|
||||
/* Generic implementation */
|
||||
#ifndef VB_LITTLE_ENDIAN
|
||||
case VB_S8 :
|
||||
return (int8_t) buffer[offset];
|
||||
case VB_U8:
|
||||
return buffer[offset];
|
||||
case VB_S16:
|
||||
return (int32_t) (int8_t)
|
||||
buffer[offset + 1] << 8 | buffer[offset];
|
||||
case VB_U16:
|
||||
offset &= 0xFFFFFFFE;
|
||||
return (int32_t) (int8_t)
|
||||
buffer[offset + 1] << 8 | buffer[offset];
|
||||
case VB_S32:
|
||||
offset &= 0xFFFFFFFC;
|
||||
return
|
||||
(int32_t) buffer[offset + 3] << 24 |
|
||||
(int32_t) buffer[offset + 2] << 16 |
|
||||
(int32_t) buffer[offset + 1] << 8 |
|
||||
buffer[offset ]
|
||||
;
|
||||
case VB_S8 : return ((int8_t *)data)[0];
|
||||
case VB_U8 : return data [0];
|
||||
case VB_S16: return (int32_t) ((int8_t *)data)[1] << 8 | data[0];
|
||||
case VB_U16: return (int32_t) data [1] << 8 | data[0];
|
||||
case VB_S32: return
|
||||
(int32_t) data[3] << 24 | (int32_t) data[2] << 16 |
|
||||
(int32_t) data[1] << 8 | data[0];
|
||||
|
||||
/* Little-endian implementation */
|
||||
/* Little-endian host */
|
||||
#else
|
||||
case VB_S8 : return *(int8_t *)&buffer[offset ];
|
||||
case VB_U8 : return buffer[offset ];
|
||||
case VB_S16: return *(int16_t *)&buffer[offset & 0xFFFFFFFE];
|
||||
case VB_U16: return *(uint16_t *)&buffer[offset & 0xFFFFFFFE];
|
||||
case VB_S32: return *(int32_t *)&buffer[offset & 0xFFFFFFFC];
|
||||
case VB_S8 : return *(int8_t *) data;
|
||||
case VB_U8 : return * data;
|
||||
case VB_S16: return *(int16_t *) data;
|
||||
case VB_U16: return *(uint16_t *) data;
|
||||
case VB_S32: return *(int32_t *) data;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Invalid type */
|
||||
return 0;
|
||||
return 0; /* Unreachable */
|
||||
}
|
||||
|
||||
/* Write a typed value to a buffer in host memory */
|
||||
static void busWriteBuffer(
|
||||
uint8_t *buffer, uint32_t size, uint32_t offset, int type, int32_t value) {
|
||||
static void busWriteBuffer(uint8_t *data, int type, int32_t value) {
|
||||
|
||||
/* There is no data */
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
|
||||
/* Mirror the buffer across its address range */
|
||||
offset &= size - 1;
|
||||
|
||||
/* Processing by type */
|
||||
/* Processing by data type */
|
||||
switch (type) {
|
||||
|
||||
/* Generic implementation */
|
||||
#ifndef VB_LITTLE_ENDIAN
|
||||
case VB_S32:
|
||||
offset &= 0xFFFFFFFC;
|
||||
buffer[offset ] = value;
|
||||
buffer[offset + 1] = value >> 8;
|
||||
buffer[offset + 2] = value >> 16;
|
||||
buffer[offset + 3] = value >> 24;
|
||||
break;
|
||||
case VB_S16:
|
||||
case VB_U16:
|
||||
offset &= 0xFFFFFFFE;
|
||||
buffer[offset ] = value;
|
||||
buffer[offset + 1] = value >> 8;
|
||||
break;
|
||||
case VB_S8 :
|
||||
case VB_U8 :
|
||||
buffer[offset ] = value;
|
||||
case VB_S32: data[3] = value >> 24;
|
||||
data[2] = value >> 16; /* Fallthrough */
|
||||
case VB_S16: /* Fallthrough */
|
||||
case VB_U16: data[1] = value >> 8; /* Fallthrough */
|
||||
case VB_S8 : /* Fallthrough */
|
||||
case VB_U8 : data[0] = value;
|
||||
|
||||
/* Little-endian implementation */
|
||||
/* Little-endian host */
|
||||
#else
|
||||
case VB_S8 :
|
||||
case VB_U8 :
|
||||
buffer[offset ] = value;
|
||||
break;
|
||||
case VB_S16:
|
||||
case VB_U16:
|
||||
*(int16_t *)&buffer[offset & 0xFFFFFFFE] = value;
|
||||
break;
|
||||
case VB_S32:
|
||||
*(int32_t *)&buffer[offset & 0xFFFFFFFC] = value;
|
||||
case VB_S8 : /* Fallthrough */
|
||||
case VB_U8 : * data = value; return;
|
||||
case VB_S16: /* Fallthrough */
|
||||
case VB_U16: *(uint16_t *) data = value; return;
|
||||
case VB_S32: *(int32_t *) data = value; return;
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -109,54 +78,79 @@ static void busWriteBuffer(
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Read a typed value from the simulation bus */
|
||||
static int32_t busRead(VB *sim, uint32_t address, int type) {
|
||||
static void busRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||
|
||||
/* Working variables */
|
||||
address &= TYPE_MASKS[type];
|
||||
*value = 0;
|
||||
|
||||
/* Process by address range */
|
||||
switch (address >> 24) {
|
||||
case 0: break; /* VIP */
|
||||
case 1: break; /* VSU */
|
||||
case 2: break; /* Misc. I/O */
|
||||
case 3: break; /* Unmapped */
|
||||
case 4: break; /* Game Pak expansion */
|
||||
|
||||
case 5: /* WRAM */
|
||||
*value = busReadBuffer(&sim->wram[address & 0x0000FFFF], type);
|
||||
break;
|
||||
|
||||
case 6: /* Game Pak RAM */
|
||||
if (sim->cart.ram != NULL) {
|
||||
*value = busReadBuffer(
|
||||
&sim->cart.ram[address & sim->cart.ramMask], type);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: /* Game Pak ROM */
|
||||
if (sim->cart.rom != NULL) {
|
||||
*value = busReadBuffer(
|
||||
&sim->cart.rom[address & sim->cart.romMask], type);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Processing by address region */
|
||||
switch (address >> 24 & 7) {
|
||||
case 0: return 0; /* VIP */
|
||||
case 1: return 0; /* VSU */
|
||||
case 2: return 0; /* Misc. hardware */
|
||||
case 3: return 0; /* Unmapped */
|
||||
case 4: return 0; /* Game pak expansion */
|
||||
case 5: return /* WRAM */
|
||||
busReadBuffer(sim->wram , 0x10000 , address, type);
|
||||
case 6: return /* Game pak RAM */
|
||||
busReadBuffer(sim->cart.ram, sim->cart.ramSize, address, type);
|
||||
case 7: return /* Game pak ROM */
|
||||
busReadBuffer(sim->cart.rom, sim->cart.romSize, address, type);
|
||||
}
|
||||
|
||||
/* Unreachable */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a typed value to the simulation bus */
|
||||
static void busWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
|
||||
(void) debug;
|
||||
|
||||
/* Processing by address region */
|
||||
switch (address >> 24 & 7) {
|
||||
/* Working variables */
|
||||
address &= TYPE_MASKS[type];
|
||||
|
||||
/* Process by address range */
|
||||
switch (address >> 24) {
|
||||
case 0: break; /* VIP */
|
||||
case 1: break; /* VSU */
|
||||
case 2: break; /* Misc. hardware */
|
||||
case 2: break; /* Misc. I/O */
|
||||
case 3: break; /* Unmapped */
|
||||
case 4: break; /* Game pak expansion */
|
||||
case 5: /* WRAM */
|
||||
busWriteBuffer(sim->wram ,0x10000 ,address,type,value);
|
||||
case 4: break; /* Game Pak expansion */
|
||||
|
||||
case 5: /* WRAM */
|
||||
busWriteBuffer(&sim->wram[address & 0x0000FFFF], type, value);
|
||||
break;
|
||||
case 6: /* Game pak RAM */
|
||||
busWriteBuffer(sim->cart.ram,sim->cart.ramSize,address,type,value);
|
||||
|
||||
case 6: /* Game Pak RAM */
|
||||
if (sim->cart.ram != NULL) {
|
||||
busWriteBuffer(
|
||||
&sim->cart.ram[address & sim->cart.ramMask], type, value);
|
||||
}
|
||||
break;
|
||||
case 7: /* Game pak ROM */
|
||||
busWriteBuffer(sim->cart.rom,sim->cart.romSize,address,type,value);
|
||||
|
||||
case 7: /* Game Pak ROM */
|
||||
if (debug && sim->cart.rom != NULL) {
|
||||
busWriteBuffer(
|
||||
&sim->cart.rom[address & sim->cart.romMask], type, value);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* VBAPI */
|
||||
|
||||
+542
-1586
File diff suppressed because it is too large
Load Diff
@@ -5,37 +5,117 @@
|
||||
|
||||
|
||||
|
||||
/***************************** Utility Functions *****************************/
|
||||
/*********************************** Types ***********************************/
|
||||
|
||||
/* Select the lesser of two unsigned numbers */
|
||||
static uint32_t Min(uint32_t a, uint32_t b) {
|
||||
/* Simulation state */
|
||||
struct VB {
|
||||
|
||||
/* Game Pak */
|
||||
struct {
|
||||
uint8_t *ram; /* Save RAM */
|
||||
uint8_t *rom; /* Program ROM */
|
||||
uint32_t ramMask; /* Size of SRAM - 1 */
|
||||
uint32_t romMask; /* Size of ROM - 1 */
|
||||
} cart;
|
||||
|
||||
/* CPU */
|
||||
struct {
|
||||
|
||||
/* Cache Control Word */
|
||||
struct {
|
||||
uint8_t ice; /* Instruction Cache Enable */
|
||||
} chcw;
|
||||
|
||||
/* Exception Cause Register */
|
||||
struct {
|
||||
uint16_t eicc; /* Exception/Interrupt Cause Code */
|
||||
uint16_t fecc; /* Fatal Error Cause Code */
|
||||
} ecr;
|
||||
|
||||
/* Program Status Word */
|
||||
struct {
|
||||
uint8_t ae; /* Address Trap Enable */
|
||||
uint8_t cy; /* Carry */
|
||||
uint8_t ep; /* Exception Pending */
|
||||
uint8_t fiv; /* Floating Invalid */
|
||||
uint8_t fov; /* Floating Overflow */
|
||||
uint8_t fpr; /* Floading Precision */
|
||||
uint8_t fro; /* Floating Reserved Operand */
|
||||
uint8_t fud; /* Floading Underflow */
|
||||
uint8_t fzd; /* Floating Zero Divide */
|
||||
uint8_t i; /* Interrupt Level */
|
||||
uint8_t id; /* Interrupt Disable */
|
||||
uint8_t np; /* NMI Pending */
|
||||
uint8_t ov; /* Overflow */
|
||||
uint8_t s; /* Sign */
|
||||
uint8_t z; /* Zero */
|
||||
} psw;
|
||||
|
||||
/* Other registers */
|
||||
uint32_t adtre; /* Address Trap Register for Execution */
|
||||
uint32_t eipc; /* Exception/Interrupt PC */
|
||||
uint32_t eipsw; /* Exception/Interrupt PSW */
|
||||
uint32_t fepc; /* Fatal Error PC */
|
||||
uint32_t fepsw; /* Fatal Error PSW */
|
||||
uint32_t pc; /* Program Counter */
|
||||
int32_t program[32]; /* Program registers */
|
||||
uint32_t sr29; /* System register 29 */
|
||||
uint32_t sr31; /* System register 31 */
|
||||
|
||||
/* Working data */
|
||||
union {
|
||||
struct {
|
||||
uint32_t address;
|
||||
int32_t value;
|
||||
} data;
|
||||
} aux;
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Master clocks to wait */
|
||||
uint16_t code[2]; /* Instruction code units */
|
||||
uint16_t irq; /* Interrupt request lines */
|
||||
int length; /* Instruction code length */
|
||||
uint32_t nextPC; /* Address of next instruction */
|
||||
int operation; /* Current operation ID */
|
||||
int step; /* Operation sub-task ID */
|
||||
} cpu;
|
||||
|
||||
/* Other system state */
|
||||
uint8_t wram[0x10000]; /* System RAM */
|
||||
|
||||
/* Application callbacks */
|
||||
vbOnExecute onExecute; /* CPU instruction execute */
|
||||
vbOnFetch onFetch; /* CPU instruction fetch */
|
||||
vbOnRead onRead; /* CPU instruction read */
|
||||
vbOnWrite onWrite; /* CPU instruction write */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Determine the lesser of two clocks figures */
|
||||
static uint32_t MinClocks(uint32_t a, uint32_t b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
/* 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
|
||||
/* Sign-extend an integer of variable width */
|
||||
static int32_t SignExtend(int32_t value, int32_t bits) {
|
||||
value &= ~((uint32_t) 0xFFFFFFFF << bits);
|
||||
bits = (int32_t) 1 << (bits - (int32_t) 1);
|
||||
return (value ^ bits) - bits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************** Sub-Module Imports *****************************/
|
||||
/******************************** Sub-Modules ********************************/
|
||||
|
||||
#include "bus.c"
|
||||
#include "cpu.c"
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
/***************************** Library Functions *****************************/
|
||||
|
||||
/* Process a simulation for a given number of clocks */
|
||||
static int sysEmulate(VB *sim, uint32_t clocks) {
|
||||
@@ -44,7 +124,7 @@ static int sysEmulate(VB *sim, uint32_t clocks) {
|
||||
;
|
||||
}
|
||||
|
||||
/* Determine how many clocks can be simulated without a breakpoint */
|
||||
/* Determine how many clocks are guaranteed to process */
|
||||
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
||||
clocks = cpuUntil(sim, clocks);
|
||||
return clocks;
|
||||
@@ -52,127 +132,121 @@ static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
||||
|
||||
|
||||
|
||||
/************************************ API ************************************/
|
||||
/******************************* API Commands ********************************/
|
||||
|
||||
/* Process a simulation */
|
||||
int vbEmulate(VB *sim, uint32_t *clocks) {
|
||||
int brk; /* A break was requested */
|
||||
uint32_t until; /* Number of clocks during which no break will occur */
|
||||
|
||||
/* Process all clocks */
|
||||
for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
|
||||
until = sysUntil (sim, *clocks);
|
||||
brk = sysEmulate(sim, until );
|
||||
/* Process one simulation */
|
||||
VBAPI int vbEmulate(VB *sim, uint32_t *clocks) {
|
||||
int brk; /* A callback requested a break */
|
||||
uint32_t until; /* Clocks guaranteed to process */
|
||||
while (*clocks != 0) {
|
||||
until = sysUntil(sim, *clocks);
|
||||
brk = sysEmulate(sim, until);
|
||||
*clocks -= until;
|
||||
if (brk)
|
||||
return brk; /* TODO: return 1 */
|
||||
}
|
||||
|
||||
return brk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process multiple simulations */
|
||||
int vbEmulateEx(VB **sims, int count, uint32_t *clocks) {
|
||||
int brk; /* A break was requested */
|
||||
uint32_t until; /* Number of clocks during which no break will occur */
|
||||
VBAPI int vbEmulateEx(VB **sims, int count, uint32_t *clocks) {
|
||||
int brk; /* A callback requested a break */
|
||||
uint32_t until; /* Clocks guaranteed to process */
|
||||
int x; /* Iterator */
|
||||
|
||||
/* Process all clocks */
|
||||
for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
|
||||
while (*clocks != 0) {
|
||||
until = *clocks;
|
||||
for (x = 0; x < count; x++)
|
||||
until = sysUntil (sims[x], until);
|
||||
for (x = 0; x < count; x++)
|
||||
brk |= sysEmulate(sims[x], until);
|
||||
}
|
||||
for (x = count - 1; x >= 0; x--)
|
||||
until = sysUntil(sims[x], until);
|
||||
|
||||
return brk;
|
||||
brk = 0;
|
||||
for (x = count - 1; x >= 0; x--)
|
||||
brk |= sysEmulate(sims[x], until);
|
||||
|
||||
*clocks -= until;
|
||||
if (brk)
|
||||
return brk; /* TODO: return 1 */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Retrieve a current breakpoint handler */
|
||||
void* vbGetCallback(VB *sim, int id) {
|
||||
/* Retrieve a callback handler */
|
||||
VBAPI void* vbGetCallback(VB *sim, int id) {
|
||||
switch (id) {
|
||||
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;
|
||||
/*case VB_EXCEPTION: return *(void **) &sim->onException;*/
|
||||
case VB_EXECUTE : return *(void **) &sim->onExecute;
|
||||
case VB_FETCH : return *(void **) &sim->onFetch;
|
||||
/*case VB_FRAME : return *(void **) &sim->onFrame;*/
|
||||
case VB_READ : return *(void **) &sim->onRead;
|
||||
case VB_WRITE : return *(void **) &sim->onWrite;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Retrieve the value of a register */
|
||||
int32_t vbGetRegister(VB *sim, int type, int id) {
|
||||
switch (type) {
|
||||
case VB_PROGRAM:
|
||||
return id < 0 || id > 31 ? 0 : sim->cpu.program[id];
|
||||
case VB_SYSTEM:
|
||||
return cpuGetSystemRegister(sim, id);
|
||||
case VB_OTHER:
|
||||
switch (id) {
|
||||
case VB_PC: return sim->cpu.pc;
|
||||
}
|
||||
}
|
||||
return 0; /* Invalid type */
|
||||
}
|
||||
|
||||
/* Retrieve a handle to the current cartridge ROM data */
|
||||
uint8_t* vbGetROM(VB *sim, uint32_t *size) {
|
||||
/* Retrieve the game pack RAM buffer */
|
||||
VBAPI void* vbGetCartRAM(VB *sim, uint32_t *size) {
|
||||
if (size != NULL)
|
||||
*size = sim->cart.romSize;
|
||||
return sim->cart.rom;
|
||||
}
|
||||
|
||||
/* Retrieve a handle to the current cartridge RAM data */
|
||||
uint8_t* vbGetSRAM(VB *sim, uint32_t *size) {
|
||||
if (size != NULL)
|
||||
*size = sim->cart.ramSize;
|
||||
*size = sim->cart.ram == NULL ? 0 : sim->cart.ramMask + 1;
|
||||
return sim->cart.ram;
|
||||
}
|
||||
|
||||
/* Prepare a simulation instance for use */
|
||||
void vbInit(VB *sim) {
|
||||
/* Retrieve the game pack ROM buffer */
|
||||
VBAPI void* vbGetCartROM(VB *sim, uint32_t *size) {
|
||||
if (size != NULL)
|
||||
*size = sim->cart.rom == NULL ? 0 : sim->cart.romMask + 1;
|
||||
return sim->cart.rom;
|
||||
}
|
||||
|
||||
/* Breakpoint handlers */
|
||||
sim->onException = NULL;
|
||||
sim->onExecute = NULL;
|
||||
sim->onFetch = NULL;
|
||||
sim->onRead = NULL;
|
||||
sim->onWrite = NULL;
|
||||
/* Retrieve the value of the program counter */
|
||||
VBAPI uint32_t vbGetProgramCounter(VB *sim) {
|
||||
return sim->cpu.pc;
|
||||
}
|
||||
|
||||
/* Game pak */
|
||||
sim->cart.ram = NULL;
|
||||
sim->cart.ramSize = 0;
|
||||
sim->cart.rom = NULL;
|
||||
sim->cart.romSize = 0;
|
||||
/* Retrieve the value in a program register */
|
||||
VBAPI int32_t vbGetProgramRegister(VB *sim, int index) {
|
||||
return index < 1 || index > 31 ? 0 : sim->cpu.program[index];
|
||||
}
|
||||
|
||||
/* Hardware reset */
|
||||
/* Retrieve the value in a system register */
|
||||
VBAPI uint32_t vbGetSystemRegister(VB *sim, int index) {
|
||||
return index < 0 || index > 31 ? 0 : cpuGetSystemRegister(sim, index);
|
||||
}
|
||||
|
||||
/* Initialize a simulation instance */
|
||||
VBAPI VB* vbInit(VB *sim) {
|
||||
sim->cart.ram = NULL;
|
||||
sim->cart.rom = NULL;
|
||||
sim->onExecute = NULL;
|
||||
sim->onFetch = NULL;
|
||||
sim->onRead = NULL;
|
||||
sim->onWrite = NULL;
|
||||
vbReset(sim);
|
||||
return sim;
|
||||
}
|
||||
|
||||
/* Read a value from memory */
|
||||
int32_t vbRead(VB *sim, uint32_t address, int type) {
|
||||
return busRead(sim, address, type);
|
||||
}
|
||||
|
||||
/* Read multiple bytes from memory */
|
||||
void vbReadEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) {
|
||||
while (length--) *buffer++ = busRead(sim, address++, VB_U8);
|
||||
/* Read a value from the memory bus */
|
||||
VBAPI int32_t vbRead(VB *sim, uint32_t address, int type) {
|
||||
int32_t value;
|
||||
if (type < 0 || type > 4)
|
||||
return 0;
|
||||
busRead(sim, address, type, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Simulate a hardware reset */
|
||||
void vbReset(VB *sim) {
|
||||
int x; /* Iterator */
|
||||
VBAPI VB* vbReset(VB *sim) {
|
||||
uint32_t x; /* Iterator */
|
||||
|
||||
/* Reset WRAM (the hardware does not do this) */
|
||||
/* WRAM (the hardware does not do this) */
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
sim->wram[x] = 0x00;
|
||||
|
||||
/* CPU (normal) */
|
||||
sim->cpu.pc = 0xFFFFFFF0;
|
||||
sim->cpu.irq = 0;
|
||||
sim->cpu.pc = 0xFFFFFFF0;
|
||||
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
||||
cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1);
|
||||
for (x = 0; x < 5; x++)
|
||||
sim->cpu.irq[x] = 0;
|
||||
|
||||
/* CPU (extra, hardware doesn't do this) */
|
||||
/* CPU (extra, hardware does not do this) */
|
||||
sim->cpu.adtre = 0x00000000;
|
||||
sim->cpu.eipc = 0x00000000;
|
||||
sim->cpu.eipsw = 0x00000000;
|
||||
@@ -184,99 +258,88 @@ void vbReset(VB *sim) {
|
||||
for (x = 0; x < 32; x++)
|
||||
sim->cpu.program[x] = 0x00000000;
|
||||
|
||||
/* CPU (internal) */
|
||||
sim->cpu.bitstring = 0;
|
||||
/* CPU (other) */
|
||||
sim->cpu.clocks = 0;
|
||||
sim->cpu.exception = 0;
|
||||
sim->cpu.stage = CPU_FETCH;
|
||||
sim->cpu.nextPC = 0xFFFFFFF0;
|
||||
sim->cpu.operation = CPU_FETCH;
|
||||
sim->cpu.step = 0;
|
||||
|
||||
return sim;
|
||||
}
|
||||
|
||||
/* Specify a breakpoint handler */
|
||||
void* vbSetCallback(VB *sim, int id, void *proc) {
|
||||
void *prev = vbGetCallback(sim, id);
|
||||
/* Specify a new callback handler */
|
||||
VBAPI void* vbSetCallback(VB *sim, int id, void *callback) {
|
||||
void *prev = NULL;
|
||||
void **target = NULL;
|
||||
|
||||
/* Select callback by ID */
|
||||
switch (id) {
|
||||
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;
|
||||
/*case VB_EXCEPTION: target = (void **) &sim->onException; break;*/
|
||||
case VB_EXECUTE : target = (void **) &sim->onExecute ; break;
|
||||
case VB_FETCH : target = (void **) &sim->onFetch ; break;
|
||||
/*case VB_FRAME : target = (void **) &sim->onFrame ; break;*/
|
||||
case VB_READ : target = (void **) &sim->onRead ; break;
|
||||
case VB_WRITE : target = (void **) &sim->onWrite ; break;
|
||||
}
|
||||
|
||||
/* Retrieve current state and update new state */
|
||||
if (target != NULL) {
|
||||
prev = *target;
|
||||
*target = callback;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* Specify a value for a register */
|
||||
int32_t vbSetRegister(VB *sim, int type, int id, int32_t value) {
|
||||
switch (type) {
|
||||
case VB_PROGRAM:
|
||||
return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value);
|
||||
case VB_SYSTEM:
|
||||
return cpuSetSystemRegister(sim, id, value, 1);
|
||||
case VB_OTHER:
|
||||
switch (id) {
|
||||
case VB_PC:
|
||||
sim->cpu.bitstring = 0;
|
||||
sim->cpu.clocks = 0;
|
||||
sim->cpu.exception = 0;
|
||||
sim->cpu.stage = CPU_FETCH;
|
||||
return sim->cpu.pc = value & 0xFFFFFFFE;
|
||||
}
|
||||
/* Specify a game pak RAM buffer */
|
||||
VBAPI int vbSetCartRAM(VB *sim, void *sram, uint32_t size) {
|
||||
if (sram != NULL) {
|
||||
if (size < 16 || size > 0x1000000 || (size & (size - 1)) != 0)
|
||||
return 1;
|
||||
sim->cart.ramMask = size - 1;
|
||||
}
|
||||
return 0; /* Invalid type or ID */
|
||||
}
|
||||
|
||||
/* Specify a cartridge ROM buffer */
|
||||
int vbSetROM(VB *sim, uint8_t *data, uint32_t size) {
|
||||
|
||||
/* Specifying no ROM */
|
||||
if (data == NULL) {
|
||||
sim->cart.rom = NULL;
|
||||
sim->cart.romSize = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Error checking */
|
||||
if (
|
||||
size < 4 ||
|
||||
size > 0x1000000 ||
|
||||
(size & (size - 1)) /* Power of 2 */
|
||||
) return 1;
|
||||
|
||||
/* Register the ROM data */
|
||||
sim->cart.rom = data;
|
||||
sim->cart.romSize = size;
|
||||
sim->cart.ram = sram;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Specify a cartridge RAM buffer */
|
||||
int vbSetSRAM(VB *sim, uint8_t *data, uint32_t size) {
|
||||
|
||||
/* Specifying no SRAM */
|
||||
if (data == NULL) {
|
||||
sim->cart.ram = NULL;
|
||||
sim->cart.ramSize = 0;
|
||||
return 0;
|
||||
/* Specify a game pak ROM buffer */
|
||||
VBAPI int vbSetCartROM(VB *sim, void *rom, uint32_t size) {
|
||||
if (rom != NULL) {
|
||||
if (size < 16 || size > 0x1000000 || (size & (size - 1)) != 0)
|
||||
return 1;
|
||||
sim->cart.romMask = size - 1;
|
||||
}
|
||||
|
||||
/* Error checking */
|
||||
if (
|
||||
size < 4 ||
|
||||
size > 0x1000000 ||
|
||||
(size & (size - 1)) /* Power of 2 */
|
||||
) return 1;
|
||||
|
||||
/* Register the SRAM data */
|
||||
sim->cart.ram = data;
|
||||
sim->cart.ramSize = size;
|
||||
sim->cart.rom = rom;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a value to memory */
|
||||
void vbWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
||||
/* Specify a new value for the program counter */
|
||||
VBAPI uint32_t vbSetProgramCounter(VB *sim, uint32_t value) {
|
||||
sim->cpu.operation = CPU_FETCH;
|
||||
sim->cpu.pc = sim->cpu.nextPC = value & 0xFFFFFFFE;
|
||||
sim->cpu.step = 0;
|
||||
return sim->cpu.pc;
|
||||
}
|
||||
|
||||
/* Specify a new value for a program register */
|
||||
VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value) {
|
||||
return index < 1 || index > 31 ? 0 : (sim->cpu.program[index] = value);
|
||||
}
|
||||
|
||||
/* Specify a new value for a system register */
|
||||
VBAPI uint32_t vbSetSystemRegister(VB *sim, int index, uint32_t value) {
|
||||
return index < 0 || index > 31 ? 0 :
|
||||
cpuSetSystemRegister(sim, index, value, 1);
|
||||
}
|
||||
|
||||
/* Determine the size of a simulation instance */
|
||||
VBAPI size_t vbSizeOf() {
|
||||
return sizeof (VB);
|
||||
}
|
||||
|
||||
/* Write a value to the memory bus */
|
||||
VBAPI int32_t vbWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
||||
if (type < 0 || type > 4)
|
||||
return 0;
|
||||
busWrite(sim, address, type, value, 1);
|
||||
}
|
||||
|
||||
/* Write multiple values to memory */
|
||||
void vbWriteEx(VB *sim, uint32_t address, uint8_t *buffer, uint32_t length) {
|
||||
while (length--) busWrite(sim, address++, VB_U8, *buffer++, 1);
|
||||
return vbRead(sim, address, type);
|
||||
}
|
||||
|
||||
@@ -15,38 +15,15 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
/**************************** Compilation Control ****************************/
|
||||
|
||||
/*
|
||||
VB_LITTLE_ENDIAN
|
||||
|
||||
Accelerates simulated memory reads and writes on hosts with little-endian
|
||||
byte ordering. If left undefined, a generic implementation is used instead.
|
||||
*/
|
||||
|
||||
/*
|
||||
VB_SIGNED_PROPAGATE
|
||||
|
||||
Accelerates sign extension by assuming the >> operator propagates the sign
|
||||
bit for signed types and does not for unsigned types. If left undefined, a
|
||||
generic implementation is used instead.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/********************************* Constants *********************************/
|
||||
|
||||
/* Data types */
|
||||
#define VB_S8 0
|
||||
#define VB_U8 1
|
||||
#define VB_S16 2
|
||||
#define VB_U16 3
|
||||
#define VB_S32 4
|
||||
|
||||
/* Register types */
|
||||
#define VB_PROGRAM 0
|
||||
#define VB_SYSTEM 1
|
||||
#define VB_OTHER 2
|
||||
/* Callback IDs */
|
||||
#define VB_EXCEPTION 0
|
||||
#define VB_EXECUTE 1
|
||||
#define VB_FETCH 2
|
||||
#define VB_FRAME 3
|
||||
#define VB_READ 4
|
||||
#define VB_WRITE 5
|
||||
|
||||
/* System registers */
|
||||
#define VB_ADTRE 25
|
||||
@@ -60,157 +37,55 @@ extern "C" {
|
||||
#define VB_PSW 5
|
||||
#define VB_TKCW 7
|
||||
|
||||
/* Other registers */
|
||||
#define VB_PC 0
|
||||
/* Memory access data types */
|
||||
#define VB_S8 0
|
||||
#define VB_U8 1
|
||||
#define VB_S16 2
|
||||
#define VB_U16 3
|
||||
#define VB_S32 4
|
||||
|
||||
/* Callbacks */
|
||||
#define VB_ONEXCEPTION 0
|
||||
#define VB_ONEXECUTE 1
|
||||
#define VB_ONFETCH 2
|
||||
#define VB_ONREAD 3
|
||||
#define VB_ONWRITE 4
|
||||
/* CPU modes */
|
||||
#define VB_ACCURACY 0
|
||||
#define VB_DEBUG 1
|
||||
#define VB_WHOLE 2
|
||||
|
||||
|
||||
|
||||
/*********************************** Types ***********************************/
|
||||
|
||||
/* Forward references */
|
||||
/* Simulation state */
|
||||
typedef struct VB VB;
|
||||
|
||||
/* Memory access descriptor */
|
||||
typedef struct {
|
||||
uint32_t address; /* Memory address */
|
||||
uint32_t clocks; /* Number of clocks taken */
|
||||
int32_t value; /* Data loaded/to store */
|
||||
uint8_t type; /* Data type */
|
||||
} VBAccess;
|
||||
|
||||
/* Exception descriptor */
|
||||
typedef struct {
|
||||
uint32_t address; /* Memory address of handler routine */
|
||||
uint16_t code; /* Cause code */
|
||||
uint8_t cancel; /* Set to cancel the exception */
|
||||
} VBException;
|
||||
|
||||
/* Instruction descriptor */
|
||||
typedef struct {
|
||||
uint32_t address; /* Memory address */
|
||||
uint16_t code[2]; /* Fetched code units */
|
||||
uint8_t size; /* Size in halfwords */
|
||||
} VBInstruction;
|
||||
|
||||
/* Breakpoint handlers */
|
||||
typedef int (*VBExceptionProc)(VB *, VBException *);
|
||||
typedef int (*VBExecuteProc )(VB *, VBInstruction *);
|
||||
typedef int (*VBFetchProc )(VB *, int, VBAccess *);
|
||||
typedef int (*VBMemoryProc )(VB *, VBAccess *);
|
||||
|
||||
/* Simulation state */
|
||||
struct VB {
|
||||
|
||||
/* Game pak */
|
||||
struct {
|
||||
uint8_t *ram; /* (S)RAM data */
|
||||
uint8_t *rom; /* ROM data */
|
||||
uint32_t ramSize; /* Size of RAM in bytes */
|
||||
uint32_t romSize; /* Size of ROM in bytes */
|
||||
} cart;
|
||||
|
||||
/* CPU */
|
||||
struct {
|
||||
|
||||
/* Main registers */
|
||||
int32_t program[32]; /* Program registers */
|
||||
uint32_t pc; /* Program counter */
|
||||
|
||||
/* System registers */
|
||||
uint32_t adtre; /* Address trap target address */
|
||||
uint32_t eipc; /* Exception return PC */
|
||||
uint32_t eipsw; /* Exception return PSW */
|
||||
uint32_t fepc; /* Duplexed exception return PC */
|
||||
uint32_t fepsw; /* Duplexed exception return PSW */
|
||||
uint32_t sr29; /* System register 29 */
|
||||
uint32_t sr31; /* System register 31 */
|
||||
|
||||
/* Exception cause register */
|
||||
struct {
|
||||
uint16_t eicc; /* Exception/interrupt cause code */
|
||||
uint16_t fecc; /* Duplexed exception cause code */
|
||||
} ecr;
|
||||
|
||||
/* Cache control word */
|
||||
struct {
|
||||
uint8_t ice; /* Instruction cache enable */
|
||||
} chcw;
|
||||
|
||||
/* Program status word */
|
||||
struct {
|
||||
uint8_t ae; /* Address trap enable */
|
||||
uint8_t cy; /* Carry */
|
||||
uint8_t ep; /* Exception pending */
|
||||
uint8_t fiv; /* Floating-point invalid operation */
|
||||
uint8_t fov; /* Floating-point overflow */
|
||||
uint8_t fpr; /* Floating point precision degradation */
|
||||
uint8_t fro; /* Floating-point reserved operand */
|
||||
uint8_t fud; /* Floating-point underflow */
|
||||
uint8_t fzd; /* Floating-point zero division */
|
||||
uint8_t i; /* Interrupt level */
|
||||
uint8_t id; /* Interrupt disable */
|
||||
uint8_t np; /* Duplexed exception pending */
|
||||
uint8_t ov; /* Overflow */
|
||||
uint8_t s; /* Sign */
|
||||
uint8_t z; /* Zero */
|
||||
} psw;
|
||||
|
||||
/* Instruction */
|
||||
struct {
|
||||
int32_t aux[9]; /* Auxiliary storage */
|
||||
void *def; /* Operation descriptor */
|
||||
uint16_t code[2]; /* Fetched code units */
|
||||
uint8_t size; /* Size in bytes */
|
||||
} inst;
|
||||
|
||||
/* Other state */
|
||||
uint32_t clocks; /* Clocks until next activity */
|
||||
uint32_t fpFlags; /* Floating-point exception flags */
|
||||
uint16_t exception; /* Current exception cause code */
|
||||
uint8_t irq[5]; /* Interrupt requests */
|
||||
uint8_t bitstring; /* Processing a bit string instruction */
|
||||
uint8_t stage; /* Pipeline stage handler */
|
||||
uint8_t step; /* General processing step index */
|
||||
} cpu;
|
||||
|
||||
/* Breakpoint hooks */
|
||||
VBExceptionProc onException; /* Exception raised */
|
||||
VBExecuteProc onExecute; /* Instruction execute */
|
||||
VBFetchProc onFetch; /* Bus read (fetch) */
|
||||
VBMemoryProc onRead; /* Bus read (execute) */
|
||||
VBMemoryProc onWrite; /* Bus write */
|
||||
|
||||
/* Other state */
|
||||
uint8_t wram[0x10000]; /* System memory */
|
||||
};
|
||||
/* 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);
|
||||
|
||||
|
||||
|
||||
/************************************ API ************************************/
|
||||
|
||||
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 int32_t vbGetRegister(VB *sim, int type, int id);
|
||||
VBAPI uint8_t* vbGetROM (VB *sim, uint32_t *size);
|
||||
VBAPI uint8_t* vbGetSRAM (VB *sim, uint32_t *size);
|
||||
VBAPI void vbInit (VB *sim);
|
||||
VBAPI int32_t vbRead (VB *sim, uint32_t address, int type);
|
||||
VBAPI void vbReadEx (VB *sim, uint32_t address, uint8_t *buffer, uint32_t length);
|
||||
VBAPI void vbReset (VB *sim);
|
||||
VBAPI void* vbSetCallback(VB *sim, int id, void *proc);
|
||||
VBAPI int32_t vbSetRegister(VB *sim, int type, int id, int32_t value);
|
||||
VBAPI int vbSetROM (VB *sim, uint8_t *data, uint32_t size);
|
||||
VBAPI int vbSetSRAM (VB *sim, uint8_t *data, uint32_t size);
|
||||
VBAPI void vbWrite (VB *sim, uint32_t address, int type, int32_t value);
|
||||
VBAPI void vbWriteEx (VB *sim, uint32_t address, uint8_t *buffer, uint32_t length);
|
||||
/******************************* 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 uint32_t vbGetProgramCounter (VB *sim);
|
||||
VBAPI int32_t vbGetProgramRegister(VB *sim, int index);
|
||||
VBAPI uint32_t vbGetSystemRegister (VB *sim, int index);
|
||||
VBAPI VB* vbInit (VB *sim);
|
||||
VBAPI int32_t vbRead (VB *sim, uint32_t address, int type);
|
||||
VBAPI VB* vbReset (VB *sim);
|
||||
VBAPI void* vbSetCallback (VB *sim, int index, void *callback);
|
||||
VBAPI int vbSetCartRAM (VB *sim, void *sram, uint32_t size);
|
||||
VBAPI int vbSetCartROM (VB *sim, void *rom, uint32_t size);
|
||||
VBAPI uint32_t vbSetProgramCounter (VB *sim, uint32_t value);
|
||||
VBAPI int32_t vbSetProgramRegister(VB *sim, int index, int32_t value);
|
||||
VBAPI uint32_t vbSetSystemRegister (VB *sim, int index, uint32_t value);
|
||||
VBAPI size_t vbSizeOf ();
|
||||
VBAPI int32_t vbWrite (VB *sim, uint32_t address, int type, int32_t value);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user