diff --git a/pico/mode4.c b/pico/mode4.c index 9051cb36..9ed6341e 100644 --- a/pico/mode4.c +++ b/pico/mode4.c @@ -27,18 +27,21 @@ static int CollisionDetect(u8 *mb, u16 sx, unsigned int pack, int zoomed) 0xc0,0xc3,0xcc,0xcf,0xf0,0xf3,0xfc,0xff }; u8 *mp = mb + (sx>>3); unsigned col, m; - // create a pixel bitmap of the sprite pixels from the 4 bitplanes in pack - pack = ((pack | (pack>>16)) | ((pack | (pack>>16))>>8)) & 0xff; - if (zoomed) pack = morton[pack&0x0f] | (morton[(pack>>4)&0x0f] << 8); - // get the corresponding data from the sprite map - m = mp[0] | (mp[1]<<8); - if (zoomed) m |= (mp[2]<<16); - // collision if bits in pixel bitmap overlap bits in sprite map - col = m & (pack<<(sx&7)); - // update sprite map data with our pixel bitmap - m |= pack<<(sx&7); - mp[0] = m, mp[1] = m>>8; - if (zoomed) mp[2] = m>>16; + + // check sprite map for collision and update map with current sprite + if (!zoomed) { // 8 sprite pixels + m = mp[0] | (mp[1]<<8); + col = m & (pack<<(sx&7)); // collision if current sprite overlaps sprite map + m |= pack<<(sx&7); + mp[0] = m, mp[1] = m>>8; + } else { // 16 sprite pixels in zoom mode + pack = morton[pack&0x0f] | (morton[(pack>>4)&0x0f] << 8); + m = mp[0] | (mp[1]<<8) | (mp[2]<<16); + col = m & (pack<<(sx&7)); + m |= pack<<(sx&7); + mp[0] = m, mp[1] = m>>8, mp[2] = m>>16; + } + // invisible overscan area, not tested for collision mb[0] = mb[33] = 0; return col; @@ -53,7 +56,7 @@ static void TileBGM4(u16 sx, int pal) pd[0] = pd[1] = pal * 0x01010101; } -// 8 pixels are arranged to have 1 bit in each byte of a 32 bit word. To pull +// 8 pixels are arranged are arranged in 4 bitplanes in a 32 bit word. To pull // the 4 bitplanes together multiply with each bit distance (multiples of 1<<7) #define PLANAR_PIXELBG(x,p) \ t = (pack>>(7-p)) & 0x01010101; \ @@ -191,6 +194,8 @@ static void DrawSpritesM4(int scanline) 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) @@ -209,20 +214,20 @@ static void DrawStripM4(const u16 *nametab, int cells_dx, int tilex_ty) unsigned int pack; unsigned code; - code = nametab[tilex_ty& 0x1f]; + code = nametab[tilex_ty & 0x1f]; if (code != oldcode) { oldcode = code; // Get tile address/2: addr = (code & 0x1ff) << 4; - addr += tilex_ty>> 16; + addr += tilex_ty >> 16; if (code & 0x0400) addr ^= 0xe; // Y-flip pal = (code>>7) & 0x30; // prio | palette select } - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); /* Get 4 bitplanes / 8 pixels */ + pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); // Get 4 bitplanes / 8 pixels if (pack == 0) TileBGM4(cells_dx, pal); else if (code & 0x0200) TileFlipBGM4(cells_dx, pack, pal); else TileNormBGM4(cells_dx, pack, pal); @@ -296,17 +301,17 @@ static void DrawDisplayM4(int scanline) } -/* Mode 2 */ -/*========*/ +/* TMS Modes */ +/*===========*/ -/* Background */ +/* Background, Graphics modes */ #define TMS_PIXELBG(x,p) \ t = (pack>>(7-p)) & 0x01; \ t = (pal >> (t << 2)) & 0x0f; \ pd[x] = t; -static void TileNormBgM2(u16 sx, unsigned int pack, int pal) +static void TileNormBgGr(u16 sx, unsigned int pack, int pal) { u8 *pd = Pico.est.HighCol + sx; unsigned int t; @@ -328,7 +333,7 @@ static void TileNormBgM2(u16 sx, unsigned int pack, int pal) if (t) \ pd[x] = pal; -static void TileNormSprM2(u16 sx, unsigned int pack, int pal) +static void TileNormSprTMS(u16 sx, unsigned int pack, int pal) { u8 *pd = Pico.est.HighCol + sx; unsigned int t; @@ -343,7 +348,7 @@ static void TileNormSprM2(u16 sx, unsigned int pack, int pal) TMS_PIXELSP(7, 7) } -static void TileDoubleSprM2(u16 sx, unsigned int pack, int pal) +static void TileDoubleSprTMS(u16 sx, unsigned int pack, int pal) { u8 *pd = Pico.est.HighCol + sx; unsigned int t; @@ -367,7 +372,7 @@ static void TileDoubleSprM2(u16 sx, unsigned int pack, int pal) } /* Draw sprites into a scanline, max 4 */ -static void DrawSpritesM2(int scanline) +static void DrawSpritesTMS(int scanline) { struct PicoVideo *pv = &Pico.video; unsigned char mb[256/8+2] = {0}; @@ -425,14 +430,14 @@ static void DrawSpritesM2(int scanline) c = sat[MEM_LE2(i+3)] & 0x0f; if (x > 0) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s])]; - if (zoomed) TileDoubleSprM2(x, pack, c); - else TileNormSprM2(x, pack, c); + if (zoomed) TileDoubleSprTMS(x, pack, c); + else TileNormSprTMS(x, pack, c); if (!m) m = CollisionDetect(mb, x, pack, zoomed); } if((pv->reg[1] & 0x2) && (x+=w) > 0) { pack = PicoMem.vramb[MEM_LE2(sprites_addr[s]+0x10)]; - if (zoomed) TileDoubleSprM2(x, pack, c); - else TileNormSprM2(x, pack, c); + if (zoomed) TileDoubleSprTMS(x, pack, c); + else TileNormSprTMS(x, pack, c); if (!m) m = CollisionDetect(mb, x, pack, zoomed); } } @@ -440,6 +445,9 @@ static void DrawSpritesM2(int scanline) pv->status |= SR_C; } +/* Mode 2 */ +/*========*/ + /* Draw the background into a scanline; cells, dx, tilex, ty merged to reduce registers */ static void DrawStripM2(const u8 *nametab, const u8 *coltab, const u8 *pattab, int cells_dx, int tilex_ty) { @@ -449,10 +457,10 @@ static void DrawStripM2(const u8 *nametab, const u8 *coltab, const u8 *pattab, i unsigned int pack, pal; unsigned code; - code = nametab[tilex_ty& 0x1f] << 3; + code = nametab[tilex_ty & 0x1f] << 3; pal = coltab[code]; pack = pattab[code]; - TileNormBgM2(cells_dx, pack, pal); + TileNormBgGr(cells_dx, pack, pal); } } @@ -484,7 +492,56 @@ static void DrawDisplayM2(int scanline) // sprites if (!(pv->debug_p & PVD_KILL_S_LO)) - DrawSpritesM2(scanline); + DrawSpritesTMS(scanline); +} + +/* Mode 1 */ +/*========*/ + +/* Draw the background into a scanline; cells, dx, tilex, ty merged to reduce registers */ +static void DrawStripM1(const u8 *nametab, const u8 *coltab, const u8 *pattab, int cells_dx, int tilex_ty) +{ + // Draw tiles across screen: + for (; cells_dx > 0; cells_dx += 8, tilex_ty++, cells_dx -= 0x10000) + { + unsigned int pack, pal; + unsigned code; + + code = nametab[tilex_ty & 0x1f]; + pal = coltab[code >> 3]; + pack = pattab[code << 3]; + TileNormBgGr(cells_dx, pack, pal); + } +} + +/* Draw a scanline */ +static void DrawDisplayM1(int scanline) +{ + struct PicoVideo *pv = &Pico.video; + u8 *nametab, *coltab, *pattab; + int tilex, dx, cells; + int cellskip = 0; // XXX + int maxcells = 32; + + // name, color, pattern table: + nametab = PicoMem.vramb + ((pv->reg[2]<<10) & 0x3c00); + coltab = PicoMem.vramb + ((pv->reg[3]<< 6) & 0x3fc0); + pattab = PicoMem.vramb + ((pv->reg[4]<<11) & 0x3800); + + nametab += (scanline>>3) << 5; + pattab += (scanline & 0x7); + + tilex = cellskip & 0x1f; + cells = maxcells - cellskip; + dx = (cellskip << 3) + line_offset + 8; + + // tiles + if (!(pv->debug_p & PVD_KILL_B)) + DrawStripM1(nametab, coltab, pattab, dx | (cells << 16), tilex | (scanline << 16)); + + // sprites + if (!(pv->debug_p & PVD_KILL_S_LO)) + DrawSpritesTMS(scanline); } @@ -568,8 +625,9 @@ void PicoLineSMS(int line) // Draw screen: BackFill(Pico.video.reg[7] & 0x0f, 0, &Pico.est); if (Pico.video.reg[1] & 0x40) { - if (Pico.video.reg[0] & 0x04) DrawDisplayM4(line); - else DrawDisplayM2(line); + if (Pico.video.reg[0] & 0x04) DrawDisplayM4(line); + else if (Pico.video.reg[0] & 0x02) DrawDisplayM2(line); + else DrawDisplayM1(line); } if (FinalizeLineSMS != NULL) diff --git a/pico/sms.c b/pico/sms.c index 5e6d7deb..765a0ae8 100644 --- a/pico/sms.c +++ b/pico/sms.c @@ -195,17 +195,14 @@ static void z80_sms_out(unsigned short a, unsigned char d) case 0xf0: // FM reg port YM2413_regWrite(d); - //printf("write FM register = %02x\n", d); break; case 0xf1: // FM data port YM2413_dataWrite(d); - //printf("write FM data = %02x\n", d); break; case 0xf2: // bit 0 = 1 active FM Pac ymflag = d; - //printf("write FM Check = %02x\n", d); break; } } @@ -261,8 +258,11 @@ static void write_sram(unsigned short a, unsigned char d) // 16KB bank mapping for Sega mapper static void write_bank_sega(unsigned short a, unsigned char d) { - elprintf(EL_Z80BNK, "bank %04x %02x @ %04x", a, d, z80_pc()); + if (Pico.ms.mapper != 1 && d == 0) return; + elprintf(EL_Z80BNK, "bank 16k %04x %02x @ %04x", a, d, z80_pc()); + Pico.ms.mapper = 1; Pico.ms.carthw[a & 0x0f] = d; + switch (a & 0x0f) { case 0x0d: @@ -295,7 +295,8 @@ static void write_bank_sega(unsigned short a, unsigned char d) // 8KB ROM mapping for MSX mapper static void write_bank_msx(unsigned short a, unsigned char d) { - Pico.ms.mapper = 1; // TODO define (more) mapper types + elprintf(EL_Z80BNK, "bank 8k %04x %02x @ %04x", a, d, z80_pc()); + Pico.ms.mapper = 2; // TODO define (more) mapper types Pico.ms.carthw[a] = d; a = (a^2)*0x2000 + 0x4000; @@ -311,20 +312,20 @@ static void xwrite(unsigned int a, unsigned char d) PicoMem.zram[a & 0x1fff] = d; // Sega. Maps 4 bank 16KB each - if (a >= 0xfff8 /*&& !Pico.ms.mapper*/) + if (a >= 0xfff8 && Pico.ms.mapper != 2) write_bank_sega(a, d); // Codemasters. Similar to Sega, but different addresses - if (a == 0x0000 && !Pico.ms.mapper) - write_bank_sega(0xfffd, d); - if (a == 0x4000) +// if (a == 0x0000 && Pico.ms.mapper != 2) +// write_bank_sega(0xfffd, d); + if (a == 0x4000 && Pico.ms.mapper != 2) write_bank_sega(0xfffe, d); - if (a == 0x8000) + if (a == 0x8000 && Pico.ms.mapper != 2) write_bank_sega(0xffff, d); // Korean. 1 selectable 16KB bank at the top - if (a == 0xa000) + if (a == 0xa000 && Pico.ms.mapper != 2) write_bank_sega(0xffff, d); // MSX. 4 selectable 8KB banks at the top - if (a <= 0x0003 && (a || Pico.ms.mapper)) + if (a <= 0x0003 && Pico.ms.mapper != 1 && (a|d)) write_bank_msx(a, d); } @@ -376,6 +377,7 @@ void PicoPowerMS(void) tmp = 1 << s; bank_mask = (tmp - 1) >> 14; + Pico.ms.mapper = 0; PicoReset(); } @@ -398,22 +400,26 @@ void PicoMemSetupMS(void) Cz80_Set_OUTPort(&CZ80, z80_sms_out); #endif - // memory mapper setup, linearly mapped, default is Sega mapper - Pico.ms.carthw[0x00] = 4; - Pico.ms.carthw[0x01] = 5; - Pico.ms.carthw[0x02] = 2; - Pico.ms.carthw[0x03] = 3; - - Pico.ms.carthw[0x0c] = 0; - Pico.ms.carthw[0x0d] = 0; - Pico.ms.carthw[0x0e] = 1; - Pico.ms.carthw[0x0f] = 2; - Pico.ms.mapper = 0; + // memory mapper setup + u8 mapper = Pico.ms.mapper; + if (Pico.ms.mapper == 2) { + xwrite(0x0000, 0); + xwrite(0x0001, 0); + xwrite(0x0002, 0); + xwrite(0x0003, 0); + } else { + xwrite(0xfffc, 0); + xwrite(0xfffd, 0); + xwrite(0xfffe, 1); + xwrite(0xffff, 2); + } + Pico.ms.mapper = mapper; } void PicoStateLoadedMS(void) { - if (Pico.ms.mapper) { + u8 mapper = Pico.ms.mapper; + if (Pico.ms.mapper == 2) { xwrite(0x0000, Pico.ms.carthw[0]); xwrite(0x0001, Pico.ms.carthw[1]); xwrite(0x0002, Pico.ms.carthw[2]); @@ -424,6 +430,7 @@ void PicoStateLoadedMS(void) xwrite(0xfffe, Pico.ms.carthw[0x0e]); xwrite(0xffff, Pico.ms.carthw[0x0f]); } + Pico.ms.mapper = mapper; } void PicoFrameMS(void) diff --git a/platform/common/menu_pico.c b/platform/common/menu_pico.c index 08c291b8..838654dc 100644 --- a/platform/common/menu_pico.c +++ b/platform/common/menu_pico.c @@ -1822,7 +1822,7 @@ static const char *sms_hardwares[] = { "auto", "Game Gear", "Master System", NUL static menu_entry e_menu_sms_options[] = { - mee_enum ("System", MA_SMSOPT_HARDWARE, currentConfig.s_hwSelect, sms_hardwares ), + mee_enum ("System", MA_SMSOPT_HARDWARE, PicoIn.hwSelect, sms_hardwares ), }; static int menu_loop_sms_options(int id, int keys) @@ -1831,7 +1831,6 @@ static int menu_loop_sms_options(int id, int keys) me_loop(e_menu_sms_options, &sel); - PicoIn.hwSelect = currentConfig.s_hwSelect; return 0; }