Fixing a Gitsplosion

This commit is contained in:
Guy Perfect 2023-03-10 18:44:57 -06:00
parent 17277bb354
commit 133a5e7e82
9 changed files with 1817 additions and 1862 deletions

Binary file not shown.

3177
core/cpu.c

File diff suppressed because it is too large Load Diff

441
core/vb.c
View File

@ -1,34 +1,35 @@
#ifdef VB_EXPORT #ifndef VBAPI
#define VBAPI VB_EXPORT #define VBAPI
#else
#define VBAPI
#endif #endif
/* Header includes */
#include <float.h>
#include <vb.h> #include <vb.h>
/********************************* Constants *********************************/ /***************************** Utility Functions *****************************/
/* Type sizes */ /* Select the lesser of two unsigned numbers */
static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 }; static uint32_t Min(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
/********************************** Macros ***********************************/ /**************************** Sub-Module Imports *****************************/
/* 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 "bus.c"
#include "cpu.c" #include "cpu.c"
@ -36,252 +37,246 @@ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
/***************************** Module Functions ******************************/ /***************************** Module Functions ******************************/
/* Process a simulation for some number of clocks */ /* Process a simulation for a given number of clocks */
static int sysEmulate(VB *sim, uint32_t clocks) { static int sysEmulate(VB *vb, uint32_t clocks) {
int broke; return
broke = cpuEmulate(sim, clocks); cpuEmulate(vb, clocks)
return broke; ;
} }
/* Determine the number of clocks before a break condititon could occur */ /* Determine how many clocks can be simulated without a breakpoint */
static uint32_t sysUntil(VB *sim, uint32_t clocks) { static uint32_t sysUntil(VB *vb, uint32_t clocks) {
clocks = cpuUntil(sim, clocks); clocks = cpuUntil(vb, clocks);
return clocks; return clocks;
} }
/******************************* API Functions *******************************/ /************************************ API ************************************/
/* Associate two simulations as peers, or remove an association */ /* Process a simulation */
void vbConnect(VB *sim1, VB *sim2) { int vbEmulate(VB *vb, uint32_t *clocks) {
int brk; /* A break was requested */
uint32_t until; /* Number of clocks during which no break will occur */
/* Disconnect */ /* Process all clocks */
if (sim2 == NULL) { for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
if (sim1->peer != NULL) until = sysUntil (vb, *clocks);
sim1->peer->peer = NULL; brk = sysEmulate(vb, until );
sim1->peer = NULL;
return;
} }
/* Disconnect any existing link associations */ return brk;
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 */ /* Process multiple simulations */
int vbEmulateMulti(VB **sims, int count, uint32_t *clocks) { int vbEmulateEx(VB **vbs, int count, uint32_t *clocks) {
int broke; /* The simulation requested an application break */ int brk; /* A break was requested */
uint32_t until; /* Maximum clocks before a break could happen */ uint32_t until; /* Number of clocks during which no break will occur */
int x; /* Iterator */ int x; /* Iterator */
/* Process simulations until a break condition occurs */ /* Process all clocks */
do { for (brk = 0; *clocks != 0 && !brk; *clocks -= until) {
broke = 0;
until = *clocks; until = *clocks;
for (x = 0; x < count; x++) for (x = 0; x < count; x++)
until = sysUntil (sims[x], until); until = sysUntil (vbs[x], until);
for (x = 0; x < count; x++) for (x = 0; x < count; x++)
broke |= sysEmulate(sims[x], until); brk |= sysEmulate(vbs[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 brk;
return *field;
} }
/* Retrieve the value of PC */ /* Retrieve a current breakpoint handler */
uint32_t vbGetProgramCounter(VB *sim) { void* vbGetCallback(VB *vb, int id) {
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) { switch (id) {
case VB_ADTRE: return sim->cpu.adtre; case VB_ONEXCEPTION: return *(void **)&vb->onException;
case VB_CHCW : return sim->cpu.chcw.ice << 1; case VB_ONEXECUTE : return *(void **)&vb->onExecute;
case VB_EIPC : return sim->cpu.eipc; case VB_ONFETCH : return *(void **)&vb->onFetch;
case VB_EIPSW: return sim->cpu.eipsw; case VB_ONREAD : return *(void **)&vb->onRead;
case VB_FEPC : return sim->cpu.fepc; case VB_ONWRITE : return *(void **)&vb->onWrite;
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; return NULL;
} }
/* Prepare a simulation state instance for use */ /* Retrieve the value of a register */
void vbInit(VB *sim) { int32_t vbGetRegister(VB *vb, int type, int id) {
switch (type) {
/* Breakpoint callbacks */ case VB_PROGRAM:
sim->onException = NULL; return id < 0 || id > 31 ? 0 : vb->cpu.program[id];
sim->onExecute = NULL; case VB_SYSTEM:
sim->onFetch = NULL; return cpuGetSystemRegister(vb, id);
sim->onRead = NULL; case VB_OTHER:
sim->onWrite = NULL; switch (id) {
case VB_PC: return vb->cpu.pc;
/* System */ }
sim->peer = NULL; }
return 0; /* Invalid type */
/* 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 */ /* Retrieve a handle to the current cartridge ROM data */
int32_t vbRead(VB *sim, uint32_t address, int type, int debug) { uint8_t* vbGetROM(VB *vb, uint32_t *size) {
return type < 0 || type >= (int) sizeof TYPE_SIZES ? 0 : if (size != NULL)
busRead(sim, address, type, debug); *size = vb->cart.romSize;
return vb->cart.rom;
}
/* Retrieve a handle to the current cartridge RAM data */
uint8_t* vbGetSRAM(VB *vb, uint32_t *size) {
if (size != NULL)
*size = vb->cart.ramSize;
return vb->cart.ram;
}
/* Prepare a simulation instance for use */
void vbInit(VB *vb) {
/* Breakpoint handlers */
vb->onException = NULL;
vb->onExecute = NULL;
vb->onFetch = NULL;
vb->onRead = NULL;
vb->onWrite = NULL;
/* Game pak */
vb->cart.ram = NULL;
vb->cart.ramSize = 0;
vb->cart.rom = NULL;
vb->cart.romSize = 0;
/* Hardware reset */
vbReset(vb);
}
/* Read a value from memory */
int32_t vbRead(VB *vb, uint32_t address, int type) {
return busRead(vb, address, type);
}
/* Read multiple bytes from memory */
void vbReadEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) {
while (length--) *buffer++ = busRead(vb, address++, VB_U8);
} }
/* Simulate a hardware reset */ /* Simulate a hardware reset */
void vbReset(VB *sim) { void vbReset(VB *vb) {
uint32_t x; /* Iterator */ int x; /* Iterator */
/* Subsystem components */ /* Reset WRAM (the hardware does not do this) */
cpuReset(sim);
/* WRAM (the hardware does not do this) */
for (x = 0; x < 0x10000; x++) for (x = 0; x < 0x10000; x++)
sim->wram[x] = 0x00; vb->wram[x] = 0x00;
/* CPU (normal) */
vb->cpu.pc = 0xFFFFFFF0;
cpuSetSystemRegister(vb, VB_ECR, 0x0000FFF0, 1);
cpuSetSystemRegister(vb, VB_PSW, 0x00008000, 1);
for (x = 0; x < 5; x++)
vb->cpu.irq[x] = 0;
/* CPU (extra, hardware doesn't do this) */
vb->cpu.adtre = 0x00000000;
vb->cpu.eipc = 0x00000000;
vb->cpu.eipsw = 0x00000000;
vb->cpu.fepc = 0x00000000;
vb->cpu.fepsw = 0x00000000;
vb->cpu.sr29 = 0x00000000;
vb->cpu.sr31 = 0x00000000;
cpuSetSystemRegister(vb, VB_CHCW, 0x00000000, 1);
for (x = 0; x < 32; x++)
vb->cpu.program[x] = 0x00000000;
/* CPU (internal) */
vb->cpu.bitstring = 0;
vb->cpu.clocks = 0;
vb->cpu.exception = 0;
vb->cpu.stage = CPU_FETCH;
vb->cpu.step = 0;
} }
/* Specify a breakpoint callback */ /* Specify a breakpoint handler */
void* vbSetCallback(VB *sim, int type, void *callback) { void* vbSetCallback(VB *vb, int id, void *proc) {
void **field; /* Pointer to field within simulation */ void *prev = vbGetCallback(vb, id);
void *prev; /* Previous value within field */ switch (id) {
case VB_ONEXCEPTION: *(void **)&vb->onException = proc; break;
/* Select the field to update */ case VB_ONEXECUTE : *(void **)&vb->onExecute = proc; break;
switch (type) { case VB_ONFETCH : *(void **)&vb->onFetch = proc; break;
case VB_ONEXCEPTION: field = (void *) &sim->onException; break; case VB_ONREAD : *(void **)&vb->onRead = proc; break;
case VB_ONEXECUTE : field = (void *) &sim->onExecute ; break; case VB_ONWRITE : *(void **)&vb->onWrite = proc; 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; return prev;
} }
/* Specify a new value for PC */ /* Specify a value for a register */
uint32_t vbSetProgramCounter(VB *sim, uint32_t value) { int32_t vbSetRegister(VB *vb, int type, int id, int32_t value) {
value &= 0xFFFFFFFE; switch (type) {
sim->cpu.busWait = 0; case VB_PROGRAM:
sim->cpu.causeCode = 0; return id < 1 || id > 31 ? 0 : (vb->cpu.program[id] = value);
sim->cpu.clocks = 0; case VB_SYSTEM:
sim->cpu.fetch = 0; return cpuSetSystemRegister(vb, id, value, 1);
sim->cpu.pc = value; case VB_OTHER:
sim->cpu.state = CPU_FETCH; switch (id) {
sim->cpu.substring = 0; case VB_PC:
return value; vb->cpu.bitstring = 0;
vb->cpu.clocks = 0;
vb->cpu.exception = 0;
vb->cpu.stage = CPU_FETCH;
return vb->cpu.pc = value & 0xFFFFFFFE;
}
}
return 0; /* Invalid type or ID */
} }
/* Specify a new value for a program register */ /* Specify a cartridge ROM buffer */
int32_t vbSetProgramRegister(VB *sim, int id, int32_t value) { int vbSetROM(VB *vb, uint8_t *data, uint32_t size) {
return id < 1 || id > 31 ? 0 : (sim->cpu.program[id] = value);
}
/* Supply a ROM buffer */ /* Specifying no ROM */
int vbSetROM(VB *sim, void *rom, uint32_t size) { if (data == NULL) {
vb->cart.rom = NULL;
/* Check the buffer size */ vb->cart.romSize = 0;
if (size < 1024 || size > 0x1000000 || ((size - 1) & size) != 0)
return 0; return 0;
}
/* Configure the ROM buffer */ /* Error checking */
sim->cart.rom = (uint8_t *) rom; if (
sim->cart.romSize = size; size < 4 ||
return 1; size > 0x1000000 ||
(size & (size - 1)) /* Power of 2 */
) return 1;
/* Register the ROM data */
vb->cart.rom = data;
vb->cart.romSize = size;
return 0;
} }
/* Supply an SRAM buffer */ /* Specify a cartridge RAM buffer */
int vbSetSRAM(VB *sim, void *sram, uint32_t size) int vbSetSRAM(VB *vb, uint8_t *data, uint32_t size) {
/* Specifying no SRAM */
if (data == NULL) {
vb->cart.ram = NULL;
vb->cart.ramSize = 0;
return 0;
}
/* Error checking */
if (
size < 4 ||
size > 0x1000000 ||
(size & (size - 1)) /* Power of 2 */
) return 1;
/* Register the SRAM data */
vb->cart.ram = data;
vb->cart.ramSize = size;
return 0;
}
/* Write a value to memory */
void vbWrite(VB *vb, uint32_t address, int type, int32_t value) {
busWrite(vb, address, type, value, 1);
}
/* Write multiple values to memory */
void vbWriteEx(VB *vb, uint32_t address, uint8_t *buffer, uint32_t length) {
while (length--) busWrite(vb, address++, VB_U8, *buffer++, 1);
}

BIN
core/vb.h

Binary file not shown.

View File

@ -1,4 +1,4 @@
Copyright (C) 2022 Guy Perfect Copyright (C) 2023 Guy Perfect
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages

BIN
makefile

Binary file not shown.

View File

@ -146,6 +146,15 @@ class Core {
}, [], options); }, [], options);
} }
// Retrieve the value of a program register
getSystemRegister(sim, id, options) {
return this.message({
command: "getProgramRegister",
id : id,
sim : sim.pointer
}, [], options);
}
// Retrieve the value of a system register // Retrieve the value of a system register
getSystemRegister(sim, id, options) { getSystemRegister(sim, id, options) {
return this.message({ return this.message({
@ -200,10 +209,10 @@ class Core {
} }
// Specify a value for a program register // Specify a value for a program register
setProgramRegister(sim, index, value, options) { setProgramRegister(sim, id, value, options) {
return this.message({ return this.message({
command: "setProgramRegister", command: "setProgramRegister",
index : index, id : id,
sim : sim.pointer, sim : sim.pointer,
value : value value : value
}, [], options); }, [], options);

View File

@ -119,11 +119,11 @@ class CoreThread {
let program = new Int32Array (32); let program = new Int32Array (32);
let system = new Uint32Array(32); let system = new Uint32Array(32);
for (let x = 0; x < 32; x++) { for (let x = 0; x < 32; x++) {
program[x] = this.vbGetProgramRegister(msg.sim, x); program[x] = this.vbGetRegister(msg.sim, 0, x);
system [x] = this.vbGetSystemRegister (msg.sim, x); system [x] = this.vbGetRegister(msg.sim, 1, x);
} }
return { return {
pc : this.vbGetProgramCounter(msg.sim) >>> 0, pc : this.vbGetRegister(msg.sim, 2, 0) >>> 0,
program : program, program : program,
system : system, system : system,
transfers: [ program.buffer, system.buffer ] transfers: [ program.buffer, system.buffer ]
@ -132,12 +132,17 @@ class CoreThread {
// Retrieve the value of PC // Retrieve the value of PC
getProgramCounter(msg) { getProgramCounter(msg) {
return { value: this.vbGetProgramCounter(msg.sim) >>> 0 }; return { value: this.vbGetRegister(msg.sim, 2, 0) >>> 0 };
}
// Retrieve the value of a program register
getProgramRegister(msg) {
return { value: this.vbGetRegister(msg.sim, 0, msg.id) };
} }
// Retrieve the value of a system register // Retrieve the value of a system register
getSystemRegister(msg) { getSystemRegister(msg) {
return { value: this.vbGetSystemRegister(msg.sim, msg.id) >>> 0 }; return { value: this.vbGetRegister(msg.sim, 1, msg.id) >>> 0 };
} }
// Read multiple bytes from memory // Read multiple bytes from memory
@ -214,19 +219,19 @@ class CoreThread {
let pcs = new Array(msg.sims.length); let pcs = new Array(msg.sims.length);
for (let x = 0; x < msg.sims.length; x++) for (let x = 0; x < msg.sims.length; x++)
pcs[x] = this.vbGetProgramCounter(msg.sims[x]) >>> 0; pcs[x] = this.vbGetRegister(msg.sims[x], 2, 0) >>> 0;
return { pcs: pcs }; return { pcs: pcs };
} }
// Specify a value for the program counter // Specify a value for the program counter
setProgramCounter(msg) { setProgramCounter(msg) {
return { value: this.vbSetProgramCounter(msg.sim, msg.value) >>> 0 }; return { value: this.vbSetRegister(msg.sim, 2, 0, msg.value) >>> 0 };
} }
// Specify a value for a program register // Specify a value for a program register
setProgramRegister(msg) { setProgramRegister(msg) {
return {value:this.vbSetProgramRegister(msg.sim,msg.index,msg.value)}; return { value: this.vbSetRegister(msg.sim, 0, msg.id, msg.value) };
} }
// Specify a cartridge ROM buffer // Specify a cartridge ROM buffer
@ -258,7 +263,7 @@ class CoreThread {
// Specify a value for a system register // Specify a value for a system register
setSystemRegister(msg) { setSystemRegister(msg) {
return {value:this.vbSetSystemRegister(msg.sim,msg.id,msg.value)>>>0}; return {value:this.vbSetRegister(msg.sim, 1, msg.id, msg.value)>>>0};
} }
// Execute the current instruction // Execute the current instruction
@ -271,7 +276,7 @@ class CoreThread {
let pcs = new Array(msg.sims.length); let pcs = new Array(msg.sims.length);
for (let x = 0; x < msg.sims.length; x++) for (let x = 0; x < msg.sims.length; x++)
pcs[x] = this.vbGetProgramCounter(msg.sims[x]) >>> 0; pcs[x] = this.vbGetRegister(msg.sims[x], 2, 0) >>> 0;
return { pcs: pcs }; return { pcs: pcs };
} }

View File

@ -41,22 +41,22 @@ EMSCRIPTEN_KEEPALIVE int PointerSize() {
////////////////////////////// Debugger Commands ////////////////////////////// ////////////////////////////// Debugger Commands //////////////////////////////
// Execute until the following instruction // Execute until the following instruction
uint32_t RunNextAddress; static uint32_t RunNextAddress;
static int RunNextFetch(VB *vb, int fetch, VBAccess *access) { static int RunNextFetch(VB *vb, int fetch, VBAccess *access) {
return access->address == RunNextAddress; return access->address == RunNextAddress;
} }
static int RunNextExecute(VB *vb, VBInstruction *inst) { static int RunNextExecute(VB *vb, VBInstruction *inst) {
RunNextAddress = inst->address + inst->size; RunNextAddress = inst->address + inst->size;
vbSetOnExecute(vb, NULL); vbSetCallback(vb, VB_ONEXECUTE, NULL);
vbSetOnFetch(vb, &RunNextFetch); vbSetCallback(vb, VB_ONFETCH, &RunNextFetch);
return 0; return 0;
} }
EMSCRIPTEN_KEEPALIVE void RunNext(VB **vbs, int count) { EMSCRIPTEN_KEEPALIVE void RunNext(VB **vbs, int count) {
uint32_t clocks = 20000000; // 1s uint32_t clocks = 20000000; // 1s
vbSetOnExecute(vbs[0], &RunNextExecute); vbSetCallback(vbs[0], VB_ONEXECUTE, &RunNextExecute);
vbEmulateEx (vbs, count, &clocks); vbEmulateEx (vbs, count, &clocks);
vbSetOnExecute(vbs[0], NULL); vbSetCallback(vbs[0], VB_ONEXECUTE, NULL);
vbSetOnFetch (vbs[0], NULL); vbSetCallback(vbs[0], VB_ONFETCH , NULL);
} }
// Execute the current instruction // Execute the current instruction
@ -72,7 +72,8 @@ static int SingleStepFetch(VB *vb, int fetch, VBAccess *access) {
EMSCRIPTEN_KEEPALIVE void SingleStep(VB **vbs, int count) { EMSCRIPTEN_KEEPALIVE void SingleStep(VB **vbs, int count) {
uint32_t clocks = 20000000; // 1s uint32_t clocks = 20000000; // 1s
SingleStepBreak = vbs[0]->cpu.stage == 0 ? 0 : 1; SingleStepBreak = vbs[0]->cpu.stage == 0 ? 0 : 1;
vbSetOnFetch(vbs[0], &SingleStepFetch); vbSetCallback(vbs[0], VB_ONFETCH, &SingleStepFetch);
vbEmulateEx (vbs, count, &clocks); vbEmulateEx (vbs, count, &clocks);
vbSetOnFetch(vbs[0], NULL); vbSetCallback(vbs[0], VB_ONEXECUTE, NULL);
vbSetCallback(vbs[0], VB_ONFETCH , NULL);
} }