shrooms-vb-core/core/vip.c

416 lines
12 KiB
C
Raw Normal View History

2024-10-15 19:11:29 +00:00
/* 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 */