]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/snes/ppu.c
games/snes: minor oam bugs
[plan9front.git] / sys / src / games / snes / ppu.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 int ppux, ppuy, rx;
8 static u8int mode, bright, pixelpri[2];
9 static u32int pixelcol[2];
10 u16int vtime = 0x1ff, htime = 0x1ff, subcolor;
11 uchar pic[256*239*2*9];
12 u16int hofs[5], vofs[5];
13 s16int m7[6];
14
15 enum {
16         M7A,
17         M7B,
18         M7C,
19         M7D,
20         M7X,
21         M7Y
22 };
23
24 enum { OBJ = 4, COL = 5, OBJNC = 8 };
25
26 static u16int
27 darken(u16int v)
28 {
29         u8int r, g, b;
30         
31         r = (v >> 10) & 0x1f;
32         g = (v >> 5) & 0x1f;
33         b = v & 0x1f;
34         r = r * bright / 15;
35         g = g * bright / 15;
36         b = b * bright / 15;
37         return r << 10 | g << 5 | b;
38 }
39
40 static void
41 pixeldraw(int x, int y, u16int v)
42 {
43         uchar *p;
44         u16int *q;
45         union { u16int w; u8int b[2]; } u;
46         int i;
47
48         if(bright != 0xf)
49                 v = darken(v);
50         if(scale == 1){
51                 p = pic + (x + y * 256) * 2;
52                 *p++ = v;
53                 *p = v >> 8;
54                 return;
55         }
56         u.b[0] = v;
57         u.b[1] = v >> 8;
58         if(scale == 2){
59                 q = (u16int*)pic + (x + y * 256 * 2) * 2;
60                 *q++ = u.w;
61                 *q = u.w;
62                 q += 256 * 2 - 1;
63                 *q++ = u.w;
64                 *q = u.w;
65         }else{
66                 q = (u16int*)pic + (x + y * 256 * 3) * 3;
67                 for(i = 0; i < 3; i++){
68                         *q++ = u.w;
69                         *q++ = u.w;
70                         *q = u.w;
71                         q += 256 * 3 - 2;
72                 }
73         }
74 }
75
76 static int
77 window(int n)
78 {
79         int a, w1, w2;
80
81         a = reg[0x2123 + (n >> 1)];
82         if((n & 1) != 0)
83                 a >>= 4;
84         if((a & (WIN1|WIN2)) == 0)
85                 return 0;
86         w1 = rx >= reg[0x2126] && rx <= reg[0x2127];
87         w2 = rx >= reg[0x2128] && rx <= reg[0x2129];
88         if((a & INVW1) != 0)
89                 w1 = !w1;
90         if((a & INVW2) != 0)
91                 w2 = !w2;
92         if((a & (WIN1|WIN2)) != (WIN1|WIN2))
93                 return (a & WIN1) != 0 ? w1 : w2;
94         a = reg[0x212a + (n >> 2)] >> ((n & 3) << 1);
95         switch(a & 3){
96         case 1: return w1 & w2;
97         case 2: return w1 ^ w2;
98         case 3: return w1 ^ w2 ^ 1;
99         }
100         return w1 | w2;
101 }
102
103 static void
104 pixel(int n, int v, int pri)
105 {
106         int a;
107         
108         a = 1<<n;
109         if((reg[TM] & a) != 0 && pri > pixelpri[0] && ((reg[TMW] & a) == 0 || !window(n))){
110                 pixelcol[0] = v;
111                 pixelpri[0] = pri;
112         }
113         if((reg[TS] & a) != 0 && pri > pixelpri[1] && ((reg[TSW] & a) == 0 || !window(n))){
114                 pixelcol[1] = v;
115                 pixelpri[1] = pri;
116         }
117 }
118
119 static u16int
120 tile(int n, int tx, int ty)
121 {
122         int a;
123         u16int ta;
124         u16int t;
125
126         a = reg[0x2107 + n];
127         ta = ((a & ~3) << 9) + ((tx & 0x1f) << 1) + ((ty & 0x1f) << 6);
128         if((a & 1) != 0)
129                 ta += (tx & 0x20) << 6;
130         if((a & 2) != 0)
131                 ta += (ty & 0x20) << (6 + (a & 1));
132         t = vram[ta++];
133         return t | vram[ta] << 8;
134 }
135
136 static void
137 chr(int n, int nb, int sz, u16int t, int x, int y, u32int c[])
138 {
139         u16int a;
140
141         if(sz == 16){
142                 if(y >= 8){
143                         t += ((x >> 3 ^ t >> 14) & 1) + ((~t >> 11) & 16);
144                         y -= 8;
145                 }else
146                         t += ((x >> 3 ^ t >> 14) & 1) + ((t >> 11) & 16);
147         }
148         if((t & 0x8000) != 0)
149                 y = 7 - y;
150         a = reg[0x210b + (n >> 1)];
151         if((n & 1) != 0)
152                 a >>= 4;
153         else
154                 a &= 0xf;
155         a = (a << 13) + (t & 0x3ff) * 8 * nb + y * 2;
156         c[0] = vram[a++];
157         c[0] |= vram[a] << 8;
158         if(nb != 2){
159                 a += 15;
160                 c[0] |= vram[a++] << 16;
161                 c[0] |= vram[a] << 24;
162                 if(nb == 8){
163                         a += 15;
164                         c[1] = vram[a++];
165                         c[1] |= vram[a] << 8;
166                         a += 15;
167                         c[1] |= vram[a++] << 16;
168                         c[1] |= vram[a] << 24;
169                 }
170         }
171 }
172
173 static int
174 palette(int n, int p)
175 {
176         switch(mode){
177         case 0:
178                 return p << 2 | n << 5;
179         case 1:
180                 if(n >= 2)
181                         return p << 2;
182         case 2:
183         case 6:
184                 return p << 4;
185         case 5:
186                 if(n == 0)
187                         return p << 4;
188                 return p << 2;
189         case 3:
190                 if(n != 0)
191                         return p << 4;
192         case 4:
193                 if(n != 0)
194                         return p << 2;
195                 if((reg[CGWSEL] & DIRCOL) != 0)
196                         return 0x10000;
197         }
198         return 0;
199 }
200
201 static void
202 shift(u32int *c, int nb, int n, int d)
203 {
204         if(d){
205                 c[0] >>= n;
206                 if(nb == 8)
207                         c[1] >>= n;
208         }else{
209                 c[0] <<= n;
210                 if(nb == 8)
211                         c[1] <<= n;
212         }
213 }
214
215 static u8int
216 bgpixel(u32int *c, int nb, int d)
217 {
218         u8int v;
219         
220         if(d){
221                 v = c[0] & 1 | c[0] >> 7 & 2;
222                 if(nb != 2){
223                         v |= c[0] >> 14 & 4 | c[0] >> 21 & 8;
224                         if(nb == 8){
225                                 v |= c[1] << 4 & 16 | c[1] >> 3 & 32 | c[1] >> 10 & 64 | c[1] >> 17 & 128;
226                                 c[1] >>= 1;
227                         }
228                 }
229                 c[0] >>= 1;
230         }else{
231                 v = c[0] >> 7 & 1 | c[0] >> 14 & 2;
232                 if(nb != 2){
233                         v |= c[0] >> 21 & 4 | c[0] >> 28 & 8;
234                         if(nb == 8){
235                                 v |= c[1] >> 3 & 16 | c[1] >> 10 & 32 | c[1] >> 17 & 64 | c[1] >> 24 & 128;
236                                 c[1] <<= 1;
237                         }
238                 }
239                 c[0] <<= 1;
240         }
241         return v;
242 }
243
244 static struct bgctxt {
245         u8int sz, szsh, nb, pri[2];
246         u16int tx, ty, tnx, tny;
247         u16int t;
248         u32int c[2];
249         int pal;
250         u8int msz, mv, mx;
251         u16int otx, oty, otny;
252 } bgctxts[4];
253
254 static void
255 bginit(int n, int nb, int prilo, int prihi)
256 {
257         struct bgctxt *p;
258         int sx, sy;
259
260         p = bgctxts + n;
261         p->szsh = (reg[BGMODE] & (1<<(4+n))) != 0 ? 4 : 3;
262         p->sz = 1<<p->szsh;
263         p->nb = nb;
264         p->pri[0] = prilo;
265         p->pri[1] = prihi;
266         sx = hofs[n];
267         sy = vofs[n] + ppuy;
268         if(reg[MOSAIC] != 0 && (reg[MOSAIC] & (1<<n)) != 0){
269                 p->msz = (reg[MOSAIC] >> 4) + 1;
270                 if(p->msz != 1){
271                         sx -= p->mx = sx % p->msz;
272                         sy -= sy % p->msz;
273                 }
274         }else
275                 p->msz = 1;
276 redo:
277         p->tx = sx >> p->szsh;
278         p->tnx = sx & (p->sz - 1);
279         p->ty = sy >> p->szsh;
280         p->tny = sy & (p->sz - 1);
281         p->t = tile(n, p->tx, p->ty);
282         chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c);
283         p->pal = palette(n, p->t >> 10 & 7);
284         if((p->tnx & 7) != 0)
285                 shift(p->c, nb, p->tnx & 7, p->t & 0x4000);
286         if(p->msz != 1 && p->mx != 0 && sx % p->msz == 0){
287                 p->mv = bgpixel(p->c, nb, p->t & 0x4000);
288                 if(p->tnx + p->mx >= 8){
289                         sx += p->mx;
290                         goto redo;
291                 }else if(p->mx > 1)
292                         shift(p->c, nb, p->mx - 1, p->t & 0x4000);
293         }
294
295 }
296
297 static void
298 bg(int n)
299 {
300         struct bgctxt *p;
301         u8int v;
302
303         p = bgctxts + n;
304         v = bgpixel(p->c, p->nb, p->t & 0x4000);
305         if(p->msz != 1)
306                 if(p->mx++ == 0)
307                         p->mv = v;
308                 else{
309                         if(p->mx == p->msz)
310                                 p->mx = 0;
311                         v = p->mv;
312                 }
313         if(v != 0)
314                 pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]);
315         if(++p->tnx == p->sz){
316                 p->tx++;
317                 p->tnx = 0;
318                 p->t = tile(n, p->tx, p->ty);
319                 p->pal = palette(n, p->t >> 10 & 7);
320         }
321         if((p->tnx & 7) == 0)
322                 chr(n, p->nb, p->sz, p->t, p->tnx, p->tny, p->c);
323 }
324
325 static void
326 optinit(void)
327 {
328         struct bgctxt *p;
329         
330         p = bgctxts + 2;
331         p->szsh = (reg[BGMODE] & (1<<6)) != 0 ? 4 : 3;
332         p->sz = 1<<p->szsh;
333         p->tnx = hofs[2] & (p->sz - 1);
334         p->tx = hofs[2] >> p->szsh;
335         bgctxts[0].otx = bgctxts[1].otx = 0xffff;
336         bgctxts[0].oty = bgctxts[0].ty;
337         bgctxts[0].otny = bgctxts[0].tny;
338         bgctxts[1].oty = bgctxts[1].ty;
339         bgctxts[1].otny = bgctxts[1].tny;
340 }
341
342 static void
343 opt(void)
344 {
345         struct bgctxt *p;
346         u16int hval, vval;
347         int sx, sy;
348         
349         p = bgctxts + 2;
350         if(++p->tnx == p->sz){
351                 if(mode == 4){
352                         hval = tile(2, p->tx, vofs[2] >> p->szsh);
353                         if((hval & 0x8000) != 0){
354                                 vval = hval;
355                                 hval = 0;
356                         }else
357                                 vval = 0;
358                 }else{
359                         hval = tile(2, p->tx, vofs[2] >> p->szsh);
360                         vval = tile(2, p->tx, (vofs[2]+8) >> p->szsh);
361                 }
362                 sx = (rx & ~7) + (hval & 0x1ff8);
363                 sy = ppuy + (vval & 0x1fff);
364                 if((vval & 0x2000) != 0){
365                         bgctxts[0].oty = sy >> bgctxts[0].szsh;
366                         bgctxts[0].otny = sy & (bgctxts[0].sz - 1);
367                 }else{
368                         bgctxts[0].oty = bgctxts[0].ty;
369                         bgctxts[0].otny = bgctxts[0].tny;
370                 }
371                 if((vval & 0x4000) != 0){
372                         bgctxts[1].oty = sy >> bgctxts[1].szsh;
373                         bgctxts[1].otny = sy & (bgctxts[1].sz - 1);
374                 }else{
375                         bgctxts[1].oty = bgctxts[1].ty;
376                         bgctxts[1].otny = bgctxts[1].tny;
377                 }
378                 if((hval & 0x2000) != 0)
379                         bgctxts[0].otx = sx >> bgctxts[0].szsh;
380                 else
381                         bgctxts[0].otx = 0xffff;
382                 if((hval & 0x4000) != 0)
383                         bgctxts[1].otx = sx >> bgctxts[1].szsh;
384                 else
385                         bgctxts[1].otx = 0xffff;
386                 p->tnx = 0;
387                 p->tx++;
388         }
389 }
390
391 static void
392 bgopt(int n)
393 {
394         struct bgctxt *p;
395         u8int v;
396         
397         p = bgctxts + n;
398         v = bgpixel(p->c, p->nb, p->t & 0x4000);
399         if(p->msz != 1)
400                 if(p->mx++ == 0)
401                         p->mv = v;
402                 else{
403                         if(p->mx == p->msz)
404                                 p->mx = 0;
405                         v = p->mv;
406                 }
407         if(v != 0)
408                 pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]);
409         if(++p->tnx == p->sz){
410                 p->tx++;
411                 p->tnx = 0;
412         }
413         if((p->tnx & 7) == 0){
414                 p->t = tile(n, p->otx == 0xffff ? p->tx : p->otx, p->oty);
415                 p->pal = palette(n, p->t >> 10 & 7);
416                 chr(n, p->nb, p->sz, p->t, p->tnx, p->otny, p->c);
417         }
418 }
419
420 struct bg7ctxt {
421         int x, y, x0, y0;
422         u8int msz, mx, mv;
423 } b7[2];
424
425 void
426 calc7(void)
427 {
428         s16int t;
429
430         if((reg[0x2105] & 7) != 7)
431                 return;
432         t = hofs[4] - m7[M7X];
433         if((t & 0x2000) != 0)
434                 t |= ~0x3ff;
435         else
436                 t &= 0x3ff;
437         b7->x0 = (t * m7[M7A]) & ~63;
438         b7->y0 = (t * m7[M7C]) & ~63;
439         t = vofs[4] - m7[M7Y];
440         if((t & 0x2000) != 0)
441                 t |= ~0x3ff;
442         else
443                 t &= 0x3ff;
444         b7->x0 += (t * m7[M7B]) & ~63;
445         b7->y0 += (t * m7[M7D]) & ~63;
446         b7->x0 += m7[M7X] << 8;
447         b7->y0 += m7[M7Y] << 8;
448 }
449
450 static void
451 bg7init(int n)
452 {
453         u8int m, y;
454         struct bg7ctxt *p;
455         
456         p = b7 + n;
457         m = reg[M7SEL];
458         y = ppuy;
459         p->msz = 1;
460         if((reg[MOSAIC] & 1) != 0){
461                 p->msz = (reg[MOSAIC] >> 4) + 1;
462                 if(p->msz != 1)
463                         y -= y % p->msz;
464         }
465         if(n == 1)
466                 if((reg[MOSAIC] & 2) != 0)
467                         p->msz = (reg[MOSAIC] >> 4) + 1;
468                 else
469                         p->msz = 1;
470         if((m & 2) != 0)
471                 y = 255 - y;
472         p->x = b7->x0 + ((m7[M7B] * y) & ~63);
473         p->y = b7->y0 + ((m7[M7D] * y) & ~63);
474         if((m & 1) != 0){
475                 p->x += 255 * m7[M7A];
476                 p->y += 255 * m7[M7C];
477         }
478 }
479
480 static void
481 bg7(int n)
482 {
483         u16int x, y;
484         u8int m, v, t;
485         struct bg7ctxt *p;
486
487         p = b7 + n;
488         m = reg[M7SEL];
489         x = p->x >> 8;
490         y = p->y >> 8;
491         if((m & 0x80) == 0){
492                 x &= 1023;
493                 y &= 1023;
494         }else if(x > 1023 || y > 1023){
495                 if((m & 0x40) != 0){
496                         t = 0;
497                         goto lookup;
498                 }
499                 v = 0;
500                 goto end;
501         }
502         t = vram[x >> 2 & 0xfe | y << 5 & 0x7f00];
503 lookup:
504         v = vram[t << 7 | y << 4 & 0x70 | x << 1 & 0x0e | 1];
505 end:
506         if(p->msz != 1){
507                 if(p->mx == 0)
508                         p->mv = v;
509                 else
510                         v = p->mv;
511                 if(++p->mx == p->msz)
512                         p->mx = 0;
513         }
514         if(n == 1){
515                 if((v & 0x7f) != 0)
516                         if((v & 0x80) != 0)
517                                 pixel(1, v & 0x7f, 0x71);
518                         else
519                                 pixel(1, v, 0x11);
520         }else if(v != 0)
521                 pixel(0, v, 0x40);
522         if((m & 1) != 0){
523                 p->x -= m7[M7A];
524                 p->y -= m7[M7C];
525         }else{
526                 p->x += m7[M7A];
527                 p->y += m7[M7C];
528         }
529 }
530
531 static void
532 bgsinit(void)
533 {
534         static int bitch[8];
535
536         switch(mode){
537         case 0:
538                 bginit(0, 2, 0x80, 0xb0);
539                 bginit(1, 2, 0x71, 0xa1);
540                 bginit(2, 2, 0x22, 0x52);
541                 bginit(3, 2, 0x13, 0x43);
542                 break;
543         case 1:
544                 bginit(0, 4, 0x80, 0xb0);
545                 bginit(1, 4, 0x71, 0xa1);
546                 bginit(2, 2, 0x12, (reg[BGMODE] & 8) != 0 ? 0xd2 : 0x42);
547                 break;
548         case 2:
549                 bginit(0, 4, 0x40, 0xa0);
550                 bginit(1, 4, 0x11, 0x71);
551                 optinit();
552                 break;
553         case 3:
554                 bginit(0, 8, 0x40, 0xa0);
555                 bginit(1, 4, 0x11, 0x71);
556                 break;
557         case 4:
558                 bginit(0, 8, 0x40, 0xa0);
559                 bginit(1, 2, 0x11, 0x71);
560                 optinit();
561                 break;
562         case 7:
563                 bg7init(0);
564                 if((reg[SETINI] & EXTBG) != 0)
565                         bg7init(1);
566                 break;
567         default:
568                 bgctxts[0].sz = bgctxts[1].sz = 0;
569                 if(bitch[mode]++ == 0)
570                         print("bg mode %d not implemented\n", mode);
571         }
572 }
573
574 static void
575 bgs(void)
576 {
577         switch(mode){
578         case 0:
579                 bg(0);
580                 bg(1);
581                 bg(2);
582                 bg(3);
583                 break;
584         case 1:
585                 bg(0);
586                 bg(1);
587                 bg(2);
588                 break;
589         case 2:
590         case 4:
591                 opt();
592                 bgopt(0);
593                 bgopt(1);
594                 break;
595         case 3:
596                 bg(0);
597                 bg(1);
598                 break;
599         case 7:
600                 bg7(0);
601                 if((reg[SETINI] & EXTBG) != 0)
602                         bg7(1);
603                 break;
604         }
605 }
606
607 static void
608 sprites(void)
609 {
610         static struct {
611                 short x;
612                 u8int y, i, c, sx, sy;
613                 u16int t0, t1;
614         } s[32], *sp;
615         static struct {
616                 short x;
617                 u8int sx, i, c, pal, pri;
618                 u32int *ch;
619         } t[32], *tp;
620         static u32int ch[34];
621         static u8int *p, q, over;
622         static int n, m;
623         static int *sz;
624         static int szs[] = {
625                 8, 8, 16, 16, 8, 8, 32, 32,
626                 8, 8, 64, 64, 16, 16, 32, 32,
627                 16, 16, 64, 64, 32, 32, 64, 64,
628                 16, 32, 32, 64, 16, 32, 32, 32
629         };
630         static u16int base[2];
631         u8int dy, v, col, pri0, pri1, prio;
632         u16int a;
633         u32int w, *cp;
634         int i, nt, dx;
635
636         if(rx == 0){
637                 n = 0;
638                 over = 1;
639                 sp = s;
640                 sz = szs + ((reg[OBSEL] & 0xe0) >> 3);
641                 base[0] = (reg[OBSEL] & 0x07) << 14;
642                 base[1] = base[0] + (((reg[OBSEL] & 0x18) + 8) << 10);
643         }
644         if((rx & 1) == 0){
645                 p = oam + 2 * rx;
646                 if(p[1] == 0xf0)
647                         goto nope;
648                 q = (oam[512 + (rx >> 3)] >> (rx & 6)) & 3;
649                 dy = ppuy - p[1];
650                 sp->sx = sz[q & 2];
651                 sp->sy = sz[(q & 2) + 1];
652                 if(dy >= sp->sy)
653                         goto nope;
654                 sp->x = p[0];
655                 if((q & 1) != 0)
656                         sp->x |= 0xff00;
657                 if(sp->x < -(short)sp->sx && sp->x != -256)
658                         goto nope;
659                 if(n == 32){
660                         over |= 0x40;
661                         goto nope;
662                 }
663                 sp->i = rx >> 1;
664                 sp->y = p[1];
665                 sp->c = p[3];
666                 sp->t0 = p[2] << 5;
667                 sp->t1 = base[sp->c & 1];
668                 sp++;
669                 n++;
670         }
671 nope:
672         if(ppuy != 0){
673                 col = 0;
674                 pri0 = 0;
675                 pri1 = 128;
676                 if((reg[OAMADDH] & 0x80) != 0)
677                         prio = oamaddr >> 2;
678                 else
679                         prio = 0;
680                 for(i = 0, tp = t; i < m; i++, tp++){
681                         dx = rx - tp->x;
682                         if(dx < 0 || dx >= tp->sx)
683                                 continue;
684                         w = *tp->ch;
685                         if((tp->c & 0x40) != 0){
686                                 v = w & 1 | w >> 7 & 2 | w >> 14 & 4 | w >> 21 & 8;
687                                 *tp->ch = w >> 1;
688                         }else{
689                                 v = w >> 7 & 1 | w >> 14 & 2 | w >> 21 & 4 | w >> 28 & 8;
690                                 *tp->ch = w << 1;
691                         }
692                         if((dx & 7) == 7)
693                                 tp->ch++;
694                         nt = (tp->i - prio) & 0x7f;
695                         if(v != 0 && nt < pri1){
696                                 col = tp->pal + v;
697                                 pri0 = tp->pri;
698                                 pri1 = nt;
699                         }
700                 }
701                 if(col > 0)
702                         pixel(OBJ, col, pri0);
703         }
704         if(rx == 255){
705                 cp = ch;
706                 m = n;
707                 for(sp = s + n - 1, tp = t + n - 1; sp >= s; sp--, tp--){
708                         tp->x = sp->x;
709                         tp->sx = 0;
710                         tp->c = sp->c;
711                         tp->pal = 0x80 | sp->c << 3 & 0x70;
712                         tp->pri = 3 * (0x10 + (sp->c & 0x30));
713                         if((tp->c & 8) != 0)
714                                 tp->pri |= OBJ;
715                         else
716                                 tp->pri |= OBJNC;
717                         tp->ch = cp;
718                         tp->i = sp->i;
719                         nt = sp->sx >> 3;
720                         dy = ppuy - sp->y;
721                         if((sp->c & 0x80) != 0)
722                                 dy = sp->sy - 1 - dy;
723                         a = sp->t0 | (dy & 7) << 1;
724                         if(dy >= 8)
725                                 a += (dy & ~7) << 6;
726                         if(sp->x < 0 && (i = (-sp->x >> 3)) != 0){
727                                 if((sp->c & 0x40) != 0)
728                                         a -= i << 5;
729                                 else
730                                         a += i << 5;
731                                 nt -= i;
732                                 tp->sx += i << 3;
733                         }
734                         if((sp->c & 0x40) != 0){
735                                 a += sp->sx * 4;
736                                 for(i = 0; i < nt; i++){
737                                         if(cp < ch + nelem(ch)){
738                                                 w  = vram[sp->t1 | (a -= 16) & 0x1fff] << 16;
739                                                 w |= vram[sp->t1 | (a + 1) & 0x1fff] << 24;
740                                                 w |= vram[sp->t1 | (a -= 16) & 0x1fff] << 0;
741                                                 w |= vram[sp->t1 | (a + 1) & 0x1fff] << 8;
742                                                 *cp++ = w;
743                                                 tp->sx += 8;
744                                         }else
745                                                 over |= 0x80;
746                                 }
747                         }else
748                                 for(i = 0; i < nt; i++){
749                                         if(cp < ch + nelem(ch)){
750                                                 w  = vram[sp->t1 | a & 0x1fff];
751                                                 w |= vram[sp->t1 | ++a & 0x1fff] << 8;
752                                                 w |= vram[sp->t1 | (a += 15) & 0x1fff] << 16;
753                                                 w |= vram[sp->t1 | ++a & 0x1fff] << 24;
754                                                 *cp++ = w;
755                                                 tp->sx += 8;
756                                                 a += 15;
757                                         }else
758                                                 over |= 0x80;
759                                 }
760                         if(sp->x < 0 && (i = (-sp->x) & 7) != 0)
761                                 if((sp->c & 0x40) != 0)
762                                         *tp->ch >>= i;
763                                 else
764                                         *tp->ch <<= i;
765                 }
766                 reg[0x213e] = over;
767         }
768 }
769
770 static u16int
771 colormath(void)
772 {
773         u16int v, w, r, g, b;
774         u8int m, m2, div;
775         int cw;
776         
777         m = reg[CGWSEL];
778         m2 = reg[CGADSUB];
779         cw = -1;
780         switch(m >> 6){
781         default: v = 1; break;
782         case 1: v = cw = window(COL); break;
783         case 2: v = !(cw = window(COL)); break;
784         case 3: v = 0; break;
785         }
786         if(v){
787                 if((pixelcol[0] & 0x10000) != 0)
788                         v = pixelcol[0];
789                 else
790                         v = cgram[pixelcol[0] & 0xff];
791         }
792         if((m2 & (1 << (pixelpri[0] & 0xf))) == 0)
793                 return v;
794         switch((m >> 4) & 3){
795         case 0: break;
796         case 1: if(cw < 0) cw = window(COL); if(!cw) return v; break;
797         case 2: if(cw < 0) cw = window(COL); if(cw) return v; break;
798         default: return v;
799         }
800         div = (m2 & 0x40) != 0;
801         if((m & 2) != 0){
802                 if((pixelcol[1] & 0x10000) != 0)
803                         w = pixelcol[1];
804                 else
805                         w = cgram[pixelcol[1] & 0xff];
806                 div = div && (pixelpri[1] & 0xf) != COL;
807         }else
808                 w = subcolor;
809         if((m2 & 0x80) != 0){
810                 r = (v & 0x7c00) - (w & 0x7c00);
811                 g = (v & 0x03e0) - (w & 0x03e0);
812                 b = (v & 0x001f) - (w & 0x001f);
813                 if(r > 0x7c00) r = 0;
814                 if(g > 0x03e0) g = 0;
815                 if(b > 0x001f) b = 0;
816                 if(div){
817                         r = (r >> 1) & 0xfc00;
818                         g = (g >> 1) & 0xffe0;
819                         b >>= 1;
820                 }
821                 return r | g | b;
822         }else{
823                 r = (v & 0x7c00) + (w & 0x7c00);
824                 g = (v & 0x03e0) + (w & 0x03e0);
825                 b = (v & 0x001f) + (w & 0x001f);
826                 if(div){
827                         r = (r >> 1) & 0xfc00;
828                         g = (g >> 1) & 0xffe0;
829                         b >>= 1;
830                 }
831                 if(r > 0x7c00) r = 0x7c00;
832                 if(g > 0x03e0) g = 0x03e0;
833                 if(b > 0x001f) b = 0x001f;
834                 return r | g | b;
835         }
836 }
837
838 void
839 ppustep(void)
840 {
841         int yvbl;
842
843         mode = reg[BGMODE] & 7;
844         bright = reg[INIDISP] & 0xf;
845         yvbl = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1;
846
847         if(ppux >= XLEFT && ppux <= XRIGHT && ppuy < 0xf0){
848                 rx = ppux - XLEFT;
849                 if(ppuy < yvbl && (reg[INIDISP] & 0x80) == 0){
850                         pixelcol[0] = 0;
851                         pixelpri[0] = COL;
852                         pixelcol[1] = 0x10000 | subcolor;
853                         pixelpri[1] = COL;      
854                         bgs();
855                         sprites();
856                         if(ppuy != 0)
857                                 pixeldraw(rx, ppuy - 1, colormath());
858                 }else if(ppuy != 0)
859                         pixeldraw(rx, ppuy - 1, ppuy >= yvbl ? 0x31c8 : 0);
860         }
861
862         if(ppux == 0x116 && ppuy <= yvbl)
863                 hdma |= reg[0x420c];
864         if((reg[NMITIMEN] & HCNTIRQ) != 0 && htime == ppux && ((reg[NMITIMEN] & VCNTIRQ) == 0 || vtime == ppuy))
865                 irq |= IRQPPU;
866         if(++ppux >= 340){
867                 ppux = 0;
868                 if(++ppuy >= 262){
869                         ppuy = 0;
870                         reg[RDNMI] &= ~VBLANK;
871                         hdma = reg[0x420c]<<8;
872                         flush();
873                 }
874                 if(ppuy < yvbl)
875                         bgsinit();
876                 if(ppuy == yvbl){
877                         reg[RDNMI] |= VBLANK;
878                         if((reg[NMITIMEN] & VBLANK) != 0)
879                                 nmi = 2;
880                         if((reg[INIDISP] & 0x80) == 0)
881                                 oamaddr = reg[0x2102] << 1 | (reg[0x2103] & 1) << 9;
882                         if((reg[NMITIMEN] & AUTOJOY) != 0){
883                                 memwrite(0x4016, 1);
884                                 memwrite(0x4016, 0);
885                                 reg[0x4218] = keylatch >> 16;
886                                 reg[0x4219] = keylatch >> 24;
887                                 keylatch = keylatch << 16 | 0xffff;
888                         }
889                 }
890                 if((reg[NMITIMEN] & (HCNTIRQ|VCNTIRQ)) == VCNTIRQ && vtime == ppuy)
891                         irq |= IRQPPU;
892         }
893 }