]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/games/snes/ppu.c
add libemu
[plan9front.git] / sys / src / games / snes / ppu.c
index 5edc52f5e069277e9bb703d65839c1f0bece3a24..5819e032c10b30de478675dc4ed3bdb6bd6c3563 100644 (file)
@@ -1,14 +1,14 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
+#include <emu.h>
 #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 vtime = 0x1ff, htime = 0x1ff, subcolor;
 u16int hofs[5], vofs[5];
 s16int m7[6];
 
@@ -38,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;
        }
 }
 
@@ -101,7 +96,7 @@ window(int n)
 }
 
 static void
-pixel(int n, int v, int pri)
+npixel(int n, int v, int pri)
 {
        int a;
        
@@ -116,6 +111,32 @@ pixel(int n, int v, int pri)
        }
 }
 
+static void
+spixel(int n, int v, int pri)
+{
+       int a;
+       
+       a = 1<<n;
+       if((reg[TS] & a) != 0 && pri > 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<<n;
+       if((reg[TM] & a) != 0 && pri > 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)
 {
@@ -134,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;
@@ -242,12 +265,13 @@ bgpixel(u32int *c, int nb, int d)
 }
 
 static struct bgctxt {
-       u8int sz, szsh, nb, pri[2];
+       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
@@ -257,8 +281,10 @@ bginit(int n, int nb, int prilo, int prihi)
        int sx, sy;
 
        p = bgctxts + n;
-       p->szsh = (reg[BGMODE] & (1<<(4+n))) != 0 ? 4 : 3;
-       p->sz = 1<<p->szsh;
+       p->hsh = ((reg[BGMODE] & (1<<(4+n))) != 0) ? 4 : 3;
+       p->wsh = mode >= 5 ? 4 : p->hsh;
+       p->h = 1<<p->hsh;
+       p->w = 1<<p->wsh;
        p->nb = nb;
        p->pri[0] = prilo;
        p->pri[1] = prihi;
@@ -272,13 +298,15 @@ bginit(int n, int nb, int prilo, int prihi)
                }
        }else
                p->msz = 1;
+       if(mode >= 5)
+               sx <<= 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->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->sz, p->t, p->tnx, p->tny, p->c);
+       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);
@@ -311,14 +339,111 @@ bg(int n)
                }
        if(v != 0)
                pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]);
-       if(++p->tnx == p->sz){
+       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, p->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
+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<<p->wsh;
+       p->h = 1<<p->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 {
@@ -437,6 +562,7 @@ bgsinit(void)
 {
        static int bitch[8];
 
+       pixel = npixel;
        switch(mode){
        case 0:
                bginit(0, 2, 0x80, 0xb0);
@@ -452,18 +578,32 @@ bgsinit(void)
        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].sz = bgctxts[1].sz = 0;
+               bgctxts[0].w = bgctxts[1].w = 0;
                if(bitch[mode]++ == 0)
                        print("bg mode %d not implemented\n", mode);
        }
@@ -485,10 +625,32 @@ bgs(void)
                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)
@@ -511,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[] = {
@@ -528,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;
@@ -547,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;
@@ -616,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++){
@@ -627,7 +796,7 @@ nope:
                                                *cp++ = w;
                                                tp->sx += 8;
                                        }else
-                                               over |= 0x80;
+                                               reg[0x213e] |= 0x80;
                                }
                        }else
                                for(i = 0; i < nt; i++){
@@ -640,15 +809,19 @@ 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, div;
@@ -664,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;
@@ -679,11 +852,11 @@ colormath(void)
        }
        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];
-               div = div && (pixelpri[1] & 0xf) != COL;
+                       w = cgram[pixelcol[1-n] & 0xff];
+               div = div && (pixelpri[1-n] & 0xf) != COL;
        }else
                w = subcolor;
        if((m2 & 0x80) != 0){
@@ -722,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){
@@ -734,20 +908,28 @@ 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();
                }
@@ -757,6 +939,8 @@ ppustep(void)
                        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);