diff --git a/sys/src/games/snes/dat.h b/sys/src/games/snes/dat.h index 04338452b..666039208 100644 --- a/sys/src/games/snes/dat.h +++ b/sys/src/games/snes/dat.h @@ -10,9 +10,11 @@ extern u32int keys, keylatch, lastkeys; extern u8int reg[32768], spcmem[65536], vram[65536], oam[544]; extern u16int cgram[256]; -extern int ppux, ppuy; +extern int ppux, ppuy, rx; extern u16int vtime, htime, subcolor, oamaddr; -extern u16int m7[6], hofs[4], vofs[4]; +extern u16int hofs[5], vofs[5]; +typedef signed short s16int; +extern s16int m7[6]; extern int battery, saveclock, scale, mouse; @@ -43,6 +45,7 @@ enum { OAMADDH = 0x2103, BGMODE = 0x2105, MOSAIC = 0x2106, + M7SEL = 0x211a, WIN1 = 2, INVW1 = 1, WIN2 = 8, @@ -55,6 +58,7 @@ enum { CGADSUB = 0x2131, DIRCOL = 1, SETINI = 0x2133, + EXTBG = 1<<6, OVERSCAN = 1<<2, AUTOJOY = 1, NMITIMEN = 0x4200, diff --git a/sys/src/games/snes/mem.c b/sys/src/games/snes/mem.c index 9fd17aa86..330615d27 100644 --- a/sys/src/games/snes/mem.c +++ b/sys/src/games/snes/mem.c @@ -21,6 +21,8 @@ enum { OPVCTH, }; +extern void calc7(void); + static void incvram(int i, int r) { @@ -220,15 +222,29 @@ regwrite(u16int p, u8int v) oam[oamaddr & 0x21f] = v; oamaddr = (oamaddr + 1) & 0x3ff; return; - case 0x210d: case 0x210f: - case 0x2111: case 0x2113: + case 0x2105: + reg[p] = v; + calc7(); + return; + case 0x210d: + hofs[4] = (v & 0x1f) << 8 | reg[M7PREV]; + if((v & 0x10) != 0) + hofs[4] |= 0xe000; + reg[M7PREV] = v; + calc7(); + case 0x210f: case 0x2111: case 0x2113: a = (p - 0x210d) >> 1; - hofs[a] = (v << 8) | reg[OFSPREV] & ~7 | (hofs[a] >> 8) & 7; + hofs[a] = v << 8 | reg[OFSPREV] & ~7 | (hofs[a] >> 8) & 7; reg[OFSPREV] = v; break; - case 0x210e: case 0x2110: - case 0x2112: case 0x2114: - vofs[(p - 0x210e) >> 1] = (v << 8) | reg[OFSPREV]; + case 0x210e: + vofs[4] = (v & 0x1f) << 8 | reg[M7PREV]; + if((v & 0x10) != 0) + vofs[4] |= 0xe000; + reg[M7PREV] = v; + calc7(); + case 0x2110: case 0x2112: case 0x2114: + vofs[(p - 0x210e) >> 1] = v << 8 | reg[OFSPREV]; reg[OFSPREV] = v; break; case 0x2116: @@ -248,8 +264,14 @@ regwrite(u16int p, u8int v) return; case 0x211b: case 0x211c: case 0x211d: case 0x211e: case 0x211f: case 0x2120: - m7[p - 0x211b] = (v << 8) | reg[M7PREV]; + m7[p - 0x211b] = v << 8 | reg[M7PREV]; + if(p >= 0x211f) + if((v & 0x10) != 0) + m7[p - 0x211b] |= 0xe000; + else + m7[p - 0x211b] &= 0x1fff; reg[M7PREV] = v; + calc7(); break; case 0x2121: reg[CGLH] = 0; diff --git a/sys/src/games/snes/ppu.c b/sys/src/games/snes/ppu.c index 808165d8d..41d23441d 100644 --- a/sys/src/games/snes/ppu.c +++ b/sys/src/games/snes/ppu.c @@ -9,7 +9,17 @@ static u8int mode, bright, pixelpri[2]; static u32int pixelcol[2]; u16int vtime = 0x1ff, htime = 0x1ff, subcolor, mosatop; uchar pic[256*239*2*9]; -u16int m7[6], hofs[4], vofs[4]; +u16int hofs[5], vofs[5]; +s16int m7[6]; + +enum { + M7A, + M7B, + M7C, + M7D, + M7X, + M7Y +}; enum { OBJ = 4, COL = 5, OBJNC = 8 }; @@ -311,6 +321,113 @@ bg(int n) chr(n, p->nb, p->sz, p->t, p->tnx, p->tny, p->c); } +struct bg7ctxt { + int x, y, x0, y0; + u8int msz, mx, mv; +} b7[2]; + +void +calc7(void) +{ + s16int t; + + if((reg[0x2105] & 7) != 7) + return; + t = hofs[4] - m7[M7X]; + if((t & 0x2000) != 0) + t |= ~0x3ff; + else + t &= 0x3ff; + b7->x0 = (t * m7[M7A]) & ~63; + b7->y0 = (t * m7[M7C]) & ~63; + t = vofs[4] - m7[M7Y]; + if((t & 0x2000) != 0) + t |= ~0x3ff; + else + t &= 0x3ff; + b7->x0 += (t * m7[M7B]) & ~63; + b7->y0 += (t * m7[M7D]) & ~63; + b7->x0 += m7[M7X] << 8; + b7->y0 += m7[M7Y] << 8; +} + +static void +bg7init(int n) +{ + u8int m, y; + struct bg7ctxt *p; + + p = b7 + n; + m = reg[M7SEL]; + y = ppuy; + p->msz = 1; + if((reg[MOSAIC] & 1) != 0){ + p->msz = (reg[MOSAIC] >> 4) + 1; + if(p->msz != 1) + y -= y % p->msz; + } + if(n == 1 && (reg[MOSAIC] & 2) != 0) + p->msz = (reg[MOSAIC] >> 4) + 1; + if((m & 2) != 0) + y = 255 - y; + p->x = b7->x0 + ((m7[M7B] * y) & ~63); + p->y = b7->y0 + ((m7[M7D] * y) & ~63); + if((m & 1) != 0){ + p->x += 255 * m7[M7A]; + p->y += 255 * m7[M7C]; + } +} + +static void +bg7(int n) +{ + u16int x, y; + u8int m, v, t; + struct bg7ctxt *p; + + p = b7 + n; + m = reg[M7SEL]; + x = p->x >> 8; + y = p->y >> 8; + if((m & 0x80) == 0){ + x &= 1023; + y &= 1023; + }else if(x > 1023 || y > 1023){ + if((m & 0x40) != 0){ + t = 0; + goto lookup; + } + v = 0; + goto end; + } + t = vram[x >> 2 & 0xfe | y << 5 & 0x7f00]; +lookup: + v = vram[t << 7 | y << 4 & 0x70 | x << 1 & 0x0e | 1]; +end: + if(p->msz != 1){ + if(p->mx == 0) + p->mv = v; + else + v = p->mv; + if(++p->mx == p->msz) + p->mx = 0; + } + if(n == 1) + if((v & 0x80) != 0) + pixel(1, v & 0x7f, 0x71); + else + pixel(1, v, 0x11); + else + pixel(0, v, 0x40); + if((m & 1) != 0){ + p->x -= m7[M7A]; + p->y -= m7[M7C]; + }else{ + p->x += m7[M7A]; + p->y += m7[M7C]; + } +} + static void bgsinit(void) { @@ -336,6 +453,11 @@ bgsinit(void) bginit(0, 8, 0x40, 0xa0); bginit(1, 4, 0x11, 0x71); break; + case 7: + bg7init(0); + if((reg[SETINI] & EXTBG) != 0) + bg7init(1); + break; default: bgctxts[0].sz = bgctxts[1].sz = 0; if(bitch[mode]++ == 0) @@ -363,6 +485,11 @@ bgs(void) bg(0); bg(1); break; + case 7: + bg7(0); + if((reg[SETINI] & EXTBG) != 0) + bg7(1); + break; } } diff --git a/sys/src/games/snes/spc.c b/sys/src/games/snes/spc.c index 9cabeb92e..6bba2c979 100644 --- a/sys/src/games/snes/spc.c +++ b/sys/src/games/snes/spc.c @@ -442,6 +442,7 @@ spcstep(void) if(trace) print("SPC %.4x %.2x A=%.2x X=%.2x Y=%.2x P=%.2x S=%.2x\n", spc-1, op, sA, sX, sY, sP, sS); switch(op){ + case 0x00: return 2; case 0x01: jsr(mem16(0xffde)); return 8; case 0x02: setb(azp(), 0); return 4; case 0x03: return branch((zp() & 0x01) != 0, 5);