[Core/CD] improved GFX processing accuracy to halt it while Word RAM is allocated to Main CPU in 2M mode

This commit is contained in:
ekeeke 2022-10-09 10:13:24 +02:00
parent dded47d5e7
commit ea8d299123
5 changed files with 160 additions and 114 deletions

View File

@ -29,6 +29,7 @@ Genesis Plus GX 1.7.5 (xx/xx/xxxx) (Eke-Eke)
* improved CDD "play" command accuracy (fixes "Snatcher" Act 2 starting cutscene)
* improved CDD status report accuracy (fixes track looping with Mode 1 patched games using MSU-MD driver)
* improved Word-RAM byte access accuracy (verified on schematics)
* improved GFX processing accuracy to halt it while Word RAM is allocated to Main CPU in 2M mode
* disabled 68k and Z80 access to PRG-RAM when SUB-CPU is running (fixes "Dungeon Explorer")
* disabled CD hardware reset on Soft-Reset (verified on real hardware)
* fixed potential load issues with non-zero backup RAM cart

View File

@ -586,132 +586,137 @@ INLINE void gfx_render(uint32 bufferIndex, uint32 width)
void gfx_start(unsigned int base, int cycles)
{
/* make sure 2M mode is enabled */
if (!(scd.regs[0x02>>1].byte.l & 0x04))
uint32 mask;
/* trace vector pointer */
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
/* stamps & stamp map size */
switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
{
uint32 mask;
/* trace vector pointer */
gfx.tracePtr = (uint16 *)(scd.word_ram_2M + ((base << 2) & 0x3fff8));
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
/* stamps & stamp map size */
switch ((scd.regs[0x58>>1].byte.l >> 1) & 0x03)
{
case 0:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 4; /* 16x16 stamps/map */
mask = 0x3fe00; /* 512 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 1:
gfx.dotMask = 0x07ffff; /* 256x256 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 3; /* 8x8 stamps/map */
mask = 0x3ff80; /* 128 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 2:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 4; /* 16x16 dots/stamps */
gfx.mapShift = 8; /* 256x256 stamps/map */
mask = 0x20000; /* 131072 bytes/table */
break;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 7; /* 128x128 stamps/map */
mask = 0x38000; /* 32768 bytes/table */
break;
}
/* stamp map table base address */
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
/* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
/* image buffer start index in dot units (2 pixels/byte) */
gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
/* add image buffer horizontal dot offset */
gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
/* reset GFX chip cycle counter */
gfx.cycles = cycles;
/* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
/* start graphics operation */
scd.regs[0x58>>1].byte.h = 0x80;
case 3:
gfx.dotMask = 0x7fffff; /* 4096*4096 dots/map */
gfx.stampShift = 11 + 5; /* 32x32 dots/stamps */
gfx.mapShift = 7; /* 128x128 stamps/map */
mask = 0x38000; /* 32768 bytes/table */
break;
}
/* stamp map table base address */
gfx.mapPtr = (uint16 *)(scd.word_ram_2M + ((scd.regs[0x5a>>1].w << 2) & mask));
/* image buffer column offset (64 pixels/cell, minus 7 pixels to restart at cell beginning) */
gfx.bufferOffset = (((scd.regs[0x5c>>1].byte.l & 0x1f) + 1) << 6) - 7;
/* image buffer start index in dot units (2 pixels/byte) */
gfx.bufferStart = (scd.regs[0x5e>>1].w << 3) & 0x7ffc0;
/* add image buffer horizontal dot offset */
gfx.bufferStart += (scd.regs[0x60>>1].byte.l & 0x3f);
/* reset GFX chip cycle counter */
gfx.cycles = cycles;
/* update GFX chip timings (see AC3:Thunderhawk / Thunderstrike) */
gfx.cyclesPerLine = 4 * 5 * scd.regs[0x62>>1].w;
/* start graphics operation */
scd.regs[0x58>>1].byte.h = 0x80;
}
void gfx_update(int cycles)
{
/* synchronize GFX chip with SUB-CPU */
cycles -= gfx.cycles;
/* make sure SUB-CPU is ahead */
if (cycles > 0)
/* make sure Word-RAM is assigned to SUB-CPU in 2M mode */
if ((scd.regs[0x02>>1].byte.l & 0x05) != 0x01)
{
/* number of lines to process */
unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
/* synchronize GFX processing with SUB-CPU */
cycles -= gfx.cycles;
/* check against remaining lines */
if (lines < scd.regs[0x64>>1].byte.l)
/* make sure SUB-CPU is ahead */
if (cycles > 0)
{
/* update Vdot remaining size */
scd.regs[0x64>>1].byte.l -= lines;
/* number of lines to process */
unsigned int lines = (cycles + gfx.cyclesPerLine - 1) / gfx.cyclesPerLine;
/* increment cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
{
/* process remaining lines */
lines = scd.regs[0x64>>1].byte.l;
/* clear Vdot remaining size */
scd.regs[0x64>>1].byte.l = 0;
/* end of graphics operation */
scd.regs[0x58>>1].byte.h = 0;
/* SUB-CPU idle on register $58 polling ? */
if (s68k.stopped & (1<<0x08))
/* check against remaining lines */
if (lines < scd.regs[0x64>>1].byte.l)
{
/* sync SUB-CPU with GFX chip */
s68k.cycles = scd.cycles;
/* update Vdot remaining size */
scd.regs[0x64>>1].byte.l -= lines;
/* restart SUB-CPU */
s68k.stopped = 0;
/* increment cycle counter */
gfx.cycles += lines * gfx.cyclesPerLine;
}
else
{
/* process remaining lines */
lines = scd.regs[0x64>>1].byte.l;
/* clear Vdot remaining size */
scd.regs[0x64>>1].byte.l = 0;
/* end of graphics operation */
scd.regs[0x58>>1].byte.h = 0;
/* SUB-CPU idle on register $58 polling ? */
if (s68k.stopped & (1<<0x08))
{
/* sync SUB-CPU with GFX chip */
s68k.cycles = scd.cycles;
/* restart SUB-CPU */
s68k.stopped = 0;
#ifdef LOG_SCD
error("s68k started from %d cycles\n", s68k.cycles);
error("s68k started from %d cycles\n", s68k.cycles);
#endif
}
/* level 1 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x02)
{
/* trigger level 1 interrupt */
scd.pending |= (1 << 1);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
}
}
/* level 1 interrupt enabled ? */
if (scd.regs[0x32>>1].byte.l & 0x02)
/* render lines */
while (lines--)
{
/* trigger level 1 interrupt */
scd.pending |= (1 << 1);
/* process dots to image buffer */
gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
/* update IRQ level */
s68k_update_irq((scd.pending & scd.regs[0x32>>1].byte.l) >> 1);
/* increment image buffer start index for next line (8 pixels/line) */
gfx.bufferStart += 8;
}
}
/* render lines */
while (lines--)
{
/* process dots to image buffer */
gfx_render(gfx.bufferStart, scd.regs[0x62>>1].w);
/* increment image buffer start index for next line (8 pixels/line) */
gfx.bufferStart += 8;
}
}
else
{
/* GFX processing is halted */
gfx.cycles = cycles;
}
}

View File

@ -932,6 +932,13 @@ static void scd_write_byte(unsigned int address, unsigned int data)
/* RET bit set in 2M mode */
if (data & 0x01)
{
/* check if graphics operation is running */
if (scd.regs[0x58>>1].byte.h & 0x80)
{
/* synchronize GFX processing with SUB-CPU */
gfx_update(s68k.cycles);
}
/* Word-RAM is returned to MAIN-CPU */
scd.dmna = 0;
@ -1196,6 +1203,13 @@ static void scd_write_word(unsigned int address, unsigned int data)
/* RET bit set in 2M mode */
if (data & 0x01)
{
/* check if graphics operation is running */
if (scd.regs[0x58>>1].byte.h & 0x80)
{
/* synchronize GFX processing with SUB-CPU */
gfx_update(s68k.cycles);
}
/* Word-RAM is returned to MAIN-CPU */
scd.dmna = 0;

View File

@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
@ -777,7 +777,7 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
}
else
{
/* writing 0 to DMNA in 1M mode actually set DMNA bit */
/* writing 0 to DMNA in 1M mode actually sets DMNA bit */
data |= 0x02;
/* update BK0-1 & DMNA bits */
@ -787,19 +787,32 @@ void ctrl_io_write_byte(unsigned int address, unsigned int data)
}
else
{
/* writing 0 in 2M mode does nothing */
/* writing 0 to DMNA in 2M mode does nothing */
if (data & 0x02)
{
/* Word-RAM is assigned to SUB-CPU */
scd.dmna = 1;
/* clear RET bit */
/* clear RET bit and update BK0-1 & DMNA bits */
scd.regs[0x03>>1].byte.l = (scd.regs[0x03>>1].byte.l & ~0xc3) | (data & 0xc2);
/* check if graphics operation is running */
if (scd.regs[0x58>>1].byte.h & 0x80)
{
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* synchronize GFX processing with SUB-CPU (only if not already ahead) */
if (gfx.cycles < cycles)
{
gfx.cycles = cycles;
}
}
return;
}
}
/* update BK0-1 bits */
/* update BK0-1 bits only */
scd.regs[0x03>>1].byte.l = (scd.regs[0x02>>1].byte.l & ~0xc0) | (data & 0xc0);
return;
}
@ -1014,7 +1027,7 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
}
else
{
/* writing 0 to DMNA in 1M mode actually set DMNA bit */
/* writing 0 to DMNA in 1M mode actually sets DMNA bit */
data |= 0x02;
/* update WP0-7, BK0-1 & DMNA bits */
@ -1024,19 +1037,32 @@ void ctrl_io_write_word(unsigned int address, unsigned int data)
}
else
{
/* writing 0 in 2M mode does nothing */
/* writing 0 to DMNA in 2M mode does nothing */
if (data & 0x02)
{
/* Word-RAM is assigned to SUB-CPU */
scd.dmna = 1;
/* clear RET bit */
/* clear RET bit and update WP0-7 & BK0-1 bits */
scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc3) | (data & 0xffc2);
/* check if graphics operation is running */
if (scd.regs[0x58>>1].byte.h & 0x80)
{
/* relative SUB-CPU cycle counter */
unsigned int cycles = (m68k.cycles * SCYCLES_PER_LINE) / MCYCLES_PER_LINE;
/* synchronize GFX processing with SUB-CPU (only if not already ahead) */
if (gfx.cycles < cycles)
{
gfx.cycles = cycles;
}
}
return;
}
}
/* update WP0-7 & BK0-1 bits */
/* update WP0-7 & BK0-1 bits only */
scd.regs[0x02>>1].w = (scd.regs[0x02>>1].w & ~0xffc0) | (data & 0xffc0);
return;
}

View File

@ -3,7 +3,7 @@
* Main 68k bus handlers
*
* Copyright (C) 1998-2003 Charles Mac Donald (original code)
* Copyright (C) 2007-2019 Eke-Eke (Genesis Plus GX)
* Copyright (C) 2007-2022 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met: