Callback symbols, VIP read/write
This commit is contained in:
parent
767675eb42
commit
c91eb0785f
16
core/bus.c
16
core/bus.c
|
@ -80,6 +80,10 @@ static void busWriteBuffer(uint8_t *data, int type, int32_t value) {
|
||||||
|
|
||||||
/***************************** Library Functions *****************************/
|
/***************************** Library Functions *****************************/
|
||||||
|
|
||||||
|
/* Forward references */
|
||||||
|
static void vipRead (VB *, uint32_t, int, int32_t *);
|
||||||
|
static void vipWrite(VB *, uint32_t, int, int32_t, int);
|
||||||
|
|
||||||
/* Read a typed value from the simulation bus */
|
/* Read a typed value from the simulation bus */
|
||||||
static void busRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
static void busRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||||
|
|
||||||
|
@ -89,7 +93,11 @@ static void busRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||||
|
|
||||||
/* Process by address range */
|
/* Process by address range */
|
||||||
switch (address >> 24) {
|
switch (address >> 24) {
|
||||||
case 0: break; /* VIP */
|
|
||||||
|
case 0: /* VIP */
|
||||||
|
vipRead(sim, address, type, value);
|
||||||
|
break;
|
||||||
|
|
||||||
case 1: break; /* VSU */
|
case 1: break; /* VSU */
|
||||||
case 2: break; /* Misc. I/O */
|
case 2: break; /* Misc. I/O */
|
||||||
case 3: break; /* Unmapped */
|
case 3: break; /* Unmapped */
|
||||||
|
@ -125,7 +133,11 @@ static void busWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
|
||||||
|
|
||||||
/* Process by address range */
|
/* Process by address range */
|
||||||
switch (address >> 24) {
|
switch (address >> 24) {
|
||||||
case 0: break; /* VIP */
|
|
||||||
|
case 0: /* VIP */
|
||||||
|
vipWrite(sim, address, type, value, debug);
|
||||||
|
break;
|
||||||
|
|
||||||
case 1: break; /* VSU */
|
case 1: break; /* VSU */
|
||||||
case 2: break; /* Misc. I/O */
|
case 2: break; /* Misc. I/O */
|
||||||
case 3: break; /* Unmapped */
|
case 3: break; /* Unmapped */
|
||||||
|
|
51
core/cpu.c
51
core/cpu.c
|
@ -212,8 +212,8 @@ static const uint8_t OPDEFS_FLOATENDO[] = {
|
||||||
#ifndef VB_DIRECT_EXCEPTION
|
#ifndef VB_DIRECT_EXCEPTION
|
||||||
#define VB_ON_EXCEPTION sim->onException
|
#define VB_ON_EXCEPTION sim->onException
|
||||||
#else
|
#else
|
||||||
extern int vbxOnException(VB *, uint16_t *);
|
extern int VB_DIRECT_EXCEPTION(VB *, uint16_t *);
|
||||||
#define VB_ON_EXCEPTION sim->onException
|
#define VB_ON_EXCEPTION VB_DIRECT_EXCEPTION
|
||||||
#endif
|
#endif
|
||||||
static int cpuOnException(VB *sim, uint16_t *cause) {
|
static int cpuOnException(VB *sim, uint16_t *cause) {
|
||||||
return sim->onException != NULL && VB_ON_EXCEPTION(sim, cause);
|
return sim->onException != NULL && VB_ON_EXCEPTION(sim, cause);
|
||||||
|
@ -224,8 +224,8 @@ static int cpuOnException(VB *sim, uint16_t *cause) {
|
||||||
#ifndef VB_DIRECT_EXECUTE
|
#ifndef VB_DIRECT_EXECUTE
|
||||||
#define VB_ON_EXECUTE sim->onExecute
|
#define VB_ON_EXECUTE sim->onExecute
|
||||||
#else
|
#else
|
||||||
extern int vbxOnExecute(VB *, uint32_t, const uint16_t *, int);
|
extern int VB_DIRECT_EXECUTE(VB *, uint32_t, const uint16_t *, int);
|
||||||
#define VB_ON_EXECUTE vbxOnExecute
|
#define VB_ON_EXECUTE VB_DIRECT_EXECUTE
|
||||||
#endif
|
#endif
|
||||||
static int cpuOnExecute(VB *sim) {
|
static int cpuOnExecute(VB *sim) {
|
||||||
return
|
return
|
||||||
|
@ -239,8 +239,8 @@ static int cpuOnExecute(VB *sim) {
|
||||||
#ifndef VB_DIRECT_READ
|
#ifndef VB_DIRECT_READ
|
||||||
#define VB_ON_READ sim->onRead
|
#define VB_ON_READ sim->onRead
|
||||||
#else
|
#else
|
||||||
extern int vbxOnRead(VB *, uint32_t, int, int32_t *, uint32_t *);
|
extern int VB_DIRECT_READ(VB *, uint32_t, int, int32_t *, uint32_t *);
|
||||||
#define VB_ON_READ vbxOnRead
|
#define VB_ON_READ VB_DIRECT_READ
|
||||||
#endif
|
#endif
|
||||||
static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||||
uint32_t cycles = 4; /* TODO: Research this */
|
uint32_t cycles = 4; /* TODO: Research this */
|
||||||
|
@ -264,8 +264,8 @@ static int cpuRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||||
#ifndef VB_DIRECT_FETCH
|
#ifndef VB_DIRECT_FETCH
|
||||||
#define VB_ON_FETCH sim->onFetch
|
#define VB_ON_FETCH sim->onFetch
|
||||||
#else
|
#else
|
||||||
extern int vbxOnFetch(VB *, int, uint32_t, int32_t *, uint32_t *);
|
extern int VB_DIRECT_FETCH(VB *, int, uint32_t, int32_t *, uint32_t *);
|
||||||
#define VB_ON_FETCH vbxOnFetch
|
#define VB_ON_FETCH VB_DIRECT_FETCH
|
||||||
#endif
|
#endif
|
||||||
static int cpuReadFetch(VB *sim, int fetch, uint32_t address, int32_t *value) {
|
static int cpuReadFetch(VB *sim, int fetch, uint32_t address, int32_t *value) {
|
||||||
uint32_t cycles = 0;
|
uint32_t cycles = 0;
|
||||||
|
@ -289,8 +289,8 @@ static int cpuReadFetch(VB *sim, int fetch, uint32_t address, int32_t *value) {
|
||||||
#ifndef VB_DIRECT_WRITE
|
#ifndef VB_DIRECT_WRITE
|
||||||
#define VB_ON_WRITE sim->onWrite
|
#define VB_ON_WRITE sim->onWrite
|
||||||
#else
|
#else
|
||||||
extern int vbxOnWrite(VB *, uint32_t, int, int32_t *, uint32_t *, int *);
|
extern int VB_DIRECT_WRITE(VB *,uint32_t,int,int32_t *,uint32_t *,int *);
|
||||||
#define VB_ON_WRITE vbxOnWrite
|
#define VB_ON_WRITE VB_DIRECT_WRITE
|
||||||
#endif
|
#endif
|
||||||
static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
static int cpuWrite(VB *sim, uint32_t address, int type, int32_t value) {
|
||||||
int cancel = 0;
|
int cancel = 0;
|
||||||
|
@ -1792,6 +1792,37 @@ static int cpuEmulate(VB *sim, uint32_t clocks) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Simulate a hardware reset */
|
||||||
|
static void cpuReset(VB *sim) {
|
||||||
|
uint32_t x; /* Iterator */
|
||||||
|
|
||||||
|
/* Normal */
|
||||||
|
sim->cpu.exception = 0;
|
||||||
|
sim->cpu.halt = 0;
|
||||||
|
sim->cpu.irq = 0;
|
||||||
|
sim->cpu.pc = 0xFFFFFFF0;
|
||||||
|
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
||||||
|
cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1);
|
||||||
|
|
||||||
|
/* Extra (the hardware does not do this) */
|
||||||
|
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);
|
||||||
|
for (x = 0; x < 32; x++)
|
||||||
|
sim->cpu.program[x] = 0x00000000;
|
||||||
|
|
||||||
|
/* Other */
|
||||||
|
sim->cpu.clocks = 0;
|
||||||
|
sim->cpu.nextPC = 0xFFFFFFF0;
|
||||||
|
sim->cpu.operation = CPU_FETCH;
|
||||||
|
sim->cpu.step = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine how many clocks are guaranteed to process */
|
/* Determine how many clocks are guaranteed to process */
|
||||||
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
|
static uint32_t cpuUntil(VB *sim, uint32_t clocks) {
|
||||||
return sim->cpu.halt || sim->cpu.clocks > clocks ?
|
return sim->cpu.halt || sim->cpu.clocks > clocks ?
|
||||||
|
|
86
core/vb.c
86
core/vb.c
|
@ -87,7 +87,55 @@ struct VB {
|
||||||
int step; /* Operation sub-task ID */
|
int step; /* Operation sub-task ID */
|
||||||
} cpu;
|
} cpu;
|
||||||
|
|
||||||
/* Other system state */
|
/* VIP */
|
||||||
|
struct {
|
||||||
|
|
||||||
|
/* CTA */
|
||||||
|
struct {
|
||||||
|
uint8_t cta_l; /* Left column table index */
|
||||||
|
uint8_t cta_r; /* Right column table index */
|
||||||
|
} cta;
|
||||||
|
|
||||||
|
/* Display control */
|
||||||
|
struct {
|
||||||
|
uint8_t disp; /* Display enabled */
|
||||||
|
uint8_t fclk; /* Frame clock signal high */
|
||||||
|
uint8_t l0bsy; /* Displaying left frame buffer 0 */
|
||||||
|
uint8_t l1bsy; /* Displaying left frame buffer 1 */
|
||||||
|
uint8_t lock; /* Lock CTA */
|
||||||
|
uint8_t r0bsy; /* Displaying right frame buffer 0 */
|
||||||
|
uint8_t r1bsy; /* Displaying right frame buffer 1*/
|
||||||
|
uint8_t re; /* Memory refresh enabled */
|
||||||
|
uint8_t scanrdy; /* Mirrors are stable */
|
||||||
|
uint8_t synce; /* Servo enabled */
|
||||||
|
} dpctrl;
|
||||||
|
|
||||||
|
/* Drawing control */
|
||||||
|
struct {
|
||||||
|
uint8_t f0bsy; /* Drawing into frame buffer 0 */
|
||||||
|
uint8_t f1bsy; /* Drawing into frame buffer 1 */
|
||||||
|
uint8_t overtime; /* Drawing extends into display interval */
|
||||||
|
uint8_t sbcmp; /* Vertical output position compare */
|
||||||
|
uint8_t sbcount; /* Current vertical output position */
|
||||||
|
uint8_t sbout; /* Drawing specified vertical output position */
|
||||||
|
uint8_t xpen; /* Drawing enabled */
|
||||||
|
} xpctrl;
|
||||||
|
|
||||||
|
/* Control state */
|
||||||
|
uint8_t bkcol; /* Backdrop color */
|
||||||
|
uint8_t brtRest[4]; /* Brightness and REST */
|
||||||
|
uint8_t frmcyc; /* Game frame control */
|
||||||
|
uint8_t gplt[4][4]; /* Background palettes */
|
||||||
|
uint16_t intenb; /* Interrupts enabled */
|
||||||
|
uint16_t intpnd; /* Interrupts pending */
|
||||||
|
uint8_t jplt[4][4]; /* Object palettes */
|
||||||
|
uint16_t spt[4]; /* Object control */
|
||||||
|
|
||||||
|
/* Other state */
|
||||||
|
uint8_t vram[0x40000]; /* Video memory */
|
||||||
|
} vip;
|
||||||
|
|
||||||
|
/* Other state */
|
||||||
uint8_t wram[0x10000]; /* System RAM */
|
uint8_t wram[0x10000]; /* System RAM */
|
||||||
|
|
||||||
/* Application data */
|
/* Application data */
|
||||||
|
@ -120,6 +168,7 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
|
||||||
|
|
||||||
#include "bus.c"
|
#include "bus.c"
|
||||||
#include "cpu.c"
|
#include "cpu.c"
|
||||||
|
#include "vip.c"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,13 +177,15 @@ static int32_t SignExtend(int32_t value, int32_t bits) {
|
||||||
/* Process a simulation for a given number of clocks */
|
/* Process a simulation for a given number of clocks */
|
||||||
static int sysEmulate(VB *sim, uint32_t clocks) {
|
static int sysEmulate(VB *sim, uint32_t clocks) {
|
||||||
return
|
return
|
||||||
cpuEmulate(sim, clocks)
|
cpuEmulate(sim, clocks) |
|
||||||
|
vipEmulate(sim, clocks)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine how many clocks are guaranteed to process */
|
/* Determine how many clocks are guaranteed to process */
|
||||||
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
static uint32_t sysUntil(VB *sim, uint32_t clocks) {
|
||||||
clocks = cpuUntil(sim, clocks);
|
clocks = cpuUntil(sim, clocks);
|
||||||
|
clocks = vipUntil(sim, clocks);
|
||||||
return clocks;
|
return clocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,38 +310,15 @@ VBAPI int32_t vbRead(VB *sim, uint32_t address, int type) {
|
||||||
|
|
||||||
/* Simulate a hardware reset */
|
/* Simulate a hardware reset */
|
||||||
VBAPI VB* vbReset(VB *sim) {
|
VBAPI VB* vbReset(VB *sim) {
|
||||||
uint32_t x; /* Iterator */
|
int x; /* Iterator */
|
||||||
|
|
||||||
/* WRAM (the hardware does not do this) */
|
/* WRAM (the hardware does not do this) */
|
||||||
for (x = 0; x < 0x10000; x++)
|
for (x = 0; x < 0x10000; x++)
|
||||||
sim->wram[x] = 0x00;
|
sim->wram[x] = 0x00;
|
||||||
|
|
||||||
/* CPU (normal) */
|
/* Components */
|
||||||
sim->cpu.exception = 0;
|
cpuReset(sim);
|
||||||
sim->cpu.halt = 0;
|
vipReset(sim);
|
||||||
sim->cpu.irq = 0;
|
|
||||||
sim->cpu.pc = 0xFFFFFFF0;
|
|
||||||
cpuSetSystemRegister(sim, VB_ECR, 0x0000FFF0, 1);
|
|
||||||
cpuSetSystemRegister(sim, VB_PSW, 0x00008000, 1);
|
|
||||||
|
|
||||||
/* CPU (extra, hardware does not do this) */
|
|
||||||
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);
|
|
||||||
for (x = 0; x < 32; x++)
|
|
||||||
sim->cpu.program[x] = 0x00000000;
|
|
||||||
|
|
||||||
/* CPU (other) */
|
|
||||||
sim->cpu.clocks = 0;
|
|
||||||
sim->cpu.nextPC = 0xFFFFFFF0;
|
|
||||||
sim->cpu.operation = CPU_FETCH;
|
|
||||||
sim->cpu.step = 0;
|
|
||||||
|
|
||||||
return sim;
|
return sim;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,10 @@ extern "C" {
|
||||||
VB_DIRECT_READ
|
VB_DIRECT_READ
|
||||||
VB_DIRECT_WRITE
|
VB_DIRECT_WRITE
|
||||||
|
|
||||||
Implements callbacks as direct function calls with names in the form of
|
Implements callbacks as direct function calls with names given by the above
|
||||||
vbxOn<callback>() with the same prototypes as the regular function pointer
|
symbols in their respective situations. If left undefined, the function
|
||||||
callbacks. If left undefined, the function pointers are used.
|
pointer in the simulation state is used. Whether or not to call the callback
|
||||||
|
is still determined by whether the function pointer is NULL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -0,0 +1,415 @@
|
||||||
|
/* This file is included into vb.c and cannot be compiled on its own. */
|
||||||
|
#ifdef VBAPI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************** Module Functions ******************************/
|
||||||
|
|
||||||
|
/* Read a palette */
|
||||||
|
static int32_t vipReadPalette(uint8_t *entries) {
|
||||||
|
return entries[3] << 6 | entries[2] << 4 | entries[1] << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a palette */
|
||||||
|
static void vipWritePalette(uint8_t *entries, int32_t mask, int32_t value) {
|
||||||
|
if (mask & 0x00FF)
|
||||||
|
return;
|
||||||
|
entries[3] = value >> 6 & 3;
|
||||||
|
entries[2] = value >> 4 & 3;
|
||||||
|
entries[1] = value >> 2 & 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a typed value from an I/O register */
|
||||||
|
static int32_t vipReadIO(VB *sim, uint32_t address, int type) {
|
||||||
|
int mask; /* Byte access mask */
|
||||||
|
int32_t value; /* Return value */
|
||||||
|
|
||||||
|
/* Adjustments by type */
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case VB_S32: /* Word */
|
||||||
|
return vipReadIO(sim, address, VB_U16) |
|
||||||
|
(uint32_t) vipReadIO(sim, address + 2, VB_U16) << 16;
|
||||||
|
|
||||||
|
case VB_S8: /* Byte */
|
||||||
|
case VB_U8:
|
||||||
|
mask = 0x00FF << ((address & 1) << 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VB_S16: /* Halfword */
|
||||||
|
case VB_U16:
|
||||||
|
mask = 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Access by register */
|
||||||
|
switch (address >> 1) {
|
||||||
|
|
||||||
|
case 0x5F800>>1: /* INTPND */
|
||||||
|
value = sim->vip.intpnd;
|
||||||
|
break;
|
||||||
|
case 0x5F802>>1: /* INTENB */
|
||||||
|
value = sim->vip.intenb;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F820>>1: /* DPSTTS */
|
||||||
|
value =
|
||||||
|
(int32_t) sim->vip.dpctrl.lock << 10 |
|
||||||
|
(int32_t) sim->vip.dpctrl.synce << 9 |
|
||||||
|
(int32_t) sim->vip.dpctrl.re << 8 |
|
||||||
|
(int32_t) sim->vip.dpctrl.fclk << 7 |
|
||||||
|
(int32_t) sim->vip.dpctrl.scanrdy << 6 |
|
||||||
|
(int32_t) sim->vip.dpctrl.r1bsy << 5 |
|
||||||
|
(int32_t) sim->vip.dpctrl.l1bsy << 4 |
|
||||||
|
(int32_t) sim->vip.dpctrl.r0bsy << 3 |
|
||||||
|
(int32_t) sim->vip.dpctrl.l0bsy << 2 |
|
||||||
|
(int32_t) sim->vip.dpctrl.disp << 1
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F824>>1: /* BRTA */
|
||||||
|
value = sim->vip.brtRest[0];
|
||||||
|
break;
|
||||||
|
case 0x5F826>>1: /* BRTB */
|
||||||
|
value = sim->vip.brtRest[1];
|
||||||
|
break;
|
||||||
|
case 0x5F828>>1: /* BRTC */
|
||||||
|
value = sim->vip.brtRest[2];
|
||||||
|
break;
|
||||||
|
case 0x5F82A>>1: /* REST */
|
||||||
|
value = sim->vip.brtRest[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F82E>>1: /* FRMCYC */
|
||||||
|
value = sim->vip.frmcyc;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F830>>1: /* CTA */
|
||||||
|
value = (int32_t) sim->vip.cta.cta_r << 8 | sim->vip.cta.cta_l;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F840>>1: /* XPSTTS */
|
||||||
|
value =
|
||||||
|
(int32_t) sim->vip.xpctrl.sbout << 15 |
|
||||||
|
(int32_t) sim->vip.xpctrl.sbcount << 8 |
|
||||||
|
(int32_t) sim->vip.xpctrl.overtime << 4 |
|
||||||
|
(int32_t) sim->vip.xpctrl.f1bsy << 3 |
|
||||||
|
(int32_t) sim->vip.xpctrl.f0bsy << 2 |
|
||||||
|
(int32_t) sim->vip.xpctrl.xpen << 1
|
||||||
|
;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F844>>1: /* VER */
|
||||||
|
value = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F848>>1: /* SPT0 */
|
||||||
|
value = sim->vip.spt[0];
|
||||||
|
break;
|
||||||
|
case 0x5F84A>>1: /* SPT1 */
|
||||||
|
value = sim->vip.spt[1];
|
||||||
|
break;
|
||||||
|
case 0x5F84C>>1: /* SPT2 */
|
||||||
|
value = sim->vip.spt[2];
|
||||||
|
break;
|
||||||
|
case 0x5F84E>>1: /* SPT3 */
|
||||||
|
value = sim->vip.spt[3];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F860>>1: /* GPLT0 */
|
||||||
|
value = vipReadPalette(sim->vip.gplt[0]);
|
||||||
|
break;
|
||||||
|
case 0x5F862>>1: /* GPLT1 */
|
||||||
|
value = vipReadPalette(sim->vip.gplt[1]);
|
||||||
|
break;
|
||||||
|
case 0x5F864>>1: /* GPLT2 */
|
||||||
|
value = vipReadPalette(sim->vip.gplt[2]);
|
||||||
|
break;
|
||||||
|
case 0x5F866>>1: /* GPLT3 */
|
||||||
|
value = vipReadPalette(sim->vip.gplt[3]);
|
||||||
|
break;
|
||||||
|
case 0x5F868>>1: /* JPLT0 */
|
||||||
|
value = vipReadPalette(sim->vip.jplt[0]);
|
||||||
|
break;
|
||||||
|
case 0x5F86A>>1: /* JPLT1 */
|
||||||
|
value = vipReadPalette(sim->vip.jplt[1]);
|
||||||
|
break;
|
||||||
|
case 0x5F86C>>1: /* JPLT2 */
|
||||||
|
value = vipReadPalette(sim->vip.jplt[2]);
|
||||||
|
break;
|
||||||
|
case 0x5F86E>>1: /* JPLT3 */
|
||||||
|
value = vipReadPalette(sim->vip.jplt[3]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F870>>1: /* BKCOL */
|
||||||
|
value = sim->vip.bkcol;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Unmapped */
|
||||||
|
default: value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select byte bits as necessary */
|
||||||
|
return
|
||||||
|
mask == 0x00FF ? value & 0x00FF :
|
||||||
|
mask == 0xFF00 ? value >> 8 :
|
||||||
|
value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a typed value to an I/O register */
|
||||||
|
static void vipWriteIO(
|
||||||
|
VB *sim, uint32_t address, int type, int32_t value, int debug) {
|
||||||
|
int mask; /* Byte access mask */
|
||||||
|
|
||||||
|
/* Adjustments by type */
|
||||||
|
switch (type) {
|
||||||
|
|
||||||
|
case VB_S32: /* Word */
|
||||||
|
vipWriteIO(sim, address , VB_U16, value , debug);
|
||||||
|
vipWriteIO(sim, address + 2, VB_U16, value >> 16, debug);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case VB_S8: /* Byte */
|
||||||
|
case VB_U8:
|
||||||
|
|
||||||
|
/* Select which half of the register to access */
|
||||||
|
if (debug) {
|
||||||
|
mask = (address & 1) << 3;
|
||||||
|
value = (value & 0x00FF) << mask;
|
||||||
|
mask = 0xFF00 >> mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to a halfword access */
|
||||||
|
if ((address & 1) != 0)
|
||||||
|
value = (value & 0x00FF) << 8;
|
||||||
|
|
||||||
|
/* Fallthrough */
|
||||||
|
default: /* Halfword */
|
||||||
|
mask = 0x0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Access by register */
|
||||||
|
switch (address >> 1) {
|
||||||
|
|
||||||
|
case 0x5F802>>1: /* INTENB */
|
||||||
|
sim->vip.intenb = (sim->vip.intenb & mask) | (value & 0xE01F);
|
||||||
|
break;
|
||||||
|
case 0x5F804>>1: /* INTCLR */
|
||||||
|
sim->vip.intpnd &= ~value;
|
||||||
|
if (sim->vip.intpnd == 0)
|
||||||
|
sim->cpu.irq &= ~0x0010;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F822>>1: /* DPCTRL */
|
||||||
|
if ((mask & 0xFF00) == 0) {
|
||||||
|
sim->vip.dpctrl.lock = value >> 10 & 1;
|
||||||
|
sim->vip.dpctrl.synce = value >> 9 & 1;
|
||||||
|
sim->vip.dpctrl.re = value >> 8 & 1;
|
||||||
|
}
|
||||||
|
if ((mask & 0x00FF) == 0) {
|
||||||
|
sim->vip.dpctrl.disp = value >> 1 & 1;
|
||||||
|
/* if (value & 1) {} TODO: DPRST */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F824>>1: /* BRTA */
|
||||||
|
sim->vip.brtRest[0] = (sim->vip.brtRest[0] & mask) | value;
|
||||||
|
break;
|
||||||
|
case 0x5F826>>1: /* BRTB */
|
||||||
|
sim->vip.brtRest[1] = (sim->vip.brtRest[1] & mask) | value;
|
||||||
|
break;
|
||||||
|
case 0x5F828>>1: /* BRTC */
|
||||||
|
sim->vip.brtRest[2] = (sim->vip.brtRest[2] & mask) | value;
|
||||||
|
break;
|
||||||
|
case 0x5F82A>>1: /* REST */
|
||||||
|
sim->vip.brtRest[3] = (sim->vip.brtRest[3] & mask) | value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F82E>>1: /* FRMCYC */
|
||||||
|
sim->vip.frmcyc = (sim->vip.frmcyc & mask) | (value & 15);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F830>>1: /* CTA */
|
||||||
|
if ((mask & 0xFF00) == 0)
|
||||||
|
sim->vip.cta.cta_r = value >> 8;
|
||||||
|
if ((mask & 0x00FF) == 0)
|
||||||
|
sim->vip.cta.cta_l = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F842>>1: /* XPCTRL */
|
||||||
|
if ((mask & 0xFF00) == 0)
|
||||||
|
sim->vip.xpctrl.sbcmp = value >> 8 & 31;
|
||||||
|
if ((mask & 0x00FF) == 0) {
|
||||||
|
sim->vip.xpctrl.xpen = value >> 1 & 1;
|
||||||
|
/* if (value & 1) TODO: XPRST */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F848>>1: /* SPT0 */
|
||||||
|
sim->vip.spt[0] = (sim->vip.spt[0]&mask) | (value&0x03FF&~mask);
|
||||||
|
break;
|
||||||
|
case 0x5F84A>>1: /* SPT1 */
|
||||||
|
sim->vip.spt[1] = (sim->vip.spt[1]&mask) | (value&0x03FF&~mask);
|
||||||
|
break;
|
||||||
|
case 0x5F84C>>1: /* SPT2 */
|
||||||
|
sim->vip.spt[2] = (sim->vip.spt[2]&mask) | (value&0x03FF&~mask);
|
||||||
|
break;
|
||||||
|
case 0x5F84E>>1: /* SPT3 */
|
||||||
|
sim->vip.spt[3] = (sim->vip.spt[3]&mask) | (value&0x03FF&~mask);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F860>>1: /* GPLT0 */
|
||||||
|
vipWritePalette(sim->vip.gplt[0], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F862>>1: /* GPLT1 */
|
||||||
|
vipWritePalette(sim->vip.gplt[1], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F864>>1: /* GPLT2 */
|
||||||
|
vipWritePalette(sim->vip.gplt[2], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F866>>1: /* GPLT3 */
|
||||||
|
vipWritePalette(sim->vip.gplt[3], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F868>>1: /* JPLT0 */
|
||||||
|
vipWritePalette(sim->vip.jplt[0], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F86A>>1: /* JPLT1 */
|
||||||
|
vipWritePalette(sim->vip.jplt[1], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F86C>>1: /* JPLT2 */
|
||||||
|
vipWritePalette(sim->vip.jplt[2], mask, value);
|
||||||
|
break;
|
||||||
|
case 0x5F86E>>1: /* JPLT3 */
|
||||||
|
vipWritePalette(sim->vip.jplt[3], mask, value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5F870>>1: /* BKCOL */
|
||||||
|
sim->vip.bkcol = (sim->vip.bkcol & mask) | (value & 3 * ~mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***************************** Library Functions *****************************/
|
||||||
|
|
||||||
|
/* Process component */
|
||||||
|
static int vipEmulate(VB *sim, uint32_t clocks) {
|
||||||
|
(void) sim;
|
||||||
|
(void) clocks;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a typed value from the VIP bus */
|
||||||
|
static void vipRead(VB *sim, uint32_t address, int type, int32_t *value) {
|
||||||
|
|
||||||
|
/* Working variables */
|
||||||
|
address &= 0x0007FFFF;
|
||||||
|
|
||||||
|
/* VRAM */
|
||||||
|
if (address < 0x40000) {
|
||||||
|
*value = busReadBuffer(&sim->vip.vram[address], type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmapped */
|
||||||
|
else if (address < 0x5E000)
|
||||||
|
*value = 0;
|
||||||
|
|
||||||
|
/* I/O register */
|
||||||
|
else if (address < 0x60000)
|
||||||
|
*value = vipReadIO(sim, address, type);
|
||||||
|
|
||||||
|
/* Unmapped */
|
||||||
|
if (address < 0x78000)
|
||||||
|
*value = 0;
|
||||||
|
|
||||||
|
/* Mirrors of character memory */
|
||||||
|
else {
|
||||||
|
address = 0x06000 | (address << 2 & 0x18000) | (address & 0x01FFF);
|
||||||
|
*value = busReadBuffer(&sim->vip.vram[address], type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simulate a hardware reset */
|
||||||
|
static void vipReset(VB *sim) {
|
||||||
|
int x, y; /* Iterators */
|
||||||
|
|
||||||
|
/* Normal */
|
||||||
|
sim->vip.dpctrl.disp = 0;
|
||||||
|
sim->vip.dpctrl.re = 0;
|
||||||
|
sim->vip.dpctrl.synce = 0;
|
||||||
|
sim->vip.intenb = 0x0000;
|
||||||
|
sim->vip.xpctrl.xpen = 0;
|
||||||
|
|
||||||
|
/* Extra (the hardware does not do this) */
|
||||||
|
sim->vip.bkcol = 0;
|
||||||
|
sim->vip.cta.cta_l = 0;
|
||||||
|
sim->vip.cta.cta_r = 0;
|
||||||
|
sim->vip.frmcyc = 0;
|
||||||
|
sim->vip.intpnd = 0x0000;
|
||||||
|
sim->vip.dpctrl.fclk = 0;
|
||||||
|
sim->vip.dpctrl.l0bsy = 0;
|
||||||
|
sim->vip.dpctrl.l1bsy = 0;
|
||||||
|
sim->vip.dpctrl.lock = 0;
|
||||||
|
sim->vip.dpctrl.r0bsy = 0;
|
||||||
|
sim->vip.dpctrl.r1bsy = 0;
|
||||||
|
sim->vip.dpctrl.scanrdy = 0;
|
||||||
|
sim->vip.xpctrl.f0bsy = 0;
|
||||||
|
sim->vip.xpctrl.f1bsy = 0;
|
||||||
|
sim->vip.xpctrl.overtime = 0;
|
||||||
|
sim->vip.xpctrl.sbcmp = 0;
|
||||||
|
sim->vip.xpctrl.sbcount = 0;
|
||||||
|
sim->vip.xpctrl.sbout = 0;
|
||||||
|
for (x = 0; x < 4; x++) {
|
||||||
|
sim->vip.brtRest[x] = 0;
|
||||||
|
sim->vip.spt [x] = 0;
|
||||||
|
for (y = 0; y < 4; y++) {
|
||||||
|
sim->vip.gplt[x][y] = 0;
|
||||||
|
sim->vip.jplt[x][y] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine how many clocks are guaranteed to process */
|
||||||
|
static uint32_t vipUntil(VB *sim, uint32_t clocks) {
|
||||||
|
(void) sim;
|
||||||
|
return clocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a typed value to the VIP bus */
|
||||||
|
static void vipWrite(VB*sim,uint32_t address,int type,int32_t value,int debug){
|
||||||
|
(void) debug;
|
||||||
|
|
||||||
|
/* Working variables */
|
||||||
|
address &= 0x0007FFFF;
|
||||||
|
|
||||||
|
/* VRAM */
|
||||||
|
if (address < 0x40000)
|
||||||
|
busWriteBuffer(&sim->vip.vram[address], type, value);
|
||||||
|
|
||||||
|
/* Unmapped */
|
||||||
|
else if (address < 0x5E000)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* I/O register */
|
||||||
|
else if (address < 0x60000)
|
||||||
|
vipWriteIO(sim, address, type, value, debug);
|
||||||
|
|
||||||
|
/* Unmapped */
|
||||||
|
else if (address < 0x78000)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Mirrors of character memory */
|
||||||
|
else {
|
||||||
|
address = 0x06000 | (address << 2 & 0x18000) | (address & 0x01FFF);
|
||||||
|
busWriteBuffer(&sim->vip.vram[address], type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* VBAPI */
|
12
makefile
12
makefile
|
@ -1,7 +1,7 @@
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
help:
|
help:
|
||||||
@echo
|
@echo
|
||||||
@echo "Shrooms Virtual Boy core module - October 14, 2024"
|
@echo "Shrooms Virtual Boy core module - October 15, 2024"
|
||||||
@echo
|
@echo
|
||||||
@echo "Target build environment is any Debian with the following packages:"
|
@echo "Target build environment is any Debian with the following packages:"
|
||||||
@echo " emscripten"
|
@echo " emscripten"
|
||||||
|
@ -26,8 +26,9 @@ core:
|
||||||
@gcc core/vb.c -I core -c -o /dev/null \
|
@gcc core/vb.c -I core -c -o /dev/null \
|
||||||
-Werror -std=c90 -Wall -Wextra -Wpedantic \
|
-Werror -std=c90 -Wall -Wextra -Wpedantic \
|
||||||
-D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \
|
-D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \
|
||||||
-D VB_DIRECT_EXCEPTION -D VB_DIRECT_EXECUTE -D VB_DIRECT_FETCH \
|
-D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \
|
||||||
-D VB_DIRECT_READ -D VB_DIRECT_WRITE -D VB_DIV_GENERIC
|
-D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_READ=testRead \
|
||||||
|
-D VB_DIRECT_WRITE=testWrite
|
||||||
# Clang generic
|
# Clang generic
|
||||||
@emcc core/vb.c -I core -c -o /dev/null \
|
@emcc core/vb.c -I core -c -o /dev/null \
|
||||||
-Werror -std=c90 -Wall -Wextra -Wpedantic
|
-Werror -std=c90 -Wall -Wextra -Wpedantic
|
||||||
|
@ -35,8 +36,9 @@ core:
|
||||||
@emcc core/vb.c -I core -c -o /dev/null \
|
@emcc core/vb.c -I core -c -o /dev/null \
|
||||||
-Werror -std=c90 -Wall -Wextra -Wpedantic \
|
-Werror -std=c90 -Wall -Wextra -Wpedantic \
|
||||||
-D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \
|
-D VB_LITTLE_ENDIAN -D VB_SIGNED_PROPAGATE -D VB_DIV_GENERIC \
|
||||||
-D VB_DIRECT_EXCEPTION -D VB_DIRECT_EXECUTE -D VB_DIRECT_FETCH \
|
-D VB_DIRECT_EXCEPTION=textException -D VB_DIRECT_EXECUTE=textExecute \
|
||||||
-D VB_DIRECT_READ -D VB_DIRECT_WRITE -D VB_DIV_GENERIC
|
-D VB_DIRECT_FETCH=testFetch -D VB_DIRECT_READ=testRead \
|
||||||
|
-D VB_DIRECT_WRITE=testWrite
|
||||||
|
|
||||||
.PHONY: wasm
|
.PHONY: wasm
|
||||||
wasm:
|
wasm:
|
||||||
|
|
Loading…
Reference in New Issue