[Core/VDP] implemented proper FIFO ring-buffer & unused bits behavior on CRAM/VSRAM reads (verified on real hardware)

This commit is contained in:
EkeEke 2013-10-20 23:48:36 +02:00
parent 5d67b14cea
commit 8a813b0ecb
3 changed files with 90 additions and 37 deletions

View File

@ -51,7 +51,7 @@ int state_load(unsigned char *state)
return 0; return 0;
} }
/* version check (1.7.1 and above only) */ /* version check (keep compatibility with previous & current state version) */
if ((version[11] < 0x31) || (version[13] < 0x37) || (version[15] < 0x31)) if ((version[11] < 0x31) || (version[13] < 0x37) || (version[15] < 0x31))
{ {
return 0; return 0;
@ -110,7 +110,7 @@ int state_load(unsigned char *state)
} }
/* VDP */ /* VDP */
bufferptr += vdp_context_load(&state[bufferptr]); bufferptr += vdp_context_load(&state[bufferptr], version[15]);
/* SOUND */ /* SOUND */
bufferptr += sound_context_load(&state[bufferptr]); bufferptr += sound_context_load(&state[bufferptr]);

View File

@ -136,7 +136,8 @@ static uint16 dma_src; /* DMA source address */
static uint16 dmafill; /* DMA Fill setup */ static uint16 dmafill; /* DMA Fill setup */
static uint32 dma_endCycles; /* 68k cycles to DMA end */ static uint32 dma_endCycles; /* 68k cycles to DMA end */
static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */ static int cached_write; /* 2nd part of 32-bit CTRL port write (Genesis mode) or LSB of CRAM data (Game Gear mode) */
static uint16 fifo[4]; /* FIFO buffer */ static uint16 fifo[4]; /* FIFO ring-buffer */
static int fifo_idx; /* FIFO write index */
static int fifo_byte_access; /* FIFO byte access flag */ static int fifo_byte_access; /* FIFO byte access flag */
static uint32 fifo_cycles; /* FIFO next access cycle */ static uint32 fifo_cycles; /* FIFO next access cycle */
@ -231,6 +232,7 @@ void vdp_reset(void)
fifo_write_cnt = 0; fifo_write_cnt = 0;
fifo_cycles = 0; fifo_cycles = 0;
fifo_slots = 0; fifo_slots = 0;
fifo_idx = 0;
cached_write = -1; cached_write = -1;
fifo_byte_access = 1; fifo_byte_access = 1;
@ -312,16 +314,16 @@ void vdp_reset(void)
parse_satb = parse_satb_m4; parse_satb = parse_satb_m4;
} }
/* 68k bus access mode (Mode 4 by default) */ /* default 68k bus interface (Mega Drive VDP only) */
vdp_68k_data_w = vdp_68k_data_w_m4; vdp_68k_data_w = vdp_68k_data_w_m4;
vdp_68k_data_r = vdp_68k_data_r_m4; vdp_68k_data_r = vdp_68k_data_r_m4;
/* Z80 bus access mode */ /* default Z80 bus interface */
switch (system_hw) switch (system_hw)
{ {
case SYSTEM_SG: case SYSTEM_SG:
{ {
/* SG-1000 port access */ /* SG-1000 VDP (TMS99xx) */
vdp_z80_data_w = vdp_z80_data_w_sg; vdp_z80_data_w = vdp_z80_data_w_sg;
vdp_z80_data_r = vdp_z80_data_r_m4; vdp_z80_data_r = vdp_z80_data_r_m4;
break; break;
@ -329,7 +331,7 @@ void vdp_reset(void)
case SYSTEM_GG: case SYSTEM_GG:
{ {
/* Game Gear port access */ /* Game Gear VDP */
vdp_z80_data_w = vdp_z80_data_w_gg; vdp_z80_data_w = vdp_z80_data_w_gg;
vdp_z80_data_r = vdp_z80_data_r_m4; vdp_z80_data_r = vdp_z80_data_r_m4;
break; break;
@ -340,7 +342,7 @@ void vdp_reset(void)
case SYSTEM_SMS2: case SYSTEM_SMS2:
case SYSTEM_GGMS: case SYSTEM_GGMS:
{ {
/* Master System port access */ /* Master System or Game Gear (in MS compatibility mode) VDP */
vdp_z80_data_w = vdp_z80_data_w_ms; vdp_z80_data_w = vdp_z80_data_w_ms;
vdp_z80_data_r = vdp_z80_data_r_m4; vdp_z80_data_r = vdp_z80_data_r_m4;
break; break;
@ -348,7 +350,7 @@ void vdp_reset(void)
default: default:
{ {
/* Genesis port access */ /* Mega Drive VDP (in MS compatibility mode) */
vdp_z80_data_w = vdp_z80_data_w_m4; vdp_z80_data_w = vdp_z80_data_w_m4;
vdp_z80_data_r = vdp_z80_data_r_m4; vdp_z80_data_r = vdp_z80_data_r_m4;
break; break;
@ -361,7 +363,7 @@ void vdp_reset(void)
/* 16k address decoding by default (Magical Kid Wiz) */ /* 16k address decoding by default (Magical Kid Wiz) */
vdp_reg_w(1, 0x80, 0); vdp_reg_w(1, 0x80, 0);
/* no H-INT on TMS9918 */ /* no H-INT on TMS99xx */
vdp_reg_w(10, 0xFF, 0); vdp_reg_w(10, 0xFF, 0);
} }
@ -418,6 +420,8 @@ int vdp_context_save(uint8 *state)
save_param(&pending, sizeof(pending)); save_param(&pending, sizeof(pending));
save_param(&status, sizeof(status)); save_param(&status, sizeof(status));
save_param(&dmafill, sizeof(dmafill)); save_param(&dmafill, sizeof(dmafill));
save_param(&fifo_idx, sizeof(fifo_idx));
save_param(&fifo, sizeof(fifo));
save_param(&hint_pending, sizeof(hint_pending)); save_param(&hint_pending, sizeof(hint_pending));
save_param(&vint_pending, sizeof(vint_pending)); save_param(&vint_pending, sizeof(vint_pending));
save_param(&dma_length, sizeof(dma_length)); save_param(&dma_length, sizeof(dma_length));
@ -427,7 +431,7 @@ int vdp_context_save(uint8 *state)
return bufferptr; return bufferptr;
} }
int vdp_context_load(uint8 *state) int vdp_context_load(uint8 *state, uint8 version)
{ {
int i, bufferptr = 0; int i, bufferptr = 0;
uint8 temp_reg[0x20]; uint8 temp_reg[0x20];
@ -473,13 +477,29 @@ int vdp_context_load(uint8 *state)
load_param(&code, sizeof(code)); load_param(&code, sizeof(code));
load_param(&pending, sizeof(pending)); load_param(&pending, sizeof(pending));
load_param(&status, sizeof(status)); load_param(&status, sizeof(status));
load_param(&dmafill, sizeof(dmafill));
/* 1.7.1 state compatibility */
if (version < 0x35)
{
uint16 temp;
load_param(&temp, 2);
dmafill = temp >> 8;
temp &= 0xff;
fifo_idx = 0;
fifo[0] = fifo[1] = fifo[2] = fifo[3] = (temp << 8) | temp;
}
else
{
load_param(&dmafill, sizeof(dmafill));
load_param(&fifo_idx, sizeof(fifo_idx));
load_param(&fifo, sizeof(fifo));
}
load_param(&hint_pending, sizeof(hint_pending)); load_param(&hint_pending, sizeof(hint_pending));
load_param(&vint_pending, sizeof(vint_pending)); load_param(&vint_pending, sizeof(vint_pending));
load_param(&dma_length, sizeof(dma_length)); load_param(&dma_length, sizeof(dma_length));
load_param(&dma_type, sizeof(dma_type)); load_param(&dma_type, sizeof(dma_type));
load_param(&dma_src, sizeof(dma_src)); load_param(&dma_src, sizeof(dma_src));
load_param(&cached_write, sizeof(cached_write)); load_param(&cached_write, sizeof(cached_write));
/* restore FIFO byte access flag */ /* restore FIFO byte access flag */
@ -528,7 +548,7 @@ int vdp_context_load(uint8 *state)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* DMA update function */ /* DMA update function (Mega Drive VDP only) */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
void vdp_dma_update(unsigned int cycles) void vdp_dma_update(unsigned int cycles)
@ -1097,7 +1117,7 @@ void vdp_sms_ctrl_w(unsigned int data)
} }
} }
/* TMS9918 (SG-1000) VDP control port specific */ /* SG-1000 VDP (TMS99xx) control port specific */
void vdp_tms_ctrl_w(unsigned int data) void vdp_tms_ctrl_w(unsigned int data)
{ {
if(pending == 0) if(pending == 0)
@ -2140,7 +2160,13 @@ static void vdp_fifo_update(unsigned int cycles)
static void vdp_bus_w(unsigned int data) static void vdp_bus_w(unsigned int data)
{ {
/* Check destination code */ /* write data to next FIFO entry */
fifo[fifo_idx] = data;
/* increment FIFO write pointer */
fifo_idx = (fifo_idx + 1) & 3;
/* Check destination code (CD0-CD3) */
switch (code & 0x0F) switch (code & 0x0F)
{ {
case 0x01: /* VRAM */ case 0x01: /* VRAM */
@ -2260,7 +2286,7 @@ static void vdp_bus_w(unsigned int data)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* 68k data port access functions (Genesis mode) */ /* 68k bus interface (Mega Drive VDP only) */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static void vdp_68k_data_w_m4(unsigned int data) static void vdp_68k_data_w_m4(unsigned int data)
@ -2434,11 +2460,12 @@ static unsigned int vdp_68k_data_r_m5(void)
/* Clear pending flag */ /* Clear pending flag */
pending = 0; pending = 0;
switch (code & 0x0F) /* Check destination code (CD0-CD3) & CD4 */
switch (code & 0x1F)
{ {
case 0x00: /* VRAM */ case 0x00:
{ {
/* Read data */ /* read two bytes from VRAM */
data = *(uint16 *)&vram[addr & 0xFFFE]; data = *(uint16 *)&vram[addr & 0xFFFE];
#ifdef LOGVDP #ifdef LOGVDP
@ -2447,10 +2474,23 @@ static unsigned int vdp_68k_data_r_m5(void)
break; break;
} }
case 0x04: /* VSRAM */ case 0x04:
{ {
/* Read data */ /* VSRAM index */
data = *(uint16 *)&vsram[addr & 0x7E]; int index = addr & 0x7E;
/* Check against VSRAM max size (80 x 11-bits) */
if (index >= 0x50)
{
/* Wrap to address 0 (TODO: check if still true with Genesis 3 model) */
index = 0;
}
/* Read 11-bit word from VSRAM */
data = *(uint16 *)&vsram[index] & 0x7FF;
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0x7FF);
#ifdef LOGVDP #ifdef LOGVDP
error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); error("[%d(%d)][%d(%d)] VSRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
@ -2458,24 +2498,30 @@ static unsigned int vdp_68k_data_r_m5(void)
break; break;
} }
case 0x08: /* CRAM */ case 0x08:
{ {
/* Read data */ /* Read 9-bit word from CRAM */
data = *(uint16 *)&cram[addr & 0x7E]; data = *(uint16 *)&cram[addr & 0x7E];
/* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */ /* Unpack 9-bit CRAM data (BBBGGGRRR) to 16-bit bus data (BBB0GGG0RRR0) */
data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1); data = ((data & 0x1C0) << 3) | ((data & 0x038) << 2) | ((data & 0x007) << 1);
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0xEEE);
#ifdef LOGVDP #ifdef LOGVDP
error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); error("[%d(%d)][%d(%d)] CRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
#endif #endif
break; break;
} }
case 0x0c: /* undocumented 8-bit VRAM read (cf. http://gendev.spritesmind.net/forum/viewtopic.php?t=790) */ case 0x0c: /* undocumented 8-bit VRAM read */
{ {
/* Read data (MSB forced to zero) */ /* Read one byte from VRAM adjacent address */
data = *(uint16 *)&vram[addr & 0xFFFE] & 0xff; data = READ_BYTE(vram, addr ^ 1);
/* Unused bits are set using data from next available FIFO entry */
data |= (fifo[fifo_idx] & ~0xFF);
#ifdef LOGVDP #ifdef LOGVDP
error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC)); error("[%d(%d)][%d(%d)] 8-bit VRAM 0x%x read -> 0x%x (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, addr, data, m68k_get_reg(M68K_REG_PC));
@ -2485,7 +2531,7 @@ static unsigned int vdp_68k_data_r_m5(void)
default: default:
{ {
/* Invalid code value */ /* Invalid code value (normally locks VDP, hard reset required) */
#ifdef LOGERROR #ifdef LOGERROR
error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC)); error("[%d(%d)][%d(%d)] Invalid (%d) 0x%x read (%x)\n", v_counter, m68k.cycles/MCYCLES_PER_LINE-1, m68k.cycles, m68k.cycles%MCYCLES_PER_LINE, code, addr, m68k_get_reg(M68K_REG_PC));
#endif #endif
@ -2502,7 +2548,7 @@ static unsigned int vdp_68k_data_r_m5(void)
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* Z80 data port access functions (Master System compatibility mode) */ /* Z80 bus interface (Mega Drive VDP in Master System compatibility mode) */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static void vdp_z80_data_w_m4(unsigned int data) static void vdp_z80_data_w_m4(unsigned int data)
@ -2562,7 +2608,11 @@ static void vdp_z80_data_w_m5(unsigned int data)
/* Clear pending flag */ /* Clear pending flag */
pending = 0; pending = 0;
/* Check destination code */ /* Push byte into FIFO */
fifo[fifo_idx] = data << 8;
fifo_idx = (fifo_idx + 1) & 3;
/* Check destination code (CD0-CD3) */
switch (code & 0x0F) switch (code & 0x0F)
{ {
case 0x01: /* VRAM */ case 0x01: /* VRAM */
@ -2690,7 +2740,8 @@ static unsigned int vdp_z80_data_r_m5(void)
/* Clear pending flag */ /* Clear pending flag */
pending = 0; pending = 0;
switch (code & 0x0F) /* Check destination code (CD0-CD3) & CD4 */
switch (code & 0x1F)
{ {
case 0x00: /* VRAM */ case 0x00: /* VRAM */
{ {
@ -2734,7 +2785,7 @@ static unsigned int vdp_z80_data_r_m5(void)
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* VDP specific data port access functions (Master System, Game Gear, SG-1000) */ /* Z80 bus interface (Master System, Game Gear & SG-1000 VDP) */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
static void vdp_z80_data_w_ms(unsigned int data) static void vdp_z80_data_w_ms(unsigned int data)
@ -2746,10 +2797,11 @@ static void vdp_z80_data_w_ms(unsigned int data)
{ {
int index; int index;
/* check if we are already on next line */ /* Check if we are already on next line */
int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame; int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;
if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special)) if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))
{ {
/* Render next line */
v_counter = line; v_counter = line;
render_line(line); render_line(line);
} }
@ -2813,10 +2865,11 @@ static void vdp_z80_data_w_gg(unsigned int data)
{ {
int index; int index;
/* check if we are already on next line*/ /* Check if we are already on next line*/
int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame; int line = (lines_per_frame + (Z80.cycles / MCYCLES_PER_LINE) - 1) % lines_per_frame;
if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special)) if ((line > v_counter) && (line < bitmap.viewport.h) && !(work_ram[0x1ffb] & cart.special))
{ {
/* Render next line */
v_counter = line; v_counter = line;
render_line(line); render_line(line);
} }
@ -2907,7 +2960,7 @@ static void vdp_z80_data_w_sg(unsigned int data)
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* DMA operations */ /* DMA operations (Mega Drive VDP only) */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* DMA from 68K bus: $000000-$7FFFFF (external area) */ /* DMA from 68K bus: $000000-$7FFFFF (external area) */

View File

@ -90,7 +90,7 @@ extern unsigned int (*vdp_z80_data_r)(void);
extern void vdp_init(void); extern void vdp_init(void);
extern void vdp_reset(void); extern void vdp_reset(void);
extern int vdp_context_save(uint8 *state); extern int vdp_context_save(uint8 *state);
extern int vdp_context_load(uint8 *state); extern int vdp_context_load(uint8 *state, uint8 version);
extern void vdp_dma_update(unsigned int cycles); extern void vdp_dma_update(unsigned int cycles);
extern void vdp_68k_ctrl_w(unsigned int data); extern void vdp_68k_ctrl_w(unsigned int data);
extern void vdp_z80_ctrl_w(unsigned int data); extern void vdp_z80_ctrl_w(unsigned int data);