pvbemu/wasm/wasm.c

140 lines
4.0 KiB
C

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <emscripten/emscripten.h>
#include <vb.h>
//////////////////////////////// Static Memory ////////////////////////////////
static VB sims[2]; // Hardware simulations
/////////////////////////////// Module Commands ///////////////////////////////
// Proxy for free()
EMSCRIPTEN_KEEPALIVE void Free(void* ptr) {
free(ptr);
}
// Proxy for malloc()
EMSCRIPTEN_KEEPALIVE void* Malloc(int size) {
return malloc(size);
}
// Read multiple data units from the bus
EMSCRIPTEN_KEEPALIVE void ReadBuffer(
int sim, uint8_t *dest, uint32_t address, uint32_t size, int debug) {
for (; size > 0; address++, size--, dest++)
*dest = vbRead(&sims[sim], address, VB_U8, debug);
}
// Execute one instruction
static uint32_t SingleStepPC;
static int SingleStepProc(VB *emu, int fetch, VB_ACCESS *acc) {
if (fetch == 0 && vbGetProgramCounter(emu, VB_PC) != SingleStepPC)
return 1;
acc->value = vbRead(emu, acc->address, acc->type, 0);
return 0;
}
EMSCRIPTEN_KEEPALIVE void SingleStep(int sim) {
uint32_t clocks = 400000; // 1/50s
VB *emu = &sims[sim];
SingleStepPC = vbGetProgramCounter(emu, VB_PC);
emu->onFetch = &SingleStepProc;
vbEmulate(emu, NULL, &clocks);
emu->onFetch = NULL;
}
// Attempt to execute until the following instruction
static uint32_t RunNextPC;
static int RunNextProcB(VB *emu, int fetch, VB_ACCESS *acc) {
if (fetch == 0 && vbGetProgramCounter(emu, VB_PC) == RunNextPC)
return 1;
acc->value = vbRead(emu, acc->address, acc->type, 0);
return 0;
}
static int RunNextProcA(VB *emu, VB_INSTRUCTION *inst) {
RunNextPC = vbGetProgramCounter(emu, VB_PC) + inst->size;
emu->onExecute = NULL;
emu->onFetch = &RunNextProcB;
return 0;
}
EMSCRIPTEN_KEEPALIVE void RunNext(int sim) {
uint32_t clocks = 400000; // 1/50s
VB *emu = &sims[sim];
emu->onExecute = &RunNextProcA;
vbEmulate(emu, NULL, &clocks);
emu->onFetch = NULL;
}
//////////////////////////////// Core Commands ////////////////////////////////
// Retrieve the value of PC
EMSCRIPTEN_KEEPALIVE uint32_t GetProgramCounter(int sim, int type) {
return vbGetProgramCounter(&sims[sim], type);
}
// Retrieve the value of a program register
EMSCRIPTEN_KEEPALIVE int32_t GetProgramRegister(int sim, int id) {
return vbGetProgramRegister(&sims[sim], id);
}
// Retrieve the value of a system register
EMSCRIPTEN_KEEPALIVE uint32_t GetSystemRegister(int sim, int id) {
return vbGetSystemRegister(&sims[sim], id);
}
// Prepare simulation state instances for use
EMSCRIPTEN_KEEPALIVE void Init() {
vbInit(&sims[0]);
vbInit(&sims[1]);
}
// Read a data unit from the bus
EMSCRIPTEN_KEEPALIVE int32_t Read(int sim,uint32_t address,int type,int debug){
return vbRead(&sims[sim], address, type, debug);
}
// Simulate a hardware reset
EMSCRIPTEN_KEEPALIVE void Reset(int sim) {
vbReset(&sims[sim]);
}
// Specify a new value for PC
EMSCRIPTEN_KEEPALIVE uint32_t SetProgramCounter(int sim, uint32_t value) {
return vbSetProgramCounter(&sims[sim], value);
}
// Specify a new value for a program register
EMSCRIPTEN_KEEPALIVE int32_t SetProgramRegister(int sim,int id,int32_t value) {
return vbSetProgramRegister(&sims[sim], id, value);
}
// Supply a ROM buffer
EMSCRIPTEN_KEEPALIVE int SetROM(int sim, void *rom, uint32_t size) {
free(vbGetROM(&sims[sim], NULL));
return vbSetROM(&sims[sim], rom, size);
}
// Supply an SRAM buffer
EMSCRIPTEN_KEEPALIVE int SetSRAM(int sim, void *sram, uint32_t size) {
free(vbGetSRAM(&sims[sim], NULL));
return vbSetSRAM(&sims[sim], sram, size);
}
// Specify a new value for a system register
EMSCRIPTEN_KEEPALIVE uint32_t SetSystemRegister(int sim,int id,uint32_t value){
return vbSetSystemRegister(&sims[sim], id, value);
}
// Write a data unit to the bus
EMSCRIPTEN_KEEPALIVE void Write(
int sim, uint32_t address, int type, int32_t value, int debug) {
vbWrite(&sims[sim], address, type, value, debug);
}