Preliminary CPU implementation
This commit is contained in:
parent
70f0f2a318
commit
94486ecf02
|
@ -291,7 +291,7 @@ let run = async function() {
|
|||
if (!file.name.endsWith(".woff2"))
|
||||
continue;
|
||||
let family = "/" + file.name;
|
||||
family = family.substring(family.lastIndexOf("/") + 1, family.length - 6);
|
||||
family = family.substring(family.lastIndexOf("/")+1, family.length-6);
|
||||
let font = new FontFace(family, file.data);
|
||||
await font.load();
|
||||
document.fonts.add(font);
|
||||
|
|
62
core/bus.c
62
core/bus.c
|
@ -1,6 +1,10 @@
|
|||
/* This file is included into vb.c and cannot be compiled on its own. */
|
||||
#ifdef VBAPI
|
||||
|
||||
|
||||
|
||||
/***************************** Utility Functions *****************************/
|
||||
|
||||
/* Read a data unit from a memory buffer */
|
||||
static int32_t busReadMemory(uint8_t *mem, int type) {
|
||||
|
||||
|
@ -28,31 +32,6 @@ static int32_t busReadMemory(uint8_t *mem, int type) {
|
|||
|
||||
}
|
||||
|
||||
/* Read a data unit from the bus */
|
||||
static int32_t busRead(VB *emu, uint32_t address, int type, int debug) {
|
||||
|
||||
/* Force address alignment */
|
||||
address &= ~((uint32_t) TYPE_SIZES[type] - 1);
|
||||
|
||||
/* Process by address range */
|
||||
switch (address >> 24 & 7) {
|
||||
case 0 : return 0; /* VIP */
|
||||
case 1 : debug = debug; return 0; /* VSU */
|
||||
case 2 : return 0; /* Miscellaneous hardware */
|
||||
case 3 : return 0; /* Unmapped */
|
||||
case 4 : return 0; /* Game pak expansion */
|
||||
case 5 : return /* WRAM */
|
||||
busReadMemory(&emu->wram[address & 0xFFFF], type);
|
||||
case 6 : return emu->cart.sram == NULL ? 0 : /* Game pak RAM */
|
||||
busReadMemory(&emu->cart.sram
|
||||
[address & (emu->cart.sramSize - 1)], type);
|
||||
default: return emu->cart.rom == NULL ? 0 : /* Game pak ROM */
|
||||
busReadMemory(&emu->cart.rom
|
||||
[address & (emu->cart.romSize - 1)], type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write a data unit to a memory buffer */
|
||||
static void busWriteMemory(uint8_t *mem, int type, int32_t value) {
|
||||
|
||||
|
@ -77,7 +56,36 @@ static void busWriteMemory(uint8_t *mem, int type, int32_t value) {
|
|||
}
|
||||
mem[0] = value;
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
|
||||
/* Read a data unit from the bus */
|
||||
static int32_t busRead(VB *emu, uint32_t address, int type, int debug) {
|
||||
|
||||
/* Force address alignment */
|
||||
address &= ~((uint32_t) TYPE_SIZES[type] - 1);
|
||||
|
||||
/* Process by address range */
|
||||
switch (address >> 24 & 7) {
|
||||
case 0 : return 0; /* VIP */
|
||||
case 1 : debug = debug; return 0; /* VSU */
|
||||
case 2 : return 0; /* Miscellaneous hardware */
|
||||
case 3 : return 0; /* Unmapped */
|
||||
case 4 : return 0; /* Game pak expansion */
|
||||
case 5 : return /* WRAM */
|
||||
busReadMemory(&emu->wram[address & 0xFFFF], type);
|
||||
case 6 : return emu->cart.sram == NULL ? 0 : /* Game pak RAM */
|
||||
busReadMemory(&emu->cart.sram
|
||||
[address & (emu->cart.sramSize - 1)], type);
|
||||
default: return emu->cart.rom == NULL ? 0 : /* Game pak ROM */
|
||||
busReadMemory(&emu->cart.rom
|
||||
[address & (emu->cart.romSize - 1)], type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Write a data unit to the bus */
|
||||
|
@ -110,4 +118,6 @@ static void busWrite(
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* VBAPI */
|
||||
|
|
1589
core/cpu.c
1589
core/cpu.c
File diff suppressed because it is too large
Load Diff
144
core/vb.c
144
core/vb.c
|
@ -1,6 +1,7 @@
|
|||
#define VBAPI
|
||||
|
||||
/* Header includes */
|
||||
#include <float.h>
|
||||
#include <vb.h>
|
||||
|
||||
|
||||
|
@ -15,7 +16,7 @@ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
/********************************** Macros ***********************************/
|
||||
|
||||
/* Sign-extend a value of some number of bits to 32 bits */
|
||||
#define SignExtend(v,b) ( (v) | (((v) & 1 << b - 1) ? ~(int32_t)0 << b : 0) )
|
||||
#define SignExtend(v,b) ((v) | (((v) & ((1<<(b)) - 1)) ? ~(int32_t)0<<(b) : 0))
|
||||
|
||||
|
||||
|
||||
|
@ -23,11 +24,78 @@ static const uint8_t TYPE_SIZES[] = { 1, 1, 2, 2, 4 };
|
|||
|
||||
/* Component includes */
|
||||
#include "bus.c"
|
||||
#include "cpu.c"
|
||||
|
||||
|
||||
|
||||
/***************************** Module Functions ******************************/
|
||||
|
||||
/* Process a simulation for some number of clocks */
|
||||
static int sysEmulate(VB *emu, uint32_t clocks) {
|
||||
int broke;
|
||||
broke = cpuEmulate(emu, clocks);
|
||||
return broke;
|
||||
}
|
||||
|
||||
/* Determine the number of clocks before a break condititon could occur */
|
||||
static uint32_t sysUntil(VB *emu, uint32_t clocks) {
|
||||
clocks = cpuUntil(emu, clocks);
|
||||
return clocks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************* API Functions *******************************/
|
||||
|
||||
/* Associate two simulations as peers */
|
||||
void vbConnect(VB *emu1, VB *emu2) {
|
||||
|
||||
/* Disconnect any existing link associations */
|
||||
if (emu1->peer != NULL && emu1->peer != emu2)
|
||||
emu1->peer->peer = NULL;
|
||||
if (emu2->peer != NULL && emu2->peer != emu1)
|
||||
emu2->peer->peer = NULL;
|
||||
|
||||
/* Link the two simulations */
|
||||
emu1->peer = emu2;
|
||||
emu2->peer = emu1;
|
||||
}
|
||||
|
||||
/* Disassociate linked peers */
|
||||
void vbDisconnect(VB *emu) {
|
||||
if (emu->peer != NULL)
|
||||
emu->peer->peer = NULL;
|
||||
emu->peer = NULL;
|
||||
}
|
||||
|
||||
/* Process one or two simulations */
|
||||
int vbEmulate(VB *emu1, VB *emu2, uint32_t *clocks) {
|
||||
int broke; /* The simulation requested an application break */
|
||||
uint32_t until; /* Maximum clocks before a break could happen */
|
||||
|
||||
/* Processing one simulaiton */
|
||||
if (emu2 == NULL) {
|
||||
do {
|
||||
until = sysUntil (emu1, *clocks);
|
||||
broke = sysEmulate(emu1, until );
|
||||
*clocks -= until;
|
||||
} while (!broke && *clocks > 0);
|
||||
}
|
||||
|
||||
/* Processing two simulations */
|
||||
else {
|
||||
do {
|
||||
until = sysUntil (emu1, *clocks);
|
||||
until = sysUntil (emu2, until );
|
||||
broke = sysEmulate(emu1, until );
|
||||
broke |= sysEmulate(emu2, until );
|
||||
*clocks -= until;
|
||||
} while (!broke && *clocks > 0);
|
||||
}
|
||||
|
||||
return broke;
|
||||
}
|
||||
|
||||
/* Retrieve the value of PC */
|
||||
uint32_t vbGetProgramCounter(VB *emu, int type) {
|
||||
switch (type) {
|
||||
|
@ -97,13 +165,23 @@ uint32_t vbGetSystemRegister(VB *emu, int id) {
|
|||
/* Prepare a simulation state instance for use */
|
||||
void vbInit(VB *emu) {
|
||||
|
||||
/* Breakpoint callbacks */
|
||||
emu->onException = NULL;
|
||||
emu->onExecute = NULL;
|
||||
emu->onFetch = NULL;
|
||||
emu->onRead = NULL;
|
||||
emu->onWrite = NULL;
|
||||
|
||||
/* System */
|
||||
emu->peer = NULL;
|
||||
|
||||
/* Cartridge */
|
||||
emu->cart.rom = NULL;
|
||||
emu->cart.romSize = 0;
|
||||
emu->cart.sram = NULL;
|
||||
emu->cart.sramSize = 0;
|
||||
|
||||
/* All others */
|
||||
/* Everything else */
|
||||
vbReset(emu);
|
||||
}
|
||||
|
||||
|
@ -118,7 +196,7 @@ void vbReset(VB *emu) {
|
|||
uint32_t x; /* Iterator */
|
||||
|
||||
/* CPU registers */
|
||||
emu->cpu.pc = 0xFFFFFFF0;
|
||||
vbSetProgramCounter(emu, 0xFFFFFFF0);
|
||||
vbSetSystemRegister(emu, VB_ECR, 0x0000FFF0);
|
||||
vbSetSystemRegister(emu, VB_PSW, 0x00008000);
|
||||
|
||||
|
@ -132,8 +210,19 @@ void vbReset(VB *emu) {
|
|||
emu->cpu.fepsw = 0x00000000;
|
||||
emu->cpu.sr29 = 0x00000000;
|
||||
emu->cpu.sr31 = 0x00000000;
|
||||
emu->cpu.pcFrom = 0xFFFFFFF0;
|
||||
emu->cpu.pcTo = 0xFFFFFFF0;
|
||||
|
||||
/* History tracking */
|
||||
emu->cpu.eipcFrom = 0xFFFFFFF0;
|
||||
emu->cpu.eipcTo = 0xFFFFFFF0;
|
||||
emu->cpu.fepcFrom = 0xFFFFFFF0;
|
||||
emu->cpu.fepcTo = 0xFFFFFFF0;
|
||||
emu->cpu.pcFrom = 0xFFFFFFF0;
|
||||
emu->cpu.pcTo = 0xFFFFFFF0;
|
||||
|
||||
/* Other CPU state */
|
||||
emu->cpu.state = CPU_FETCH;
|
||||
for (x = 0; x < 5; x++)
|
||||
emu->cpu.irq[x] = 0;
|
||||
|
||||
/* WRAM (the hardware does not do this) */
|
||||
for (x = 0; x < 0x10000; x++)
|
||||
|
@ -142,9 +231,11 @@ void vbReset(VB *emu) {
|
|||
|
||||
/* Specify a new value for PC */
|
||||
uint32_t vbSetProgramCounter(VB *emu, uint32_t value) {
|
||||
value &= 0xFFFFFFFE;
|
||||
emu->cpu.pc = value;
|
||||
/* Set stage to fecth=0 */
|
||||
value &= 0xFFFFFFFE;
|
||||
emu->cpu.fetch = 0;
|
||||
emu->cpu.pc = value;
|
||||
emu->cpu.state = CPU_FETCH;
|
||||
emu->cpu.substring = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -181,42 +272,7 @@ int vbSetSRAM(VB *emu, void *sram, uint32_t size) {
|
|||
|
||||
/* Specify a new value for a system register */
|
||||
uint32_t vbSetSystemRegister(VB *emu, int id, uint32_t value) {
|
||||
switch (id) {
|
||||
case VB_ADTRE: return emu->cpu.adtre = value & 0xFFFFFFFE;
|
||||
case VB_EIPC : return emu->cpu.eipc = value & 0xFFFFFFFE;
|
||||
case VB_EIPSW: return emu->cpu.eipsw = value & 0x000FF3FF;
|
||||
case VB_FEPC : return emu->cpu.fepc = value & 0xFFFFFFFE;
|
||||
case VB_FEPSW: return emu->cpu.fepsw = value & 0x000FF3FF;
|
||||
case VB_PIR : return 0x00005346;
|
||||
case VB_TKCW : return 0x000000E0;
|
||||
case 29 : return emu->cpu.sr29 = value & 0x00000001;
|
||||
case 31 : return emu->cpu.sr31 = value;
|
||||
case VB_CHCW :
|
||||
emu->cpu.chcw.ice = value >> 1 & 1;
|
||||
return value & 0x00000002;
|
||||
case VB_ECR :
|
||||
emu->cpu.ecr.fecc = value >> 16;
|
||||
emu->cpu.ecr.eicc = value;
|
||||
return value;
|
||||
case VB_PSW :
|
||||
emu->cpu.psw.i = value >> 16 & 15;
|
||||
emu->cpu.psw.np = value >> 15 & 1;
|
||||
emu->cpu.psw.ep = value >> 14 & 1;
|
||||
emu->cpu.psw.ae = value >> 13 & 1;
|
||||
emu->cpu.psw.id = value >> 12 & 1;
|
||||
emu->cpu.psw.fro = value >> 9 & 1;
|
||||
emu->cpu.psw.fiv = value >> 8 & 1;
|
||||
emu->cpu.psw.fzd = value >> 7 & 1;
|
||||
emu->cpu.psw.fov = value >> 6 & 1;
|
||||
emu->cpu.psw.fud = value >> 5 & 1;
|
||||
emu->cpu.psw.fpr = value >> 4 & 1;
|
||||
emu->cpu.psw.cy = value >> 3 & 1;
|
||||
emu->cpu.psw.ov = value >> 2 & 1;
|
||||
emu->cpu.psw.s = value >> 1 & 1;
|
||||
emu->cpu.psw.z = value & 1;
|
||||
return value & 0x000FF3FF;
|
||||
}
|
||||
return 0;
|
||||
return cpuSetSystemRegister(emu, id, value, 1);
|
||||
}
|
||||
|
||||
/* Write a data unit to the bus */
|
||||
|
|
76
core/vb.h
76
core/vb.h
|
@ -18,11 +18,12 @@ extern "C" {
|
|||
/********************************* Constants *********************************/
|
||||
|
||||
/* Memory access types */
|
||||
#define VB_S8 0
|
||||
#define VB_U8 1
|
||||
#define VB_S16 2
|
||||
#define VB_U16 3
|
||||
#define VB_S32 4
|
||||
#define VB_CANCEL -1
|
||||
#define VB_S8 0
|
||||
#define VB_U8 1
|
||||
#define VB_S16 2
|
||||
#define VB_U16 3
|
||||
#define VB_S32 4
|
||||
|
||||
/* System register IDs */
|
||||
#define VB_ADTRE 25
|
||||
|
@ -45,8 +46,38 @@ extern "C" {
|
|||
|
||||
/*********************************** Types ***********************************/
|
||||
|
||||
/* Simulation state */
|
||||
/* Forward references */
|
||||
typedef struct VB VB;
|
||||
|
||||
/* Memory access */
|
||||
typedef struct {
|
||||
uint32_t address; /* Bus address being accessed */
|
||||
uint32_t clocks; /* Number of clocks required to complete */
|
||||
int32_t value; /* Value read (callback's responsibility) or to write */
|
||||
int8_t type; /* Data type of value */
|
||||
} VB_ACCESS;
|
||||
|
||||
/* CPU instruction */
|
||||
typedef struct {
|
||||
|
||||
/* Public fields */
|
||||
uint32_t address; /* Bus address */
|
||||
uint16_t bits[2]; /* Binary instruction code */
|
||||
uint8_t size; /* Size in bytes of the instruction */
|
||||
|
||||
/* Implementation fields */
|
||||
int32_t aux[2]; /* Auxiliary storage for CAXI and bit strings */
|
||||
uint8_t id; /* Internal operation ID */
|
||||
} VB_INSTRUCTION;
|
||||
|
||||
/* Breakpoint callbacks */
|
||||
typedef int (*VB_EXCEPTIONPROC)(VB *, uint16_t);
|
||||
typedef int (*VB_EXECUTEPROC )(VB *, VB_INSTRUCTION *);
|
||||
typedef int (*VB_FETCHPROC )(VB *, int, VB_ACCESS *);
|
||||
typedef int (*VB_READPROC )(VB *, VB_ACCESS *);
|
||||
typedef int (*VB_WRITEPROC )(VB *, VB_ACCESS *);
|
||||
|
||||
/* Simulation state */
|
||||
struct VB {
|
||||
|
||||
/* Game pak */
|
||||
|
@ -101,17 +132,37 @@ struct VB {
|
|||
|
||||
/* Other registers */
|
||||
uint32_t pc; /* Program counter */
|
||||
uint32_t pcFrom; /* Source of most recent jump */
|
||||
uint32_t pcTo; /* Destination of most recent jump */
|
||||
int32_t program[32]; /* program registers */
|
||||
|
||||
/* History tracking */
|
||||
uint32_t eipcFrom; /* Source of most recent jump */
|
||||
uint32_t eipcTo; /* Destination of most recent jump */
|
||||
uint32_t fepcFrom; /* Source of most recent jump */
|
||||
uint32_t fepcTo; /* Destination of most recent jump */
|
||||
uint32_t pcFrom; /* Source of most recent jump */
|
||||
uint32_t pcTo; /* Destination of most recent jump */
|
||||
|
||||
/* Other fields */
|
||||
uint32_t clocks; /* Clocks until next action */
|
||||
uint8_t fetch; /* Index of fetch unit */
|
||||
uint8_t state; /* Operations state */
|
||||
VB_ACCESS access; /* Memory access descriptor */
|
||||
VB_INSTRUCTION inst; /* Instruction descriptor */
|
||||
uint8_t irq[5]; /* Interrupt request lines */
|
||||
uint8_t busWait; /* Waiting on a memory access */
|
||||
uint16_t causeCode; /* Exception cause code */
|
||||
uint32_t clocks; /* Clocks until next action */
|
||||
int16_t fetch; /* Index of fetch unit */
|
||||
uint8_t state; /* Operations state */
|
||||
uint8_t substring; /* A bit string operation is in progress */
|
||||
} cpu;
|
||||
|
||||
/* Breakpoint callbacks */
|
||||
VB_EXCEPTIONPROC onException; /* CPU exception */
|
||||
VB_EXECUTEPROC onExecute; /* Instruction execute */
|
||||
VB_FETCHPROC onFetch; /* Instruction fetch */
|
||||
VB_READPROC onRead; /* Memory read */
|
||||
VB_WRITEPROC onWrite; /* Memory write */
|
||||
|
||||
/* Other fields */
|
||||
VB *peer; /* Communications peer */
|
||||
uint8_t wram[0x10000]; /* Main memory */
|
||||
};
|
||||
|
||||
|
@ -119,6 +170,9 @@ struct VB {
|
|||
|
||||
/**************************** Function Prototypes ****************************/
|
||||
|
||||
VBAPI void vbConnect (VB *emu1, VB *emu2);
|
||||
VBAPI void vbDisconnect (VB *emu);
|
||||
VBAPI int vbEmulate (VB *emu1, VB *emu2, uint32_t *clocks);
|
||||
VBAPI uint32_t vbGetProgramCounter (VB *emu, int type);
|
||||
VBAPI int32_t vbGetProgramRegister (VB *emu, int id);
|
||||
VBAPI void* vbGetROM (VB *emu, uint32_t *size);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (C) 2021 Planet Virtual Boy
|
||||
Copyright (C) 2021 Guy Perfect
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
|
Loading…
Reference in New Issue