]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/snes/ppu.c
merge
[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, mosatop;
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 } bgctxts[4];
252
253 static void
254 bginit(int n, int nb, int prilo, int prihi)
255 {
256         struct bgctxt *p;
257         int sx, sy;
258
259         p = bgctxts + n;
260         p->szsh = (reg[BGMODE] & (1<<(4+n))) != 0 ? 4 : 3;
261         p->sz = 1<<p->szsh;
262         p->nb = nb;
263         p->pri[0] = prilo;
264         p->pri[1] = prihi;
265         sx = hofs[n];
266         sy = vofs[n] + ppuy;
267         if(reg[MOSAIC] != 0 && (reg[MOSAIC] & (1<<n)) != 0){
268                 p->msz = (reg[MOSAIC] >> 4) + 1;
269                 if(p->msz != 1){
270                         sx -= p->mx = sx % p->msz;
271                         sy -= sy % p->msz;
272                 }
273         }else
274                 p->msz = 1;
275 redo:
276         p->tx = sx >> p->szsh;
277         p->tnx = sx & (p->sz - 1);
278         p->ty = sy >> p->szsh;
279         p->tny = sy & (p->sz - 1);
280         p->t = tile(n, p->tx, p->ty);
281         chr(n, nb, p->sz, p->t, p->tnx, p->tny, p->c);
282         p->pal = palette(n, p->t >> 10 & 7);
283         if((p->tnx & 7) != 0)
284                 shift(p->c, nb, p->tnx & 7, p->t & 0x4000);
285         if(p->msz != 1 && p->mx != 0 && sx % p->msz == 0){
286                 p->mv = bgpixel(p->c, nb, p->t & 0x4000);
287                 if(p->tnx + p->mx >= 8){
288                         sx += p->mx;
289                         goto redo;
290                 }else if(p->mx > 1)
291                         shift(p->c, nb, p->mx - 1, p->t & 0x4000);
292         }
293
294 }
295
296 static void
297 bg(int n)
298 {
299         struct bgctxt *p;
300         u8int v;
301
302         p = bgctxts + n;
303         v = bgpixel(p->c, p->nb, p->t & 0x4000);
304         if(p->msz != 1)
305                 if(p->mx++ == 0)
306                         p->mv = v;
307                 else{
308                         if(p->mx == p->msz)
309                                 p->mx = 0;
310                         v = p->mv;
311                 }
312         if(v != 0)
313                 pixel(n, p->pal + v, p->pri[(p->t & 0x2000) != 0]);
314         if(++p->tnx == p->sz){
315                 p->tx++;
316                 p->tnx = 0;
317                 p->t = tile(n, p->tx, p->ty);
318                 p->pal = palette(n, p->t >> 10 & 7);
319         }
320         if((p->tnx & 7) == 0)
321                 chr(n, p->nb, p->sz, p->t, p->tnx, p->tny, p->c);
322 }
323
324 struct bg7ctxt {
325         int x, y, x0, y0;
326         u8int msz, mx, mv;
327 } b7[2];
328
329 void
330 calc7(void)
331 {
332         s16int t;
333
334         if((reg[0x2105] & 7) != 7)
335                 return;
336         t = hofs[4] - m7[M7X];
337         if((t & 0x2000) != 0)
338                 t |= ~0x3ff;
339         else
340                 t &= 0x3ff;
341         b7->x0 = (t * m7[M7A]) & ~63;
342         b7->y0 = (t * m7[M7C]) & ~63;
343         t = vofs[4] - m7[M7Y];
344         if((t & 0x2000) != 0)
345                 t |= ~0x3ff;
346         else
347                 t &= 0x3ff;
348         b7->x0 += (t * m7[M7B]) & ~63;
349         b7->y0 += (t * m7[M7D]) & ~63;
350         b7->x0 += m7[M7X] << 8;
351         b7->y0 += m7[M7Y] << 8;
352 }
353
354 static void
355 bg7init(int n)
356 {
357         u8int m, y;
358         struct bg7ctxt *p;
359         
360         p = b7 + n;
361         m = reg[M7SEL];
362         y = ppuy;
363         p->msz = 1;
364         if((reg[MOSAIC] & 1) != 0){
365                 p->msz = (reg[MOSAIC] >> 4) + 1;
366                 if(p->msz != 1)
367                         y -= y % p->msz;
368         }
369         if(n == 1)
370                 if((reg[MOSAIC] & 2) != 0)
371                         p->msz = (reg[MOSAIC] >> 4) + 1;
372                 else
373                         p->msz = 1;
374         if((m & 2) != 0)
375                 y = 255 - y;
376         p->x = b7->x0 + ((m7[M7B] * y) & ~63);
377         p->y = b7->y0 + ((m7[M7D] * y) & ~63);
378         if((m & 1) != 0){
379                 p->x += 255 * m7[M7A];
380                 p->y += 255 * m7[M7C];
381         }
382 }
383
384 static void
385 bg7(int n)
386 {
387         u16int x, y;
388         u8int m, v, t;
389         struct bg7ctxt *p;
390
391         p = b7 + n;
392         m = reg[M7SEL];
393         x = p->x >> 8;
394         y = p->y >> 8;
395         if((m & 0x80) == 0){
396                 x &= 1023;
397                 y &= 1023;
398         }else if(x > 1023 || y > 1023){
399                 if((m & 0x40) != 0){
400                         t = 0;
401                         goto lookup;
402                 }
403                 v = 0;
404                 goto end;
405         }
406         t = vram[x >> 2 & 0xfe | y << 5 & 0x7f00];
407 lookup:
408         v = vram[t << 7 | y << 4 & 0x70 | x << 1 & 0x0e | 1];
409 end:
410         if(p->msz != 1){
411                 if(p->mx == 0)
412                         p->mv = v;
413                 else
414                         v = p->mv;
415                 if(++p->mx == p->msz)
416                         p->mx = 0;
417         }
418         if(n == 1){
419                 if((v & 0x7f) != 0)
420                         if((v & 0x80) != 0)
421                                 pixel(1, v & 0x7f, 0x71);
422                         else
423                                 pixel(1, v, 0x11);
424         }else if(v != 0)
425                 pixel(0, v, 0x40);
426         if((m & 1) != 0){
427                 p->x -= m7[M7A];
428                 p->y -= m7[M7C];
429         }else{
430                 p->x += m7[M7A];
431                 p->y += m7[M7C];
432         }
433 }
434
435 static void
436 bgsinit(void)
437 {
438         static int bitch[8];
439
440         switch(mode){
441         case 0:
442                 bginit(0, 2, 0x80, 0xb0);
443                 bginit(1, 2, 0x71, 0xa1);
444                 bginit(2, 2, 0x22, 0x52);
445                 bginit(3, 2, 0x13, 0x43);
446                 break;
447         case 1:
448                 bginit(0, 4, 0x80, 0xb0);
449                 bginit(1, 4, 0x71, 0xa1);
450                 bginit(2, 2, 0x12, (reg[BGMODE] & 8) != 0 ? 0xd2 : 0x42);
451                 break;
452         case 2:
453                 bginit(0, 4, 0x40, 0xa0);
454                 bginit(1, 4, 0x11, 0x71);
455                 break;
456         case 3:
457                 bginit(0, 8, 0x40, 0xa0);
458                 bginit(1, 4, 0x11, 0x71);
459                 break;
460         case 7:
461                 bg7init(0);
462                 if((reg[SETINI] & EXTBG) != 0)
463                         bg7init(1);
464                 break;
465         default:
466                 bgctxts[0].sz = bgctxts[1].sz = 0;
467                 if(bitch[mode]++ == 0)
468                         print("bg mode %d not implemented\n", mode);
469         }
470 }
471
472 static void
473 bgs(void)
474 {
475         switch(mode){
476         case 0:
477                 bg(0);
478                 bg(1);
479                 bg(2);
480                 bg(3);
481                 break;
482         case 1:
483                 bg(0);
484                 bg(1);
485                 bg(2);
486                 break;
487         case 2:
488         case 3:
489                 bg(0);
490                 bg(1);
491                 break;
492         case 7:
493                 bg7(0);
494                 if((reg[SETINI] & EXTBG) != 0)
495                         bg7(1);
496                 break;
497         }
498 }
499
500 static void
501 sprites(void)
502 {
503         static struct {
504                 short x;
505                 u8int y, i, c, sx, sy;
506                 u16int t0, t1;
507         } s[32], *sp;
508         static struct {
509                 short x;
510                 u8int sx, i, c, pal, pri;
511                 u32int *ch;
512         } t[32], *tp;
513         static u32int ch[34];
514         static u8int *p, q, over;
515         static int n, m;
516         static int *sz;
517         static int szs[] = {
518                 8, 8, 16, 16, 8, 8, 32, 32,
519                 8, 8, 64, 64, 16, 16, 32, 32,
520                 16, 16, 64, 64, 32, 32, 64, 64,
521                 16, 32, 32, 64, 16, 32, 32, 32
522         };
523         static u16int base[2];
524         u8int dy, v, col, pri0, pri1, prio;
525         u16int a;
526         u32int w, *cp;
527         int i, nt, dx;
528
529         if(rx == 0){
530                 n = 0;
531                 over = 1;
532                 sp = s;
533                 sz = szs + ((reg[OBSEL] & 0xe0) >> 3);
534                 base[0] = (reg[OBSEL] & 0x07) << 14;
535                 base[1] = base[0] + (((reg[OBSEL] & 0x18) + 8) << 10);
536         }
537         if((rx & 1) == 0){
538                 p = oam + 2 * rx;
539                 if(p[1] == 0xf0)
540                         goto nope;
541                 q = (oam[512 + (rx >> 3)] >> (rx & 6)) & 3;
542                 dy = ppuy - p[1];
543                 sp->sx = sz[q & 2];
544                 sp->sy = sz[(q & 2) + 1];
545                 if(dy >= sp->sy)
546                         goto nope;
547                 sp->x = p[0];
548                 if((q & 1) != 0)
549                         sp->x |= 0xff00;
550                 if(sp->x < -(short)sp->sx && sp->x != -256)
551                         goto nope;
552                 if(n == 32){
553                         over |= 0x40;
554                         goto nope;
555                 }
556                 sp->i = rx >> 1;
557                 sp->y = p[1];
558                 sp->c = p[3];
559                 sp->t0 = p[2] << 5;
560                 sp->t1 = base[sp->c & 1];
561                 sp++;
562                 n++;
563         }
564 nope:
565         if(ppuy != 0){
566                 col = 0;
567                 pri0 = 0;
568                 pri1 = 128;
569                 if((reg[OAMADDH] & 0x80) != 0)
570                         prio = oamaddr >> 2;
571                 else
572                         prio = 0;
573                 for(i = 0, tp = t; i < m; i++, tp++){
574                         dx = rx - tp->x;
575                         if(dx < 0 || dx >= tp->sx)
576                                 continue;
577                         w = *tp->ch;
578                         if((tp->c & 0x40) != 0){
579                                 v = w & 1 | w >> 7 & 2 | w >> 14 & 4 | w >> 21 & 8;
580                                 *tp->ch = w >> 1;
581                         }else{
582                                 v = w >> 7 & 1 | w >> 14 & 2 | w >> 21 & 4 | w >> 28 & 8;
583                                 *tp->ch = w << 1;
584                         }
585                         if((dx & 7) == 7)
586                                 tp->ch++;
587                         nt = (tp->i - prio) & 0x7f;
588                         if(v != 0 && nt < pri1){
589                                 col = tp->pal + v;
590                                 pri0 = tp->pri;
591                                 pri1 = nt;
592                         }
593                 }
594                 if(col > 0)
595                         pixel(OBJ, col, pri0);
596         }
597         if(rx == 255){
598                 cp = ch;
599                 m = n;
600                 for(sp = s + n - 1, tp = t + n - 1; sp >= s; sp--, tp--){
601                         tp->x = sp->x;
602                         tp->sx = 0;
603                         tp->c = sp->c;
604                         tp->pal = 0x80 | sp->c << 3 & 0x70;
605                         tp->pri = 3 * (0x10 + (sp->c & 0x30));
606                         if((tp->c & 8) != 0)
607                                 tp->pri |= OBJ;
608                         else
609                                 tp->pri |= OBJNC;
610                         tp->ch = cp;
611                         tp->i = sp->i;
612                         nt = sp->sx >> 3;
613                         dy = ppuy - sp->y;
614                         if((sp->c & 0x80) != 0)
615                                 dy = sp->sy - 1 - dy;
616                         a = sp->t0 | (dy & 7) << 1;
617                         if(dy >= 8)
618                                 a += (dy & ~7) << 6;
619                         if((sp->c & 0x40) != 0){
620                                 a += sp->sx * 4;
621                                 for(i = 0; i < nt; i++){
622                                         if(cp < ch + nelem(ch)){
623                                                 w  = vram[sp->t1 | (a -= 16) & 0x1fff] << 16;
624                                                 w |= vram[sp->t1 | (a + 1) & 0x1fff] << 24;
625                                                 w |= vram[sp->t1 | (a -= 16) & 0x1fff] << 0;
626                                                 w |= vram[sp->t1 | (a + 1) & 0x1fff] << 8;
627                                                 *cp++ = w;
628                                                 tp->sx += 8;
629                                         }else
630                                                 over |= 0x80;
631                                 }
632                         }else
633                                 for(i = 0; i < nt; i++){
634                                         if(cp < ch + nelem(ch)){
635                                                 w  = vram[sp->t1 | a & 0x1fff];
636                                                 w |= vram[sp->t1 | ++a & 0x1fff] << 8;
637                                                 w |= vram[sp->t1 | (a += 15) & 0x1fff] << 16;
638                                                 w |= vram[sp->t1 | ++a & 0x1fff] << 24;
639                                                 *cp++ = w;
640                                                 tp->sx += 8;
641                                                 a += 15;
642                                         }else
643                                                 over |= 0x80;
644                                 }
645                 }
646                 reg[0x213e] = over;
647         }
648 }
649
650 static u16int
651 colormath(void)
652 {
653         u16int v, w, r, g, b;
654         u8int m, m2, div;
655         int cw;
656         
657         m = reg[CGWSEL];
658         m2 = reg[CGADSUB];
659         cw = -1;
660         switch(m >> 6){
661         default: v = 1; break;
662         case 1: v = cw = window(COL); break;
663         case 2: v = !(cw = window(COL)); break;
664         case 3: v = 0; break;
665         }
666         if(v){
667                 if((pixelcol[0] & 0x10000) != 0)
668                         v = pixelcol[0];
669                 else
670                         v = cgram[pixelcol[0] & 0xff];
671         }
672         if((m2 & (1 << (pixelpri[0] & 0xf))) == 0)
673                 return v;
674         switch((m >> 4) & 3){
675         case 0: break;
676         case 1: if(cw < 0) cw = window(COL); if(!cw) return v; break;
677         case 2: if(cw < 0) cw = window(COL); if(cw) return v; break;
678         default: return v;
679         }
680         div = (m2 & 0x40) != 0;
681         if((m & 2) != 0){
682                 if((pixelcol[1] & 0x10000) != 0)
683                         w = pixelcol[1];
684                 else
685                         w = cgram[pixelcol[1] & 0xff];
686                 div = div && (pixelpri[1] & 0xf) != COL;
687         }else
688                 w = subcolor;
689         if((m2 & 0x80) != 0){
690                 r = (v & 0x7c00) - (w & 0x7c00);
691                 g = (v & 0x03e0) - (w & 0x03e0);
692                 b = (v & 0x001f) - (w & 0x001f);
693                 if(r > 0x7c00) r = 0;
694                 if(g > 0x03e0) g = 0;
695                 if(b > 0x001f) b = 0;
696                 if(div){
697                         r = (r >> 1) & 0xfc00;
698                         g = (g >> 1) & 0xffe0;
699                         b >>= 1;
700                 }
701                 return r | g | b;
702         }else{
703                 r = (v & 0x7c00) + (w & 0x7c00);
704                 g = (v & 0x03e0) + (w & 0x03e0);
705                 b = (v & 0x001f) + (w & 0x001f);
706                 if(div){
707                         r = (r >> 1) & 0xfc00;
708                         g = (g >> 1) & 0xffe0;
709                         b >>= 1;
710                 }
711                 if(r > 0x7c00) r = 0x7c00;
712                 if(g > 0x03e0) g = 0x03e0;
713                 if(b > 0x001f) b = 0x001f;
714                 return r | g | b;
715         }
716 }
717
718 void
719 ppustep(void)
720 {
721         int yvbl;
722
723         mode = reg[BGMODE] & 7;
724         bright = reg[INIDISP] & 0xf;
725         yvbl = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1;
726
727         if(ppux >= XLEFT && ppux <= XRIGHT && ppuy < 0xf0){
728                 rx = ppux - XLEFT;
729                 if(ppuy < yvbl && (reg[INIDISP] & 0x80) == 0){
730                         pixelcol[0] = 0;
731                         pixelpri[0] = COL;
732                         pixelcol[1] = 0x10000 | subcolor;
733                         pixelpri[1] = COL;      
734                         bgs();
735                         sprites();
736                         if(ppuy != 0)
737                                 pixeldraw(rx, ppuy - 1, colormath());
738                 }else if(ppuy != 0)
739                         pixeldraw(rx, ppuy - 1, ppuy >= yvbl ? 0x31c8 : 0);
740         }
741
742         if(ppux == 0x116 && ppuy <= yvbl)
743                 hdma |= reg[0x420c];
744         if((reg[NMITIMEN] & HCNTIRQ) != 0 && htime == ppux && ((reg[NMITIMEN] & VCNTIRQ) == 0 || vtime == ppuy))
745                 irq |= IRQPPU;
746         if(++ppux >= 340){
747                 ppux = 0;
748                 if(++ppuy >= 262){
749                         ppuy = 0;
750                         reg[RDNMI] &= ~VBLANK;
751                         hdma = reg[0x420c]<<8;
752                         flush();
753                 }
754                 if(ppuy < yvbl)
755                         bgsinit();
756                 if(ppuy == yvbl){
757                         reg[RDNMI] |= VBLANK;
758                         if((reg[NMITIMEN] & VBLANK) != 0)
759                                 nmi = 2;
760                         if((reg[NMITIMEN] & AUTOJOY) != 0){
761                                 memwrite(0x4016, 1);
762                                 memwrite(0x4016, 0);
763                                 reg[0x4218] = keylatch >> 16;
764                                 reg[0x4219] = keylatch >> 24;
765                                 keylatch = keylatch << 16 | 0xffff;
766                         }
767                 }
768                 if((reg[NMITIMEN] & (HCNTIRQ|VCNTIRQ)) == VCNTIRQ && vtime == ppuy)
769                         irq |= IRQPPU;
770         }
771 }