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