2024-10-15 19:11:29 +00:00
|
|
|
/* This file is included into vb.c and cannot be compiled on its own. */
|
|
|
|
#ifdef VBAPI
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/********************************** Macros ***********************************/
|
|
|
|
|
|
|
|
/* Compute how many clocks are in some number of milliseconds */
|
|
|
|
#define vipClocksMs(x) x * 20000
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-15 19:11:29 +00:00
|
|
|
/***************************** Module Functions ******************************/
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* Precompute brightness values for image output */
|
|
|
|
static void vipComputeBrightness(VB *sim) {
|
|
|
|
int32_t brt[4]; /* Working output */
|
|
|
|
int32_t repeat; /* Multiplier from column table */
|
|
|
|
int x; /* Iterator */
|
|
|
|
|
|
|
|
/* Compute brightness from hardware state */
|
|
|
|
repeat = (int32_t) sim->vip.ram[sim->vip.dp.cta + 1] + 1;
|
|
|
|
brt[1] = repeat * sim->vip.brtRest[0];
|
|
|
|
brt[2] = repeat * sim->vip.brtRest[1];
|
|
|
|
brt[3] = repeat * sim->vip.brtRest[2] + brt[2] + brt[1];
|
|
|
|
|
|
|
|
/* Scale brightness values to 0..255 */
|
|
|
|
for (x = 1; x < 4; x++)
|
|
|
|
sim->vip.dp.brt[x] = ((brt[x] > 127 ? 127 : brt[x]) * 510 + 127) / 254;
|
|
|
|
}
|
|
|
|
|
2024-10-15 19:11:29 +00:00
|
|
|
/* Read a palette */
|
|
|
|
static int32_t vipReadPalette(uint8_t *entries) {
|
|
|
|
return entries[3] << 6 | entries[2] << 4 | entries[1] << 2;
|
|
|
|
}
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* Raise an interrupt request */
|
|
|
|
static void vipThrow(VB *sim, uint16_t cause) {
|
|
|
|
if (!(sim->vip.intenb & cause))
|
|
|
|
return;
|
|
|
|
sim->vip.intpnd |= cause;
|
|
|
|
sim->cpu.irq |= 0x0010;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Transfer one column of frame buffer pixels to output */
|
|
|
|
static void vipTransferColumn(VB *sim, int32_t eye) {
|
|
|
|
int32_t bits; /* Pixel bits from frame buffer */
|
|
|
|
int y, z; /* Iterators */
|
|
|
|
|
|
|
|
/* Select source and destination addresses in host memory */
|
|
|
|
uint8_t *dest = &sim->vip.frames
|
|
|
|
[sim->vip.dp.buffer][eye][sim->vip.dp.column];
|
|
|
|
uint8_t *src = &sim->vip.ram[
|
|
|
|
eye << 16 |
|
|
|
|
sim->vip.dp.buffer << 15 |
|
|
|
|
sim->vip.dp.column << 6
|
|
|
|
];
|
|
|
|
|
|
|
|
/* Transfer all rows as words */
|
|
|
|
for (y = 0; y < 224; y += 4) {
|
|
|
|
bits = busReadBuffer(src, VB_S32);
|
|
|
|
for (z = 0; z < 1536; z += 384, bits >>= 2)
|
|
|
|
dest[z] = sim->vip.dp.brt[bits & 3];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-10-15 19:11:29 +00:00
|
|
|
/* 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) {
|
2024-10-16 21:15:39 +00:00
|
|
|
int32_t mask; /* Byte access mask */
|
2024-10-15 19:11:29 +00:00
|
|
|
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 =
|
2024-10-16 21:15:39 +00:00
|
|
|
(int32_t) sim->vip.dp.lock << 10 |
|
|
|
|
(int32_t) sim->vip.dp.synce << 9 |
|
|
|
|
(int32_t) sim->vip.dp.re << 8 |
|
|
|
|
(int32_t) sim->vip.dp.fclk << 7 |
|
|
|
|
(int32_t) sim->vip.dp.scanrdy << 6 |
|
|
|
|
(int32_t) sim->vip.dp.r1bsy << 5 |
|
|
|
|
(int32_t) sim->vip.dp.l1bsy << 4 |
|
|
|
|
(int32_t) sim->vip.dp.r0bsy << 3 |
|
|
|
|
(int32_t) sim->vip.dp.l0bsy << 2 |
|
|
|
|
(int32_t) sim->vip.dp.disp << 1
|
2024-10-15 19:11:29 +00:00
|
|
|
;
|
|
|
|
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 =
|
2024-10-16 21:15:39 +00:00
|
|
|
(int32_t) sim->vip.xp.sbout << 15 |
|
|
|
|
(int32_t) sim->vip.xp.sbcount << 8 |
|
|
|
|
(int32_t) sim->vip.xp.overtime << 4 |
|
|
|
|
(int32_t) sim->vip.xp.f1bsy << 3 |
|
|
|
|
(int32_t) sim->vip.xp.f0bsy << 2 |
|
|
|
|
(int32_t) sim->vip.xp.xpen << 1
|
2024-10-15 19:11:29 +00:00
|
|
|
;
|
|
|
|
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) {
|
2024-10-16 21:15:39 +00:00
|
|
|
int32_t mask; /* Byte access mask */
|
2024-10-15 19:11:29 +00:00
|
|
|
|
|
|
|
/* 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) {
|
2024-10-16 21:15:39 +00:00
|
|
|
sim->vip.dp.lock = value >> 10 & 1;
|
|
|
|
sim->vip.dp.synce = value >> 9 & 1;
|
|
|
|
sim->vip.dp.re = value >> 8 & 1;
|
2024-10-15 19:11:29 +00:00
|
|
|
}
|
|
|
|
if ((mask & 0x00FF) == 0) {
|
2024-10-16 21:15:39 +00:00
|
|
|
sim->vip.dp.disp = value >> 1 & 1;
|
2024-10-15 19:11:29 +00:00
|
|
|
/* 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)
|
2024-10-16 21:15:39 +00:00
|
|
|
sim->vip.xp.sbcmp = value >> 8 & 31;
|
2024-10-15 19:11:29 +00:00
|
|
|
if ((mask & 0x00FF) == 0) {
|
2024-10-16 21:15:39 +00:00
|
|
|
sim->vip.xp.xpen = value >> 1 & 1;
|
2024-10-15 19:11:29 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/***************************** Callback Handlers *****************************/
|
|
|
|
|
|
|
|
/* Prepare to handle an exception */
|
|
|
|
#ifndef VB_DIRECT_FRAME
|
|
|
|
#define VB_ON_FRAME sim->onFrame
|
|
|
|
#else
|
|
|
|
extern int VB_DIRECT_FRAME(VB *);
|
|
|
|
#define VB_ON_FRAME VB_DIRECT_FRAME
|
|
|
|
#endif
|
|
|
|
static int vipOnFrame(VB *sim) {
|
|
|
|
return sim->onFrame != NULL && VB_ON_FRAME(sim);
|
|
|
|
}
|
|
|
|
#undef VB_ON_FRAME
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-10-15 19:11:29 +00:00
|
|
|
/***************************** Library Functions *****************************/
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* Display processor */
|
|
|
|
static int vipEmulateDisplay(VB *sim, uint32_t clocks) {
|
|
|
|
|
|
|
|
/* Process all clocks */
|
|
|
|
while (clocks != 0) {
|
|
|
|
|
|
|
|
/* The next event is after the time remaining */
|
|
|
|
if (sim->vip.dp.clocks > clocks) {
|
|
|
|
sim->vip.dp.clocks -= clocks;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Advance forward the component's number of clocks */
|
|
|
|
clocks -= sim->vip.dp.clocks;
|
|
|
|
sim->vip.dp.clocks = 0;
|
|
|
|
|
|
|
|
/* Processing by operation phase */
|
|
|
|
switch (sim->vip.dp.step) {
|
|
|
|
|
|
|
|
case 0: /* 0ms - FCLK rising edge */
|
|
|
|
sim->vip.dp.clocks = vipClocksMs(3);
|
|
|
|
sim->vip.dp.fclk = 1;
|
|
|
|
sim->vip.dp.step = 1;
|
|
|
|
vipThrow(sim, 0x0010); /* FRAMESTART */
|
|
|
|
/* TODO: Initiate drawing, throw GAMESTART */
|
|
|
|
/* ELSE: Set OVERTIME, throw TIMEERR */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 0ms-3ms - Idle */
|
|
|
|
|
|
|
|
case 1: /* 3ms - L*BSY rising edge */
|
|
|
|
if (sim->vip.dp.buffer == 0)
|
|
|
|
sim->vip.dp.l0bsy = 1;
|
|
|
|
else sim->vip.dp.l1bsy = 1;
|
|
|
|
sim->vip.dp.column = 0;
|
|
|
|
sim->vip.dp.cta = 0x3DC00 | (uint32_t)sim->vip.cta.cta_l<<1;
|
|
|
|
sim->vip.dp.step = 2;
|
|
|
|
vipComputeBrightness(sim);
|
|
|
|
|
|
|
|
/* Fallthrough */
|
|
|
|
case 2: /* 3ms-8ms - Display left frame buffer */
|
|
|
|
if ((sim->vip.dp.column & 3) == 0)
|
|
|
|
vipComputeBrightness(sim);
|
|
|
|
vipTransferColumn(sim, 0);
|
|
|
|
sim->vip.dp.clocks =
|
|
|
|
260 + (0xA94 >> sim->vip.dp.column % 12 & 1);
|
|
|
|
sim->vip.dp.column++;
|
|
|
|
if ((sim->vip.dp.column & 3) == 0)
|
|
|
|
sim->vip.dp.cta -= 2;
|
|
|
|
if (sim->vip.dp.column == 384)
|
|
|
|
sim->vip.dp.step = 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: /* 8ms - L*BSY falling edge */
|
|
|
|
if (sim->vip.dp.buffer == 0)
|
|
|
|
sim->vip.dp.l0bsy = 0;
|
|
|
|
else sim->vip.dp.l1bsy = 0;
|
|
|
|
sim->vip.dp.clocks = vipClocksMs(2);
|
|
|
|
sim->vip.dp.step = 4;
|
|
|
|
vipThrow(sim, 0x0002); /* LFBEND */
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 8ms-10ms - Idle */
|
|
|
|
|
|
|
|
case 4: /* 10ms - FCLK falling edge */
|
|
|
|
sim->vip.dp.clocks = vipClocksMs(3);
|
|
|
|
sim->vip.dp.fclk = 0;
|
|
|
|
sim->vip.dp.step = 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 10ms-13ms - Idle */
|
|
|
|
|
|
|
|
case 5: /* 13ms - R*BSY rising edge */
|
|
|
|
if (sim->vip.dp.buffer == 0)
|
|
|
|
sim->vip.dp.r0bsy = 1;
|
|
|
|
else sim->vip.dp.r1bsy = 1;
|
|
|
|
sim->vip.dp.column = 0;
|
|
|
|
sim->vip.dp.cta = 0x3DE00 | (uint32_t)sim->vip.cta.cta_r<<1;
|
|
|
|
sim->vip.dp.step = 6;
|
|
|
|
|
|
|
|
/* Fallthrough */
|
|
|
|
case 6: /* 13ms-18ms - Display right frame buffer */
|
|
|
|
vipTransferColumn(sim, 1);
|
|
|
|
sim->vip.dp.clocks =
|
|
|
|
260 + (0xA94 >> sim->vip.dp.column % 12 & 1);
|
|
|
|
sim->vip.dp.column++;
|
|
|
|
if (sim->vip.dp.column == 384)
|
|
|
|
sim->vip.dp.step = 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7: /* 18ms - R*BSY falling edge */
|
|
|
|
if (sim->vip.dp.buffer == 0)
|
|
|
|
sim->vip.dp.r0bsy = 0;
|
|
|
|
else sim->vip.dp.r1bsy = 0;
|
|
|
|
sim->vip.dp.clocks = vipClocksMs(2);
|
|
|
|
sim->vip.dp.step = 0;
|
|
|
|
vipThrow(sim, 0x0004); /* RFBEND */
|
|
|
|
if (vipOnFrame(sim))
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* 18ms-20ms - Idle */
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-10-15 19:11:29 +00:00
|
|
|
/* Process component */
|
|
|
|
static int vipEmulate(VB *sim, uint32_t clocks) {
|
2024-10-16 21:15:39 +00:00
|
|
|
int brk = vipEmulateDisplay(sim, clocks);
|
|
|
|
/*vipEmulateDrawing(sim, clocks);*/
|
|
|
|
return brk;
|
2024-10-15 19:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* RAM */
|
|
|
|
if (address < 0x40000)
|
|
|
|
*value = busReadBuffer(&sim->vip.ram[address], type);
|
2024-10-15 19:11:29 +00:00
|
|
|
|
|
|
|
/* 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);
|
2024-10-16 21:15:39 +00:00
|
|
|
*value = busReadBuffer(&sim->vip.ram[address], type);
|
2024-10-15 19:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Simulate a hardware reset */
|
|
|
|
static void vipReset(VB *sim) {
|
|
|
|
int x, y; /* Iterators */
|
|
|
|
|
|
|
|
/* Normal */
|
2024-10-16 21:15:39 +00:00
|
|
|
sim->vip.dp.disp = 0;
|
|
|
|
sim->vip.dp.re = 0;
|
|
|
|
sim->vip.dp.synce = 0;
|
|
|
|
sim->vip.intenb = 0x0000;
|
|
|
|
sim->vip.xp.xpen = 0;
|
2024-10-15 19:11:29 +00:00
|
|
|
|
|
|
|
/* Extra (the hardware does not do this) */
|
2024-10-16 21:15:39 +00:00
|
|
|
for (x = 0; x < 0x80000; x++)
|
|
|
|
sim->vip.ram[x] = 0;
|
|
|
|
sim->vip.bkcol = 0;
|
|
|
|
sim->vip.cta.cta_l = 0xFA;
|
|
|
|
sim->vip.cta.cta_r = 0xFA;
|
|
|
|
sim->vip.frmcyc = 0;
|
|
|
|
sim->vip.intpnd = 0x0000;
|
|
|
|
sim->vip.dp.fclk = 0;
|
|
|
|
sim->vip.dp.l0bsy = 0;
|
|
|
|
sim->vip.dp.l1bsy = 0;
|
|
|
|
sim->vip.dp.lock = 0;
|
|
|
|
sim->vip.dp.r0bsy = 0;
|
|
|
|
sim->vip.dp.r1bsy = 0;
|
|
|
|
sim->vip.dp.scanrdy = 0;
|
|
|
|
sim->vip.xp.f0bsy = 0;
|
|
|
|
sim->vip.xp.f1bsy = 0;
|
|
|
|
sim->vip.xp.overtime = 0;
|
|
|
|
sim->vip.xp.sbcmp = 0;
|
|
|
|
sim->vip.xp.sbcount = 0;
|
|
|
|
sim->vip.xp.sbout = 0;
|
2024-10-15 19:11:29 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* Other */
|
|
|
|
sim->vip.dp.brt[0] = 0;
|
|
|
|
sim->vip.dp.clocks = 0;
|
|
|
|
sim->vip.dp.step = 0;
|
2024-10-15 19:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine how many clocks are guaranteed to process */
|
|
|
|
static uint32_t vipUntil(VB *sim, uint32_t clocks) {
|
|
|
|
(void) sim;
|
2024-10-16 21:15:39 +00:00
|
|
|
/* Don't allow clocks to exceed interrupt conditions, even if disabled */
|
2024-10-15 19:11:29 +00:00
|
|
|
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){
|
|
|
|
|
|
|
|
/* Working variables */
|
|
|
|
address &= 0x0007FFFF;
|
|
|
|
|
2024-10-16 21:15:39 +00:00
|
|
|
/* RAM */
|
2024-10-15 19:11:29 +00:00
|
|
|
if (address < 0x40000)
|
2024-10-16 21:15:39 +00:00
|
|
|
busWriteBuffer(&sim->vip.ram[address], type, value);
|
2024-10-15 19:11:29 +00:00
|
|
|
|
|
|
|
/* 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);
|
2024-10-16 21:15:39 +00:00
|
|
|
busWriteBuffer(&sim->vip.ram[address], type, value);
|
2024-10-15 19:11:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* VBAPI */
|