vdp fifo, tentative fix for broken save/load

This commit is contained in:
kub 2020-02-16 14:08:48 +01:00
parent 29d99d6bb8
commit daf29df963
3 changed files with 78 additions and 39 deletions

View file

@ -316,7 +316,10 @@ struct PicoVideo
unsigned char debug_p; // ... parsed: PVD_* unsigned char debug_p; // ... parsed: PVD_*
unsigned char addr_u; // bit16 of .addr unsigned char addr_u; // bit16 of .addr
unsigned char hint_cnt; unsigned char hint_cnt;
unsigned char pad[0x0b]; unsigned char pad2;
unsigned short hv_latch; // latched hvcounter value
signed int fifo_cnt; // pending xfers for current FIFO queue entry
unsigned char pad[0x04];
}; };
struct PicoMisc struct PicoMisc
@ -339,7 +342,7 @@ struct PicoMisc
unsigned char eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs unsigned char eeprom_slave; // EEPROM slave word for X24C02 and better SRAMs
unsigned char eeprom_status; unsigned char eeprom_status;
unsigned char pad1; // was ym2612 status unsigned char pad1; // was ym2612 status
unsigned short pad2; // 18 was dma_xfers unsigned short dma_xfers; // 18 unused (was VDP DMA transfer count)
unsigned char eeprom_wb[2]; // EEPROM latch/write buffer unsigned char eeprom_wb[2]; // EEPROM latch/write buffer
unsigned int frame_count; // 1c for movies and idle det unsigned int frame_count; // 1c for movies and idle det
}; };
@ -856,6 +859,8 @@ extern int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, u
void PicoVideoFIFOSync(int cycles); void PicoVideoFIFOSync(int cycles);
int PicoVideoFIFOHint(void); int PicoVideoFIFOHint(void);
int PicoVideoFIFOWrite(int count, int byte_p, unsigned sr_mask, unsigned sr_flags); int PicoVideoFIFOWrite(int count, int byte_p, unsigned sr_mask, unsigned sr_flags);
void PicoVideoSave(void);
void PicoVideoLoad(void);
// misc.c // misc.c
PICO_INTERNAL_ASM void memcpy16bswap(unsigned short *dest, void *src, int count); PICO_INTERNAL_ASM void memcpy16bswap(unsigned short *dest, void *src, int count);

View file

@ -250,6 +250,8 @@ static int state_save(void *file)
CHECKED_WRITE_BUFF(CHUNK_ZRAM, PicoMem.zram); CHECKED_WRITE_BUFF(CHUNK_ZRAM, PicoMem.zram);
CHECKED_WRITE_BUFF(CHUNK_CRAM, PicoMem.cram); CHECKED_WRITE_BUFF(CHUNK_CRAM, PicoMem.cram);
CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m); CHECKED_WRITE_BUFF(CHUNK_MISC, Pico.m);
PicoVideoSave();
CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video); CHECKED_WRITE_BUFF(CHUNK_VIDEO, Pico.video);
z80_pack(buff_z80); z80_pack(buff_z80);
@ -433,7 +435,11 @@ static int state_load(void *file)
case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); break; case CHUNK_CRAM: CHECKED_READ_BUFF(PicoMem.cram); break;
case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); break; case CHUNK_VSRAM: CHECKED_READ_BUFF(PicoMem.vsram); break;
case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break; case CHUNK_MISC: CHECKED_READ_BUFF(Pico.m); break;
case CHUNK_VIDEO: CHECKED_READ_BUFF(Pico.video); break; case CHUNK_VIDEO:
CHECKED_READ_BUFF(Pico.video);
PicoVideoLoad();
break;
case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break; case CHUNK_IOPORTS: CHECKED_READ_BUFF(PicoMem.ioports); break;
case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break; case CHUNK_PSG: CHECKED_READ2(28*4, sn76496_regs); break;
case CHUNK_FM: case CHUNK_FM:

View file

@ -14,7 +14,6 @@
extern const unsigned char hcounts_32[]; extern const unsigned char hcounts_32[];
extern const unsigned char hcounts_40[]; extern const unsigned char hcounts_40[];
static unsigned hvlatch; // latched hvcounter value
static int blankline; // display disabled for this line static int blankline; // display disabled for this line
int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, unsigned int *mask) = NULL; int (*PicoDmaHook)(unsigned int source, int len, unsigned short **base, unsigned int *mask) = NULL;
@ -70,7 +69,7 @@ const unsigned char vdpcyc2sl_32[] = { // 68k cycles/4 since HINT to slot #
14,14,14,14,14,14,14,14,15,16,16,16,16,16,16,16, 14,14,14,14,14,14,14,14,15,16,16,16,16,16,16,16,
}; };
const unsigned char vdpsl2cyc_32[] = { // slot # to 68k cycles/4 since HINT const unsigned char vdpsl2cyc_32[] = { // slot # to 68k cycles/4 since HINT
0, 9, 19, 30, 35, 41, 52, 58, 64, 75, 81, 87, 98,104,110,120,121,123,123 0, 9, 19, 30, 35, 41, 52, 58, 64, 75, 81, 87, 98,104,110,120,121,123
}; };
// VDP transfer slots in active display 40col mode. 1 slot is 488/210 = 2.3238 // VDP transfer slots in active display 40col mode. 1 slot is 488/210 = 2.3238
@ -88,33 +87,37 @@ const unsigned char vdpcyc2sl_40[] = { // 68k cycles/4 since HINT to slot #
16,16,16,16,16,16,16,16,17,18,18,18,18,18,18,18, 16,16,16,16,16,16,16,16,17,18,18,18,18,18,18,18,
}; };
const unsigned char vdpsl2cyc_40[] = { // slot # to 68k cycles/4 since HINT const unsigned char vdpsl2cyc_40[] = { // slot # to 68k cycles/4 since HINT
0, 13, 28, 33, 37, 47, 51, 56, 65, 70, 74, 84, 88, 93,102,107,112,120,121,123,123 0, 13, 28, 33, 37, 47, 51, 56, 65, 70, 74, 84, 88, 93,102,107,112,120,121,123
}; };
// NB code assumes fifo_* arrays have size 2^n // NB code assumes fifo_* arrays have size 2^n
// last transferred FIFO data, ...x = index XXX currently only CPU // last transferred FIFO data, ...x = index XXX currently only CPU
static short fifo_data[4], fifo_dx; static short fifo_data[4], fifo_dx; // XXX must go into save?
// queued FIFO transfers, ...x = index, ...l = queue length // queued FIFO transfers, ...x = index, ...l = queue length
// each entry has 2 values: [n]>>2=#writes, [n]&3=flags:2=DMA fill 1=byte access // each entry has 2 values: [n]>>2=#writes, [n]&3=flags:2=DMA fill 1=byte access
static int fifo_queue[8], fifo_qx, fifo_ql; static int fifo_queue[8], fifo_qx, fifo_ql; // XXX must go into save?
signed int fifo_cnt; // pending slots for current queue entry
unsigned short fifo_slot; // last executed slot in current scanline
unsigned int fifo_total; // total# of pending FIFO entries unsigned int fifo_total; // total# of pending FIFO entries
unsigned short fifo_slot; // last executed slot in current scanline
// do the FIFO math // do the FIFO math
static __inline int AdvanceFIFOEntry(int slots) static __inline int AdvanceFIFOEntry(struct PicoVideo *pv, int slots)
{ {
int l = slots, b = fifo_queue[fifo_qx&7] & 1; int l = slots, b = fifo_queue[fifo_qx&7] & 1;
if (l > fifo_cnt) if (l > pv->fifo_cnt)
l = fifo_cnt; l = pv->fifo_cnt;
fifo_total -= ((fifo_cnt & b) + l) >> b; fifo_total -= ((pv->fifo_cnt & b) + l) >> b;
fifo_cnt -= l; pv->fifo_cnt -= l;
if (fifo_cnt == 0) { if (pv->fifo_cnt == 0) {
fifo_qx ++, fifo_ql --; if (fifo_ql)
fifo_cnt= (fifo_queue[fifo_qx&7] >> 2) << (fifo_queue[fifo_qx&7] & 1); fifo_qx ++, fifo_ql --;
if (fifo_ql)
pv->fifo_cnt= (fifo_queue[fifo_qx&7] >> 2) << (fifo_queue[fifo_qx&7] & 1);
else
fifo_total = 0;
} }
return l; return l;
} }
@ -129,7 +132,7 @@ static __inline int GetFIFOSlot(struct PicoVideo *pv, int cycles)
else return (cycles * vdpcyc2sl_bl[h40] + cycles) >> 16; else return (cycles * vdpcyc2sl_bl[h40] + cycles) >> 16;
} }
static inline int GetFIFOCycles(struct PicoVideo *pv, int slot) static __inline int GetFIFOCycles(struct PicoVideo *pv, int slot)
{ {
int active = !(pv->status & SR_VB) && (pv->reg[1] & 0x40); int active = !(pv->status & SR_VB) && (pv->reg[1] & 0x40);
int h40 = pv->reg[12] & 1; int h40 = pv->reg[12] & 1;
@ -146,13 +149,12 @@ void PicoVideoFIFOSync(int cycles)
int slots, done; int slots, done;
// calculate #slots since last executed slot // calculate #slots since last executed slot
slots = GetFIFOSlot(pv, cycles); slots = GetFIFOSlot(pv, cycles) - fifo_slot;
slots -= fifo_slot;
// advance FIFO queue by #done slots // advance FIFO queue by #done slots
done = slots; done = slots;
while (done > 0 && fifo_ql) { while (done > 0 && pv->fifo_cnt) {
int l = AdvanceFIFOEntry(done); int l = AdvanceFIFOEntry(pv, done);
fifo_slot += l; fifo_slot += l;
done -= l; done -= l;
} }
@ -181,7 +183,7 @@ int PicoVideoFIFODrain(int level, int cycles)
int b = fifo_queue[fifo_qx&7] & 1; int b = fifo_queue[fifo_qx&7] & 1;
int cnt = (fifo_total-level) << b; int cnt = (fifo_total-level) << b;
int last = fifo_slot; int last = fifo_slot;
int slot = (fifo_cnt<cnt?fifo_cnt:cnt) + last; // target slot int slot = (pv->fifo_cnt<cnt?pv->fifo_cnt:cnt) + last; // target slot
unsigned ocyc = cycles; unsigned ocyc = cycles;
if (slot > maxsl) { if (slot > maxsl) {
@ -196,7 +198,7 @@ int PicoVideoFIFODrain(int level, int cycles)
} }
burn += cycles - ocyc; burn += cycles - ocyc;
AdvanceFIFOEntry(slot - last); AdvanceFIFOEntry(pv, slot - last);
} }
// release CPU and terminate DMA if FIFO isn't blocking the bus anymore // release CPU and terminate DMA if FIFO isn't blocking the bus anymore
@ -249,7 +251,7 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
// update FIFO state if it was empty // update FIFO state if it was empty
if (fifo_total == 0 && count) { if (fifo_total == 0 && count) {
fifo_slot = GetFIFOSlot(pv, lc); fifo_slot = GetFIFOSlot(pv, lc);
fifo_cnt = count << (flags&1); pv->fifo_cnt = count << (flags&1);
} }
// create xfer queue entry // create xfer queue entry
@ -263,8 +265,8 @@ int PicoVideoFIFOWrite(int count, int flags, unsigned sr_mask,unsigned sr_flags)
if ((pv->status & (PVS_CPUWR|PVS_DMAFILL)) == PVS_CPUWR) if ((pv->status & (PVS_CPUWR|PVS_DMAFILL)) == PVS_CPUWR)
burn = PicoVideoFIFODrain(4, lc); burn = PicoVideoFIFODrain(4, lc);
else if (fifo_queue[fifo_qx&7]&2) { else if (fifo_queue[fifo_qx&7]&2) {
// if interrupting a DMA fill terminate it // if interrupting a DMA fill terminate it XXX wrong, changes fill data
AdvanceFIFOEntry(fifo_cnt); AdvanceFIFOEntry(pv, pv->fifo_cnt);
pv->status &= ~PVS_DMAFILL; pv->status &= ~PVS_DMAFILL;
} }
@ -699,9 +701,9 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
// try avoiding the sync.. // try avoiding the sync..
if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) && if (Pico.m.scanline < (pvid->reg[1]&0x08 ? 240 : 224) && (pvid->reg[1]&0x40) &&
!(!pvid->pending && !(!pvid->pending &&
((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == d)) ((pvid->command & 0xc00000f0) == 0x40000010 && PicoMem.vsram[pvid->addr>>1] == (d & 0x7ff)))
) )
DrawSync(0); DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-440);
if (pvid->pending) { if (pvid->pending) {
CommandChange(); CommandChange();
@ -736,7 +738,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
CommandChange(); CommandChange();
// Check for dma: // Check for dma:
if (d & 0x80) { if (d & 0x80) {
DrawSync(0); DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);
CommandDma(); CommandDma();
} }
} }
@ -747,7 +749,6 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
// Register write: // Register write:
int num=(d>>8)&0x1f; int num=(d>>8)&0x1f;
int dold=pvid->reg[num]; int dold=pvid->reg[num];
int skip=0;
pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II) pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II)
if (num > 0x0a && !(pvid->reg[1]&4)) { if (num > 0x0a && !(pvid->reg[1]&4)) {
elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc); elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc);
@ -755,16 +756,14 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d)
} }
if (num == 0 && !(pvid->reg[0]&2) && (d&2)) if (num == 0 && !(pvid->reg[0]&2) && (d&2))
hvlatch = PicoVideoRead(0x08); pvid->hv_latch = PicoVideoRead(0x08);
if (num == 1 && ((pvid->reg[1]^d)&0x40)) { if (num == 1 && ((pvid->reg[1]^d)&0x40)) {
PicoVideoFIFOMode(d & 0x40); PicoVideoFIFOMode(d & 0x40);
// handle line blanking before line rendering // handle line blanking before line rendering
if (SekCyclesDone() - Pico.t.m68c_line_start <= 488-390) { if (SekCyclesDone() - Pico.t.m68c_line_start <= 488-390)
skip = 1;
blankline = d&0x40 ? -1 : Pico.m.scanline; blankline = d&0x40 ? -1 : Pico.m.scanline;
}
} }
DrawSync(skip); DrawSync(SekCyclesDone() - Pico.t.m68c_line_start <= 488-390);
pvid->reg[num]=(unsigned char)d; pvid->reg[num]=(unsigned char)d;
switch (num) switch (num)
{ {
@ -904,7 +903,7 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a)
d = (SekCyclesDone() - Pico.t.m68c_line_start) & 0x1ff; // FIXME d = (SekCyclesDone() - Pico.t.m68c_line_start) & 0x1ff; // FIXME
if (Pico.video.reg[0]&2) if (Pico.video.reg[0]&2)
d = hvlatch; d = Pico.video.hv_latch;
else if (Pico.video.reg[12]&1) else if (Pico.video.reg[12]&1)
d = hcounts_40[d] | (Pico.video.v_counter << 8); d = hcounts_40[d] | (Pico.video.v_counter << 8);
else d = hcounts_32[d] | (Pico.video.v_counter << 8); else d = hcounts_32[d] | (Pico.video.v_counter << 8);
@ -970,4 +969,33 @@ unsigned char PicoVideoRead8HV_L(void)
return d; return d;
} }
void PicoVideoSave(void)
{
struct PicoVideo *pv = &Pico.video;
int l, x;
// account for all outstanding xfers XXX kludge, entry attr's not saved
for (l = fifo_ql, x = fifo_qx + l-1; l > 1; l--, x--)
pv->fifo_cnt += (fifo_queue[x&7] >> 2) << (fifo_queue[x&7] & 1);
}
void PicoVideoLoad(void)
{
struct PicoVideo *pv = &Pico.video;
int l;
// convert former dma_xfers (why was this in PicoMisc anyway?)
if (Pico.m.dma_xfers) {
pv->fifo_cnt = Pico.m.dma_xfers * (pv->type == 1 ? 2 : 1);
fifo_total = Pico.m.dma_xfers;
Pico.m.dma_xfers = 0;
}
// rebuild SAT cache XXX wrong since cache and memory can differ
for (l = 0; l < 80; l++) {
*((u16 *)VdpSATCache + 2*l ) = PicoMem.vram[(sat>>1) + l*4 ];
*((u16 *)VdpSATCache + 2*l+1) = PicoMem.vram[(sat>>1) + l*4 + 1];
}
}
// vim:shiftwidth=2:ts=2:expandtab // vim:shiftwidth=2:ts=2:expandtab