diff --git a/pico/draw.c b/pico/draw.c index 236e347e..38b920d6 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -1688,13 +1688,13 @@ void FinalizeLine8bit(int sh, int line, struct PicoEState *est) int len; static int dirty_line; + // a hack for mid-frame palette changes if (Pico.m.dirtyPal == 1) { - // a hack for mid-frame palette changes - if (!(est->rendstatus & PDRAW_SONIC_MODE) | (line - dirty_line > 4)) { - // store a maximum of 3 additional palettes in SonicPal - if (est->SonicPalCount < 3) - est->SonicPalCount ++; + // store a maximum of 2 additional palettes in SonicPal + if (est->SonicPalCount < 2 && + (!(est->rendstatus & PDRAW_SONIC_MODE) || (line - dirty_line > 4))) { + est->SonicPalCount ++; dirty_line = line; est->rendstatus |= PDRAW_SONIC_MODE; } @@ -1854,7 +1854,6 @@ static int DrawDisplay(int sh) PICO_INTERNAL void PicoFrameStart(void) { int loffs = 8, lines = 224, coffs = 0, columns = 320; - int dirty = ((Pico.est.rendstatus & PDRAW_SONIC_MODE) || Pico.m.dirtyPal); int sprep = Pico.est.rendstatus & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES); int skipped = Pico.est.rendstatus & PDRAW_SKIP_FRAME; @@ -1896,7 +1895,7 @@ PICO_INTERNAL void PicoFrameStart(void) if (FinalizeLine == FinalizeLine8bit) { // make a backup of the current palette in case Sonic mode is detected later Pico.est.SonicPalCount = 0; - Pico.m.dirtyPal = (dirty ? 2 : 0); // mark as dirty but already copied + Pico.m.dirtyPal = (Pico.m.dirtyPal ? 2 : 0); // mark as dirty but copied blockcpy(Pico.est.SonicPal, PicoMem.cram, 0x40*2); } } @@ -2011,6 +2010,8 @@ void PicoDrawUpdateHighPal(void) blockcpy(est->HighPal+0x40, est->HighPal, 0x40*2); blockcpy(est->HighPal+0x80, est->HighPal, 0x80*2); } + Pico.est.HighPal[0xe0] = 0x0000; // black and white, reserved for OSD + Pico.est.HighPal[0xf0] = 0xffff; } } diff --git a/pico/mode4.c b/pico/mode4.c index 0525b935..9d9235ab 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -465,6 +465,7 @@ static void DrawDisplayM2(int scanline) /*===============*/ static void FinalizeLineRGB555SMS(int line); +static void FinalizeLine8bitSMS(int line); void PicoFrameStartSMS(void) { @@ -513,6 +514,12 @@ void PicoFrameStartSMS(void) Pico.est.HighCol = HighColBase + screen_offset * HighColIncrement; Pico.est.DrawLineDest = (char *)DrawLineDestBase + screen_offset * DrawLineDestIncrement; + + if (FinalizeLineSMS == FinalizeLine8bitSMS) { + Pico.est.SonicPalCount = 0; + Pico.m.dirtyPal = (Pico.m.dirtyPal ? 2 : 0); + memcpy(Pico.est.SonicPal, PicoMem.cram, 0x20*2); + } } void PicoLineSMS(int line) @@ -557,32 +564,45 @@ static u16 tmspal[32] = { void PicoDoHighPal555SMS(void) { - u32 *spal=(void *)PicoMem.cram; - u32 *dpal=(void *)Pico.est.HighPal; + u32 *spal = (void *)Pico.est.SonicPal; + u32 *dpal = (void *)Pico.est.HighPal; + unsigned int cnt = Pico.est.SonicPalCount+1; unsigned int t; - int i; + int i, j; + + if (FinalizeLineSMS != FinalizeLine8bitSMS || Pico.m.dirtyPal == 2) + Pico.m.dirtyPal = 0; - Pico.m.dirtyPal = 0; - if (!(Pico.video.reg[0] & 0x4)) + // use hardware palette for 16bit accurate mode + if (FinalizeLineSMS == FinalizeLineRGB555SMS) + spal = (void *)PicoMem.cram; + + // fixed palette in TMS modes + if (!(Pico.video.reg[0] & 0x4)) { spal = (u32 *)tmspal; + cnt = 1; + } /* SMS 6 bit cram data was already converted to MD/GG format by vdp write, * hence GG/SMS/TMS can all be handled the same here */ - for (i = 0x20/2; i > 0; i--, spal++, dpal++) { - t = *spal; + for (j = cnt; j > 0; j--) { + for (i = 0x20/2; i > 0; i--, spal++, dpal++) { + t = *spal; #if defined(USE_BGR555) - t = ((t & 0x000f000f)<< 1) | ((t & 0x00f000f0)<<2) | ((t & 0x0f000f00)<<3); - t |= (t >> 4) & 0x04210421; + t = ((t & 0x000f000f)<< 1) | ((t & 0x00f000f0)<<2) | ((t & 0x0f000f00)<<3); + t |= (t >> 4) & 0x04210421; #elif defined(USE_BGR565) - t = ((t & 0x000f000f)<< 1) | ((t & 0x00f000f0)<<3) | ((t & 0x0f000f00)<<4); - t |= (t >> 4) & 0x08610861; + t = ((t & 0x000f000f)<< 1) | ((t & 0x00f000f0)<<3) | ((t & 0x0f000f00)<<4); + t |= (t >> 4) & 0x08610861; #else - t = ((t & 0x000f000f)<<12) | ((t & 0x00f000f0)<<3) | ((t & 0x0f000f00)>>7); - t |= (t >> 4) & 0x08610861; + t = ((t & 0x000f000f)<<12) | ((t & 0x00f000f0)<<3) | ((t & 0x0f000f00)>>7); + t |= (t >> 4) & 0x08610861; #endif - *dpal = t; + *dpal = t; + } + memcpy(dpal, dpal-0x20/2, 0x20*2); // for prio bit + spal += 0x20/2, dpal += 0x20/2; } - memcpy(&Pico.est.HighPal[0x20], Pico.est.HighPal, 0x20*2); // for prio bit Pico.est.HighPal[0xe0] = 0; } diff --git a/pico/sms.c b/pico/sms.c index 78fce13b..7940f5fb 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -21,13 +21,15 @@ extern void YM2413_dataWrite(unsigned data); static unsigned short ymflag = 0xffff; +static u8 vdp_buffer; static unsigned char vdp_data_read(void) { struct PicoVideo *pv = &Pico.video; unsigned char d; - d = PicoMem.vramb[MEM_LE2(pv->addr)]; + d = vdp_buffer; + vdp_buffer = PicoMem.vramb[MEM_LE2(pv->addr)]; pv->addr = (pv->addr + 1) & 0x3fff; pv->pending = 0; return d; @@ -54,12 +56,14 @@ static void vdp_data_write(unsigned char d) if (pv->type == 3) { if (Pico.m.hardware & 0x1) { // GG, same layout as MD unsigned a = pv->addr & 0x3f; - if (a & 0x1) d &= 0x0f; - if (((u8 *)PicoMem.cram)[MEM_LE2(a)] != d) Pico.m.dirtyPal = 1; - ((u8 *)PicoMem.cram)[MEM_LE2(a)] = d; + if (a & 0x1) { // write complete color on high byte write + u16 c = ((d&0x0f) << 8) | vdp_buffer; + if (PicoMem.cram[a >> 1] != c) Pico.m.dirtyPal = 1; + PicoMem.cram[a >> 1] = c; + } } else { // SMS, convert to MD layout (00BbGgRr to 0000BbBbGgGgRrRr) unsigned a = pv->addr & 0x1f; - u16 c = (d&0x30)*0x40 + (d&0x0c)*0x10 + (d&0x03)*0x04; + u16 c = ((d&0x30)<<6) + ((d&0x0c)<<4) + ((d&0x03)<<2); if (PicoMem.cram[a] != (c | (c>>2))) Pico.m.dirtyPal = 1; PicoMem.cram[a] = c | (c>>2); } @@ -68,6 +72,7 @@ static void vdp_data_write(unsigned char d) } pv->addr = (pv->addr + 1) & 0x3fff; + vdp_buffer = d; pv->pending = 0; } @@ -95,14 +100,18 @@ static void vdp_ctl_write(u8 d) struct PicoVideo *pv = &Pico.video; if (pv->pending) { - if ((d >> 6) == 2) { + pv->type = d >> 6; + if (pv->type == 2) { elprintf(EL_IO, " VDP r%02x=%02x", d & 0x0f, pv->addr & 0xff); if (pv->reg[d & 0x0f] != (u8)pv->addr) vdp_reg_write(pv, d & 0x0f, pv->addr); } - pv->type = d >> 6; pv->addr &= 0x00ff; pv->addr |= (d & 0x3f) << 8; + if (pv->type == 0) { + vdp_buffer = PicoMem.vramb[MEM_LE2(pv->addr)]; + pv->addr = (pv->addr + 1) & 0x3fff; + } } else { pv->addr &= 0x3f00; pv->addr |= d; @@ -147,8 +156,12 @@ static unsigned char z80_sms_in(unsigned short a) elprintf(EL_HVCNT, "V counter read: %02x", d); break; - case 0x41: /* H counter */ - d = Pico.m.rotate++; + case 0x41: /* H counter, TODO: latched by toggle of pad TH line */ + // 171 slots per scanline of 228 clocks, runs from 0x85-0x93,0xe9-0x84 +#define CYC2SLOT (256 * 171/228) // cycles to slot factor in Q8 + d = 228-z80_cyclesLeft; + if (d <= 19) d = (( d * CYC2SLOT)>>8) + 0x85; + else d = (((d-20) * CYC2SLOT)>>8) + 0xe9; elprintf(EL_HVCNT, "H counter read: %02x", d); break; @@ -404,7 +417,7 @@ void PicoFrameMS(void) struct PicoVideo *pv = &Pico.video; int is_pal = Pico.m.pal; int lines = is_pal ? 313 : 262; - int cycles_line = is_pal ? 58020 : 58293; /* (226.6 : 227.7) * 256 */ + int cycles_line = 228; int cycles_done = 0, cycles_aim = 0; int skip = PicoIn.skipFrame; int lines_vis = 192; @@ -454,8 +467,8 @@ void PicoFrameMS(void) } cycles_aim += cycles_line; - Pico.t.z80c_aim = cycles_aim >> 8; - cycles_done += z80_run((cycles_aim - cycles_done) >> 8) << 8; + Pico.t.z80c_aim = cycles_aim; + cycles_done += z80_run(cycles_aim - cycles_done); } if (PicoIn.sndOut)