From: kub Date: Sat, 6 Nov 2021 20:00:55 +0000 (+0100) Subject: sms vdp, separate SAT parsing X-Git-Tag: v2.00~432 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1ce2b0923c65c1270b1d34e73a6f0cca6783c8bf;p=picodrive.git sms vdp, separate SAT parsing --- diff --git a/pico/mode4.c b/pico/mode4.c index 5fda0e7d..3827875d 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -20,6 +20,14 @@ static int skip_next_line; static int screen_offset, line_offset; static u8 mode; +static unsigned int sprites_addr[32]; // bitmap address +static unsigned char sprites_c[32]; // TMS sprites color +static int sprites_x[32]; // x position +static int sprites; // count +static unsigned char sprites_map[2+256/8+2]; // collision detection map + +unsigned int sprites_status; + /* sprite collision detection */ static int CollisionDetect(u8 *mb, u16 sx, unsigned int pack, int zoomed) { @@ -139,17 +147,14 @@ static void TileDoubleSprM4(int sx, unsigned int pack, int pal) PLANAR_PIXELSP(15, 7) } -static void DrawSpritesM4(int scanline) +static void ParseSpritesM4(int scanline) { struct PicoVideo *pv = &Pico.video; - unsigned char mb[1+256/8+2] = {0}; // zoomed - unsigned int sprites_addr[64]; - unsigned int sprites_x[64]; - unsigned int pack; u8 *sat; int xoff = 8; // relative to HighCol, which is (screen - 8) int sprite_base, addr_mask; int zoomed = pv->reg[1] & 0x1; // zoomed sprites, e.g. Earthworm Jim + unsigned int pack; int i, s, h, m; if (pv->reg[0] & 8) @@ -157,7 +162,6 @@ static void DrawSpritesM4(int scanline) xoff += line_offset; if ((Pico.m.hardware & 0x3) == 0x3) xoff -= 48; // GG LCD, adjust to center 160 px - scanline --; sat = (u8 *)PicoMem.vram + ((pv->reg[5] & 0x7e) << 7); if (pv->reg[1] & 2) { @@ -168,6 +172,8 @@ static void DrawSpritesM4(int scanline) if (zoomed) h *= 2; sprite_base = (pv->reg[6] & 4) << (13-2-1); + m = 0; + memset(sprites_map, 0, sizeof(sprites_map)); for (i = s = 0; i < 64; i++) { int y; @@ -180,8 +186,8 @@ static void DrawSpritesM4(int scanline) if (y + h <= scanline || scanline < y) continue; // not on this line if (s >= 8) { - pv->status |= SR_SOVR; - if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 64) + if (scanline >= 0) sprites_status |= SR_SOVR; + if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 32) break; } @@ -189,22 +195,34 @@ static void DrawSpritesM4(int scanline) sprites_x[s] = xoff + sat[MEM_LE2(0x80 + i*2)]; sprites_addr[s] = sprite_base + ((sat[MEM_LE2(0x80 + i*2 + 1)] & addr_mask) << (5-1)) + ((scanline - y) >> zoomed << (2-1)); + if (Pico.video.reg[1] & 0x40) { + // collision detection. Do it here since off-screen lines aren't drawn + pack = CPU_LE2(*(u32 *)(PicoMem.vram + sprites_addr[s])); + // make sprite pixel map by merging the 4 bitplanes + pack = ((pack | (pack>>16)) | ((pack | (pack>>16))>>8)) & 0xff; + if (!m) m = CollisionDetect(sprites_map, sprites_x[s], pack, zoomed); + } s++; } } + if (m) + sprites_status |= SR_C; + sprites = s; +} + +static void DrawSpritesM4(void) +{ + struct PicoVideo *pv = &Pico.video; + unsigned int pack; + int zoomed = pv->reg[1] & 0x1; // zoomed sprites, e.g. Earthworm Jim + int s = sprites; // now draw all sprites backwards - m = 0; for (--s; s >= 0; s--) { pack = CPU_LE2(*(u32 *)(PicoMem.vram + sprites_addr[s])); if (zoomed) TileDoubleSprM4(sprites_x[s], pack, 0x10); else TileNormSprM4(sprites_x[s], pack, 0x10); - // make sprite pixel map by merging the 4 bitplanes - pack = ((pack | (pack>>16)) | ((pack | (pack>>16))>>8)) & 0xff; - if (!m) m = CollisionDetect(mb, sprites_x[s], pack, zoomed); } - if (m) - pv->status |= SR_C; } // cells_dx, tilex_ty merged to reduce register pressure @@ -295,7 +313,7 @@ static void DrawDisplayM4(int scanline) // sprites if (!(pv->debug_p & PVD_KILL_S_LO)) - DrawSpritesM4(scanline); + DrawSpritesM4(); if ((pv->reg[0] & 0x20) && (Pico.m.hardware & 0x3) != 0x3) { // first column masked with background, caculate offset to start of line @@ -376,13 +394,9 @@ static void TileDoubleSprTMS(u16 sx, unsigned int pack, int pal) TMS_PIXELSP(15, 7) } -/* Draw sprites into a scanline, max 4 */ -static void DrawSpritesTMS(int scanline) +static void ParseSpritesTMS(int scanline) { struct PicoVideo *pv = &Pico.video; - unsigned char mb[1+256/8+4] = {0}; // zoomed+doublesize - unsigned int sprites_addr[32]; - unsigned int sprites_x[32]; unsigned int pack; u8 *sat; int xoff = 8; // relative to HighCol, which is (screen - 8) @@ -391,7 +405,6 @@ static void DrawSpritesTMS(int scanline) int i, s, h, m; xoff += line_offset; - scanline --; sat = (u8 *)PicoMem.vramb + ((pv->reg[5] & 0x7e) << 7); if (pv->reg[1] & 2) { @@ -400,13 +413,14 @@ static void DrawSpritesTMS(int scanline) addr_mask = 0xff; h = 8; } if (zoomed) h *= 2; - sprite_base = (pv->reg[6] & 0x7) << 11; + m = 0; + memset(sprites_map, 0, sizeof(sprites_map)); /* find sprites on this scanline */ for (i = s = 0; i < 32; i++) { - int y; + int x, y; y = sat[MEM_LE2(4*i)]; if (y == 0xd0) break; @@ -416,42 +430,62 @@ static void DrawSpritesTMS(int scanline) if (y + h <= scanline || scanline < y) continue; // not on this line if (s >= 4) { - pv->status |= SR_SOVR | i; + if (scanline >= 0) sprites_status |= SR_SOVR | i; if (!(PicoIn.opt & POPT_DIS_SPRITE_LIM) || s >= 32) break; } + x = sat[MEM_LE2(4*i+1)] + xoff; + if (sat[MEM_LE2(4*i+3)] & 0x80) + x -= 32; - sprites_x[s] = 4*i; + sprites_c[s] = sat[MEM_LE2(4*i+3)] & 0x0f; + sprites_x[s] = x; sprites_addr[s] = sprite_base + ((sat[MEM_LE2(4*i + 2)] & addr_mask) << 3) + ((scanline - y) >> zoomed); + if (Pico.video.reg[1] & 0x40) { + // collision detection. Do it here since off-screen lines aren't drawn + if (sprites_c[s] && x > 0) { + pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])]; + if (!m) m = CollisionDetect(sprites_map, x, pack, zoomed); + } + x += (zoomed ? 16:8); + if (sprites_c[s] && (pv->reg[1] & 0x2) && x > 0 && x < 8+256) { + pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)]; + if (!m) m = CollisionDetect(sprites_map, x, pack, zoomed); + } + } s++; } + if (m) + sprites_status |= SR_C; + sprites = s; +} + +/* Draw sprites into a scanline, max 4 */ +static void DrawSpritesTMS(void) +{ + struct PicoVideo *pv = &Pico.video; + unsigned int pack; + int zoomed = pv->reg[1] & 0x1; // zoomed sprites + int s = sprites; // now draw all sprites backwards - m = 0; for (--s; s >= 0; s--) { int x, c, w = (zoomed ? 16: 8); - i = sprites_x[s]; - x = sat[MEM_LE2(i+1)] + xoff; - if (sat[MEM_LE2(i+3)] & 0x80) - x -= 32; - c = sat[MEM_LE2(i+3)] & 0x0f; + x = sprites_x[s]; + c = sprites_c[s]; // c may be 0 (transparent): sprite invisible - if (x > 0) { + if (c && x > 0) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])]; - if (zoomed && c) TileDoubleSprTMS(x, pack, c); - else if (c) TileNormSprTMS(x, pack, c); - if (!m) m = CollisionDetect(mb, x, pack, zoomed); + if (zoomed) TileDoubleSprTMS(x, pack, c); + else TileNormSprTMS(x, pack, c); } - if((pv->reg[1] & 0x2) && (x+=w) > 0 && x < 8+256) { + if (c && (pv->reg[1] & 0x2) && (x+=w) > 0 && x < 8+256) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)]; - if (zoomed && c) TileDoubleSprTMS(x, pack, c); - else if (c) TileNormSprTMS(x, pack, c); - if (!m) m = CollisionDetect(mb, x, pack, zoomed); + if (zoomed) TileDoubleSprTMS(x, pack, c); + else TileNormSprTMS(x, pack, c); } } - if (m) - pv->status |= SR_C; } /* Mode 2 */ @@ -501,7 +535,7 @@ static void DrawDisplayM2(int scanline) // sprites if (!(pv->debug_p & PVD_KILL_S_LO)) - DrawSpritesTMS(scanline); + DrawSpritesTMS(); } /* Mode 0 */ @@ -550,7 +584,7 @@ static void DrawDisplayM0(int scanline) // sprites if (!(pv->debug_p & PVD_KILL_S_LO)) - DrawSpritesTMS(scanline); + DrawSpritesTMS(); } @@ -609,6 +643,7 @@ void PicoFrameStartSMS(void) emu_video_mode_change(loffs, lines, coffs, columns); rendstatus_old = Pico.est.rendstatus; rendlines = lines; + sprites = 0; } Pico.est.HighCol = HighColBase + screen_offset * HighColIncrement; @@ -621,6 +656,12 @@ void PicoFrameStartSMS(void) } } +void PicoParseSATSMS(int line) +{ + if (Pico.video.reg[0] & 0x04) ParseSpritesM4(line); + else ParseSpritesTMS(line); +} + void PicoLineSMS(int line) { int skip = skip_next_line; diff --git a/pico/pico_int.h b/pico/pico_int.h index e6da5182..a1990296 100644 --- a/pico/pico_int.h +++ b/pico/pico_int.h @@ -704,6 +704,7 @@ PICO_INTERNAL void PicoFrameFull(); // mode4.c void PicoFrameStartSMS(void); +void PicoParseSATSMS(int line); void PicoLineSMS(int line); void PicoDoHighPal555SMS(void); void PicoDrawSetOutputSMS(pdso_t which); diff --git a/pico/sms.c b/pico/sms.c index a65fe415..fd29fa32 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -20,6 +20,7 @@ extern void YM2413_regWrite(unsigned reg); extern void YM2413_dataWrite(unsigned data); +extern unsigned sprites_status; // TODO put in some hdr file! static unsigned char vdp_data_read(void) { @@ -583,7 +584,7 @@ void PicoMemSetupMS(void) z80_map_set(z80_write_map, 0x0000, 0xbfff, xwrite, 1); z80_map_set(z80_write_map, 0xc000, 0xdfff, PicoMem.zram, 0); z80_map_set(z80_write_map, 0xe000, 0xffff, xwrite, 1); - + // Nemesis mapper maps last 8KB rom bank #15 to adress 0 if (Pico.ms.mapper == PMS_MAP_NEMESIS && Pico.romsize > 0x1e000) z80_map_set(z80_read_map, 0x0000, 0x1fff, Pico.rom + 0x1e000, 0); @@ -682,9 +683,15 @@ void PicoFrameMS(void) PicoFrameStartSMS(); hint = pv->reg[0x0a]; + // SMS: xscroll:f3 sprovr,vint, vcount:fc, hint:fd + // GG: xscroll:f5 sprovr,vint:fd vcount:fe, hint:ff for (y = 0; y < lines; y++) { - pv->v_counter = Pico.m.scanline = y; + Pico.t.z80c_line_start = Pico.t.z80c_aim; + + // advance the line counter. It is set back at some point in the VBLANK so + // that the line count in the active area (-32..lines+1) is contiguous. + pv->v_counter = Pico.m.scanline = (u8)y; switch (is_pal ? -lines_vis : lines_vis) { case 192: if (y > 218) pv->v_counter = y - (lines-256); break; case 224: if (y > 234) pv->v_counter = y - (lines-256); break; @@ -693,14 +700,24 @@ void PicoFrameMS(void) case -240: if (y > 266) pv->v_counter = y - (lines-256); break; } + // Parse sprites for the next line + if (y < lines_vis) + PicoParseSATSMS(y-1); + else if (y > lines-32) + PicoParseSATSMS(y-1-lines); + + // render next line if (y < lines_vis && !skip) PicoLineSMS(y); - Pico.t.z80c_line_start = Pico.t.z80c_aim; + // take over status bits from previously rendered line TODO: cycle exact? + pv->status |= sprites_status; + sprites_status = 0; // Interrupt handling. Simulate interrupt flagged and immediately reset in // same insn by flagging the irq, execute for 1 insn, then checking if the // irq is still pending. (GG Chicago, SMS Back to the Future III) + pv->pending_ints &= ~2; // lost if not caught in the same line if (y <= lines_vis) { if (--hint < 0) @@ -713,11 +730,9 @@ void PicoFrameMS(void) elprintf(EL_INTS, "hint"); z80_int_assert(1); } - pv->pending_ints &= ~2; // lost if not caught immediately } } else if (y == lines_vis + 1) { - pv->pending_ints &= ~2; pv->pending_ints |= 1; z80_exec(Pico.t.z80c_cnt + 1); @@ -736,13 +751,18 @@ void PicoFrameMS(void) void PicoFrameDrawOnlyMS(void) { + struct PicoVideo *pv = &Pico.video; int lines_vis = 192; int y; + if ((pv->reg[0] & 6) == 6 && (pv->reg[1] & 0x18)) + lines_vis = (pv->reg[1] & 0x08) ? 240 : 224; PicoFrameStartSMS(); - for (y = 0; y < lines_vis; y++) + for (y = 0; y < lines_vis; y++) { + PicoParseSATSMS(y-1); PicoLineSMS(y); + } } // vim:ts=2:sw=2:expandtab