X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2Fgames%2Fsnes%2Fppu.c;h=5819e032c10b30de478675dc4ed3bdb6bd6c3563;hb=1195ca910c393e542d6aa23035fa75719af1107e;hp=a0c82443eebc8cc6a8e9bd2d2eceb7a08f1804ad;hpb=8d11fd6d274a0792ebb64dcc89e2b8c087888fab;p=plan9front.git diff --git a/sys/src/games/snes/ppu.c b/sys/src/games/snes/ppu.c index a0c82443e..5819e032c 100644 --- a/sys/src/games/snes/ppu.c +++ b/sys/src/games/snes/ppu.c @@ -1,17 +1,27 @@ #include #include #include +#include #include "dat.h" #include "fns.h" int ppux, ppuy, rx; -static u8int mode, bright, pixelpri[2]; +static u8int mode, bright, pixelpri[2], hires; 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 vtime = 0x1ff, htime = 0x1ff, subcolor; +u16int hofs[5], vofs[5]; +s16int m7[6]; -enum { OBJ = 4, COL = 5, OBJNC = 6 }; +enum { + M7A, + M7B, + M7C, + M7D, + M7X, + M7Y +}; + +enum { OBJ = 4, COL = 5, OBJNC = 8 }; static u16int darken(u16int v) @@ -28,38 +38,33 @@ darken(u16int v) } static void -pixeldraw(int x, int y, u16int v) +pixeldraw(int x, int y, u16int v, int s) { - uchar *p; - u16int *q; + u16int *p; union { u16int w; u8int b[2]; } u; - int i; - if(bright != 0xf) + if(bright != 0xf && s >= 0) v = darken(v); - if(scale == 1){ - p = pic + (x + y * 256) * 2; - *p++ = v; - *p = v >> 8; - return; - } + p = (u16int *)pic + (x + y * 256) * scale; u.b[0] = v; u.b[1] = v >> 8; - if(scale == 2){ - q = (u16int*)pic + (x + y * 256 * 2) * 2; - *q++ = u.w; - *q = u.w; - q += 256 * 2 - 1; - *q++ = u.w; - *q = u.w; - }else{ - q = (u16int*)pic + (x + y * 256 * 3) * 3; - for(i = 0; i < 3; i++){ - *q++ = u.w; - *q++ = u.w; - *q = u.w; - q += 256 * 3 - 2; - } + switch(scale){ + case 16: *p++ = u.w; + case 15: *p++ = u.w; + case 14: *p++ = u.w; + case 13: *p++ = u.w; + case 12: *p++ = u.w; + case 11: *p++ = u.w; + case 10: *p++ = u.w; + case 9: *p++ = u.w; + case 8: *p++ = u.w; + case 7: *p++ = u.w; + case 6: *p++ = u.w; + case 5: *p++ = u.w; + case 4: *p++ = u.w; + case 3: *p++ = u.w; + case 2: if(s < 1) *p++ = u.w; + default: *p = u.w; } } @@ -91,7 +96,7 @@ window(int n) } static void -pixel(int n, int v, int pri) +npixel(int n, int v, int pri) { int a; @@ -106,6 +111,32 @@ pixel(int n, int v, int pri) } } +static void +spixel(int n, int v, int pri) +{ + int a; + + a = 1< pixelpri[1] && ((reg[TSW] & a) == 0 || !window(n))){ + pixelcol[1] = v; + pixelpri[1] = pri; + } +} + +static void +mpixel(int n, int v, int pri) +{ + int a; + + a = 1< pixelpri[0] && ((reg[TMW] & a) == 0 || !window(n))){ + pixelcol[0] = v; + pixelpri[0] = pri; + } +} + +static void (*pixel)(int, int, int) = npixel; + static u16int tile(int n, int tx, int ty) { @@ -124,16 +155,18 @@ tile(int n, int tx, int ty) } static void -chr(int n, int nb, int sz, u16int t, int x, int y, u32int c[]) +chr(int n, int nb, int w, int h, u16int t, int x, int y, u32int c[]) { u16int a; - if(sz == 16){ + if(w == 16) + t += (x >> 3 ^ t >> 14) & 1; + if(h == 16){ if(y >= 8){ - t += ((x >> 3 ^ t >> 14) & 1) + ((~t >> 11) & 16); + t += (~t >> 11) & 16; y -= 8; }else - t += ((x >> 3 ^ t >> 14) & 1) + ((t >> 11) & 16); + t += (t >> 11) & 16; } if((t & 0x8000) != 0) y = 7 - y; @@ -231,54 +264,71 @@ bgpixel(u32int *c, int nb, int d) return v; } +static struct bgctxt { + u8int w, h, wsh, hsh, nb, pri[2]; + u16int tx, ty, tnx, tny; + u16int t; + u32int c[2]; + int pal; + u8int msz, mv, mx; + u16int otx, oty, otny; +} bgctxts[4]; + static void -bg(int n, int nb, int prilo, int prihi) +bginit(int n, int nb, int prilo, int prihi) { - static struct bg { - u8int sz, szsh; - u16int tx, ty, tnx, tny; - u16int t; - u32int c[2]; - int pal; - u8int msz, mv, mx; - } bgs[4]; - struct bg *p; - int v, sx, sy; - - p = bgs + n; - if(rx == 0){ - p->szsh = (reg[BGMODE] & (1<<(4+n))) != 0 ? 4 : 3; - p->sz = 1<szsh; - sx = hofs[n]; - sy = vofs[n] + ppuy; - if(reg[MOSAIC] != 0 && (reg[MOSAIC] & (1<msz = (reg[MOSAIC] >> 4) + 1; - if(p->msz != 1){ - sx -= p->mx = sx % p->msz; - sy -= sy % p->msz; - } - }else - p->msz = 1; - redo: - p->tx = sx >> p->szsh; - p->tnx = sx & (p->sz - 1); - p->ty = sy >> p->szsh; - p->tny = sy & (p->sz - 1); - p->t = tile(n, p->tx, p->ty); - chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c); - p->pal = palette(n, p->t >> 10 & 7); - if(p->tnx != 0) - shift(p->c, nb, p->tnx, p->t & 0x4000); - if(p->msz != 1 && p->mx != 0 && sx % p->msz == 0){ - p->mv = bgpixel(p->c, nb, p->t & 0x4000); - if(p->tnx + p->mx >= 8){ - sx += p->mx; - goto redo; - }else if(p->mx > 1) - shift(p->c, nb, p->mx - 1, p->t & 0x4000); + struct bgctxt *p; + int sx, sy; + + p = bgctxts + n; + p->hsh = ((reg[BGMODE] & (1<<(4+n))) != 0) ? 4 : 3; + p->wsh = mode >= 5 ? 4 : p->hsh; + p->h = 1<hsh; + p->w = 1<wsh; + p->nb = nb; + p->pri[0] = prilo; + p->pri[1] = prihi; + sx = hofs[n]; + sy = vofs[n] + ppuy; + if(reg[MOSAIC] != 0 && (reg[MOSAIC] & (1<msz = (reg[MOSAIC] >> 4) + 1; + if(p->msz != 1){ + sx -= p->mx = sx % p->msz; + sy -= sy % p->msz; } + }else + p->msz = 1; + if(mode >= 5) + sx <<= 1; +redo: + p->tx = sx >> p->wsh; + p->tnx = sx & (p->w - 1); + p->ty = sy >> p->hsh; + p->tny = sy & (p->h - 1); + p->t = tile(n, p->tx, p->ty); + chr(n, nb, p->w, p->h, p->t, p->tnx, p->tny, p->c); + p->pal = palette(n, p->t >> 10 & 7); + if((p->tnx & 7) != 0) + shift(p->c, nb, p->tnx & 7, p->t & 0x4000); + if(p->msz != 1 && p->mx != 0 && sx % p->msz == 0){ + p->mv = bgpixel(p->c, nb, p->t & 0x4000); + if(p->tnx + p->mx >= 8){ + sx += p->mx; + goto redo; + }else if(p->mx > 1) + shift(p->c, nb, p->mx - 1, p->t & 0x4000); } - v = bgpixel(p->c, nb, p->t & 0x4000); + +} + +static void +bg(int n) +{ + struct bgctxt *p; + u8int v; + + p = bgctxts + n; + v = bgpixel(p->c, p->nb, p->t & 0x4000); if(p->msz != 1) if(p->mx++ == 0) p->mv = v; @@ -288,40 +338,327 @@ bg(int n, int nb, int prilo, int prihi) v = p->mv; } if(v != 0) - pixel(n, p->pal + v, (p->t & 0x2000) != 0 ? prihi : prilo); - if(++p->tnx == p->sz){ + pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]); + if(++p->tnx == p->w){ p->tx++; p->tnx = 0; p->t = tile(n, p->tx, p->ty); p->pal = palette(n, p->t >> 10 & 7); } if((p->tnx & 7) == 0) - chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c); + chr(n, p->nb, p->w, p->h, p->t, p->tnx, p->tny, p->c); } static void -bgs(void) +optinit(void) +{ + struct bgctxt *p; + + p = bgctxts + 2; + p->hsh = (reg[BGMODE] & (1<<6)) != 0 ? 4 : 3; + p->wsh = mode >= 5 ? 4 : p->hsh; + p->w = 1<wsh; + p->h = 1<hsh; + p->tnx = hofs[2] & (p->w - 1); + p->tx = hofs[2] >> p->wsh; + bgctxts[0].otx = bgctxts[1].otx = 0xffff; + bgctxts[0].oty = bgctxts[0].ty; + bgctxts[0].otny = bgctxts[0].tny; + bgctxts[1].oty = bgctxts[1].ty; + bgctxts[1].otny = bgctxts[1].tny; +} + +static void +opt(void) +{ + struct bgctxt *p; + u16int hval, vval; + int sx, sy; + + p = bgctxts + 2; + if(++p->tnx == p->w){ + if(mode == 4){ + hval = tile(2, p->tx, vofs[2] >> p->hsh); + if((hval & 0x8000) != 0){ + vval = hval; + hval = 0; + }else + vval = 0; + }else{ + hval = tile(2, p->tx, vofs[2] >> p->hsh); + vval = tile(2, p->tx, (vofs[2]+8) >> p->hsh); + } + sx = (rx & ~7) + (hval & 0x1ff8); + sy = ppuy + (vval & 0x1fff); + if((vval & 0x2000) != 0){ + bgctxts[0].oty = sy >> bgctxts[0].hsh; + bgctxts[0].otny = sy & (bgctxts[0].h - 1); + }else{ + bgctxts[0].oty = bgctxts[0].ty; + bgctxts[0].otny = bgctxts[0].tny; + } + if((vval & 0x4000) != 0){ + bgctxts[1].oty = sy >> bgctxts[1].hsh; + bgctxts[1].otny = sy & (bgctxts[1].h - 1); + }else{ + bgctxts[1].oty = bgctxts[1].ty; + bgctxts[1].otny = bgctxts[1].tny; + } + if((hval & 0x2000) != 0) + bgctxts[0].otx = sx >> bgctxts[0].wsh; + else + bgctxts[0].otx = 0xffff; + if((hval & 0x4000) != 0) + bgctxts[1].otx = sx >> bgctxts[1].wsh; + else + bgctxts[1].otx = 0xffff; + p->tnx = 0; + p->tx++; + } +} + +static void +bgopt(int n) +{ + struct bgctxt *p; + u8int v; + + p = bgctxts + n; + v = bgpixel(p->c, p->nb, p->t & 0x4000); + if(p->msz != 1) + if(p->mx++ == 0) + p->mv = v; + else{ + if(p->mx == p->msz) + p->mx = 0; + v = p->mv; + } + if(v != 0) + pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]); + if(++p->tnx == p->w){ + p->tx++; + p->tnx = 0; + } + if((p->tnx & 7) == 0){ + p->t = tile(n, p->otx == 0xffff ? p->tx : p->otx, p->oty); + p->pal = palette(n, p->t >> 10 & 7); + chr(n, p->nb, p->w, p->h, p->t, p->tnx, p->otny, 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) + if((reg[MOSAIC] & 2) != 0) + p->msz = (reg[MOSAIC] >> 4) + 1; + else + p->msz = 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 & 0x7f) != 0) + if((v & 0x80) != 0) + pixel(1, v & 0x7f, 0x71); + else + pixel(1, v, 0x11); + }else if(v != 0) + 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) { static int bitch[8]; + pixel = npixel; switch(mode){ case 0: - bg(0, 2, 0x80, 0xb0); - bg(1, 2, 0x71, 0xa1); - bg(2, 2, 0x22, 0x52); - bg(3, 2, 0x13, 0x43); + bginit(0, 2, 0x80, 0xb0); + bginit(1, 2, 0x71, 0xa1); + bginit(2, 2, 0x22, 0x52); + bginit(3, 2, 0x13, 0x43); break; case 1: - bg(0, 4, 0x80, 0xb0); - bg(1, 4, 0x71, 0xa1); - bg(2, 2, 0x12, (reg[BGMODE] & 8) != 0 ? 0xd2 : 0x42); + bginit(0, 4, 0x80, 0xb0); + bginit(1, 4, 0x71, 0xa1); + bginit(2, 2, 0x12, (reg[BGMODE] & 8) != 0 ? 0xd2 : 0x42); + break; + case 2: + bginit(0, 4, 0x40, 0xa0); + bginit(1, 4, 0x11, 0x71); + optinit(); + break; + case 3: + bginit(0, 8, 0x40, 0xa0); + bginit(1, 4, 0x11, 0x71); + break; + case 4: + bginit(0, 8, 0x40, 0xa0); + bginit(1, 2, 0x11, 0x71); + optinit(); + break; + case 5: + bginit(0, 4, 0x40, 0xa0); + bginit(1, 2, 0x11, 0x71); + break; + case 6: + bginit(0, 4, 0x40, 0xa0); + optinit(); + break; + case 7: + bg7init(0); + if((reg[SETINI] & EXTBG) != 0) + bg7init(1); break; default: + bgctxts[0].w = bgctxts[1].w = 0; if(bitch[mode]++ == 0) print("bg mode %d not implemented\n", mode); } } +static void +bgs(void) +{ + switch(mode){ + case 0: + bg(0); + bg(1); + bg(2); + bg(3); + break; + case 1: + bg(0); + bg(1); + bg(2); + break; + case 2: + case 4: + opt(); + bgopt(0); + bgopt(1); + break; + case 3: + bg(0); + bg(1); + break; + case 5: + pixel = spixel; + bg(0); + bg(1); + pixel = mpixel; + bg(0); + bg(1); + pixel = npixel; + break; + case 6: + opt(); + pixel = spixel; + bgopt(0); + pixel = mpixel; + bgopt(0); + pixel = npixel; + break; + case 7: + bg7(0); + if((reg[SETINI] & EXTBG) != 0) + bg7(1); + break; + } +} + static void sprites(void) { @@ -336,7 +673,7 @@ sprites(void) u32int *ch; } t[32], *tp; static u32int ch[34]; - static u8int *p, q, over; + static u8int *p, q; static int n, m; static int *sz; static int szs[] = { @@ -353,7 +690,6 @@ sprites(void) if(rx == 0){ n = 0; - over = 1; sp = s; sz = szs + ((reg[OBSEL] & 0xe0) >> 3); base[0] = (reg[OBSEL] & 0x07) << 14; @@ -372,10 +708,10 @@ sprites(void) sp->x = p[0]; if((q & 1) != 0) sp->x |= 0xff00; - if(sp->x < -(short)sp->sx && sp->x != -256) + if(sp->x <= -(short)sp->sx && sp->x != -256) goto nope; if(n == 32){ - over |= 0x40; + reg[0x213e] |= 0x40; goto nope; } sp->i = rx >> 1; @@ -441,6 +777,14 @@ nope: a = sp->t0 | (dy & 7) << 1; if(dy >= 8) a += (dy & ~7) << 6; + if(sp->x < 0 && (i = (-sp->x >> 3)) != 0){ + if((sp->c & 0x40) != 0) + a -= i << 5; + else + a += i << 5; + nt -= i; + tp->sx += i << 3; + } if((sp->c & 0x40) != 0){ a += sp->sx * 4; for(i = 0; i < nt; i++){ @@ -452,7 +796,7 @@ nope: *cp++ = w; tp->sx += 8; }else - over |= 0x80; + reg[0x213e] |= 0x80; } }else for(i = 0; i < nt; i++){ @@ -465,18 +809,22 @@ nope: tp->sx += 8; a += 15; }else - over |= 0x80; + reg[0x213e] |= 0x80; } + if(sp->x < 0 && (i = (-sp->x) & 7) != 0) + if((sp->c & 0x40) != 0) + *tp->ch >>= i; + else + *tp->ch <<= i; } - reg[0x213e] = over; } } static u16int -colormath(void) +colormath(int n) { u16int v, w, r, g, b; - u8int m, m2; + u8int m, m2, div; int cw; m = reg[CGWSEL]; @@ -489,12 +837,12 @@ colormath(void) case 3: v = 0; break; } if(v){ - if((pixelcol[0] & 0x10000) != 0) - v = pixelcol[0]; + if((pixelcol[n] & 0x10000) != 0) + v = pixelcol[n]; else - v = cgram[pixelcol[0] & 0xff]; + v = cgram[pixelcol[n] & 0xff]; } - if((m2 & (1 << (pixelpri[0] & 0xf))) == 0) + if((m2 & (1 << (pixelpri[n] & 0xf))) == 0) return v; switch((m >> 4) & 3){ case 0: break; @@ -502,31 +850,33 @@ colormath(void) case 2: if(cw < 0) cw = window(COL); if(cw) return v; break; default: return v; } + div = (m2 & 0x40) != 0; if((m & 2) != 0){ - if((pixelcol[1] & 0x10000) != 0) - w = pixelcol[1]; + if((pixelcol[1-n] & 0x10000) != 0) + w = pixelcol[1-n]; else - w = cgram[pixelcol[1] & 0xff]; + w = cgram[pixelcol[1-n] & 0xff]; + div = div && (pixelpri[1-n] & 0xf) != COL; }else w = subcolor; if((m2 & 0x80) != 0){ r = (v & 0x7c00) - (w & 0x7c00); g = (v & 0x03e0) - (w & 0x03e0); b = (v & 0x001f) - (w & 0x001f); - if((m2 & 0x40) != 0){ + if(r > 0x7c00) r = 0; + if(g > 0x03e0) g = 0; + if(b > 0x001f) b = 0; + if(div){ r = (r >> 1) & 0xfc00; g = (g >> 1) & 0xffe0; b >>= 1; } - if(r > 0x7c00) r = 0; - if(g > 0x03e0) g = 0; - if(b > 0x001f) b = 0; return r | g | b; }else{ r = (v & 0x7c00) + (w & 0x7c00); g = (v & 0x03e0) + (w & 0x03e0); b = (v & 0x001f) + (w & 0x001f); - if((m2 & 0x40) != 0){ + if(div){ r = (r >> 1) & 0xfc00; g = (g >> 1) & 0xffe0; b >>= 1; @@ -545,6 +895,7 @@ ppustep(void) mode = reg[BGMODE] & 7; bright = reg[INIDISP] & 0xf; + hires = mode >= 5 && mode < 7 || (reg[SETINI] & 8) != 0; yvbl = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1; if(ppux >= XLEFT && ppux <= XRIGHT && ppuy < 0xf0){ @@ -557,27 +908,39 @@ ppustep(void) bgs(); sprites(); if(ppuy != 0) - pixeldraw(rx, ppuy - 1, colormath()); + if(hires){ + pixeldraw(rx, ppuy - 1, colormath(1), 0); + pixeldraw(rx, ppuy - 1, colormath(0), 1); + }else + pixeldraw(rx, ppuy - 1, colormath(0), 0); }else if(ppuy != 0) - pixeldraw(rx, ppuy - 1, ppuy >= yvbl ? 0x31c8 : 0); + pixeldraw(rx, ppuy - 1, ppuy >= yvbl ? 0x6739 : 0, -1); } + if(ppux == 134) + cpupause = 1; if(ppux == 0x116 && ppuy <= yvbl) hdma |= reg[0x420c]; - if((reg[NMITIMEN] & HCNTIRQ) != 0 && htime == ppux && ((reg[NMITIMEN] & VCNTIRQ) == 0 || vtime == ppuy)) + if((reg[NMITIMEN] & HCNTIRQ) != 0 && htime+4 == ppux && ((reg[NMITIMEN] & VCNTIRQ) == 0 || vtime == ppuy)) irq |= IRQPPU; if(++ppux >= 340){ ppux = 0; if(++ppuy >= 262){ ppuy = 0; reg[RDNMI] &= ~VBLANK; + reg[0x213e] = 1; + reg[0x213f] ^= 0x80; hdma = reg[0x420c]<<8; flush(); } + if(ppuy < yvbl) + bgsinit(); if(ppuy == yvbl){ reg[RDNMI] |= VBLANK; if((reg[NMITIMEN] & VBLANK) != 0) nmi = 2; + if((reg[INIDISP] & 0x80) == 0) + oamaddr = reg[0x2102] << 1 | (reg[0x2103] & 1) << 9; if((reg[NMITIMEN] & AUTOJOY) != 0){ memwrite(0x4016, 1); memwrite(0x4016, 0);