]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gb/mem.c
games/gb: when the LCD is turned off, reset ppuy and ppustate to 0, fixes bug in...
[plan9front.git] / sys / src / games / gb / mem.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "../eui.h"
5 #include "dat.h"
6 #include "fns.h"
7
8 u8int *rom;
9 u8int *romb, *vramb, *wramb, *eramb;
10 u8int wram[32768], vram[16384], oam[256], reg[256];
11 u8int *back;
12 u8int palm[128];
13 u32int pal[64];
14 int nrom, nback, nbackbank;
15 u32int divclock;
16 int prish;
17 MBC3Timer timer, timerl;
18 s8int dma;
19 u32int white;
20 u32int moncols[4];
21
22 Var memvars[] = {ARR(wram), ARR(vram), ARR(oam), ARR(reg), ARR(palm), VAR(clock), VAR(divclock), VAR(mode), VAR(dma), {nil, 0, 0}};
23
24 u8int
25 regread(u8int a)
26 {
27         u8int v;
28
29         switch(a){
30         case JOYP:
31                 v = reg[a] & 0xff;
32                 if((reg[a] & 0x10) == 0)
33                         v &= 0xf0 | ~keys;
34                 if((reg[a] & 0x20) == 0)
35                         v &= 0xf0 | ~(keys >> 4);
36                 return v;
37         case DIV:
38                 return reg[DIV] + (clock - divclock >> 7 - ((mode & TURBO) != 0));
39         case TIMA:
40                 return timread();
41         case STAT:
42                 return reg[a] & 0xf8 | (reg[LYC] == ppuy) << 2 | ppustate;
43         case LY:
44                 return ppuy;
45         case BCPD:
46                 return palm[reg[BCPS] & 0x3f];
47         case OCPD:
48                 return palm[0x40 | reg[OCPS] & 0x3f];
49         case NR13: case NR23: case NR31: case NR33: case NR41:
50                 return 0xff;
51         case NR14: case NR24: case NR34: case NR44:
52                 return reg[a] | 0xbf;
53         case NR52:
54                 return apustatus;
55         case NR11: case NR21:
56                 return reg[a] | 0x3f;
57         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
58         case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
59                 return waveread(a & 0xf);
60         default:
61                 return reg[a];
62         }
63 }
64
65 void
66 colcol(int i, u16int v)
67 {
68         union { u8int c[4]; u32int l; } c;
69
70         c.c[0] = v >> 7 & 0xf8;
71         c.c[1] = v >> 2 & 0xf8;
72         c.c[2] = v << 3;
73         c.c[3] = 0;
74         pal[i] = c.l;   
75 }
76
77 void
78 regwrite(u8int a, u8int v)
79 {
80         extern Event evhblank;
81         int i;
82         u8int u;
83
84         switch(a){
85         case JOYP: v |= 0xcf; break;
86         case SC: v |= 0x7c; break;
87         case DIV:
88                 divclock = clock;
89                 v = 0;
90                 break;
91         case TIMA:
92                 reg[a] = v;
93                 timerset();
94                 return;
95         case TAC:
96                 v |= 0xf8;
97                 timertac(v, 0);
98                 break;
99         case STAT:
100                 v |= 0x80;
101                 if((v & IRQLYC) != 0 && ppuy == reg[LYC])
102                         reg[IF] |= IRQLCDS;
103                 break;
104         case LYC:
105                 if((reg[STAT] & IRQLYC) != 0 && ppuy == v)
106                         reg[IF] |= IRQLCDS;
107                 break;
108         case LCDC:
109                 ppusync();
110                 if((~v & reg[a] & LCDEN) != 0){
111                         ppuy = 0;
112                         ppustate = 0;
113                         delevent(&evhblank);
114                 }
115                 if((v & ~reg[a] & LCDEN) != 0)
116                         addevent(&evhblank, 456*2);
117                 break;
118         case SCY: case SCX: case WY: case WX:
119                 ppusync();
120                 break;
121         case VBK:
122                 if((mode & COL) == 0)
123                         goto ff;
124                 vramb = vram + ((v & 1) << 13);
125                 v |= 0xfe;
126                 break;
127         case SVBK:
128                 if((mode & COL) == 0)
129                         goto ff;
130                 v &= 7;
131                 wramb = wram + (v + (v - 1 >> 3 & 1) << 12);
132                 v |= 0xf8;
133                 break;
134         case BGP:
135         case OBP0:
136         case OBP1:
137                 if((mode & COL) != 0)
138                         break;
139                 ppusync();
140                 i = a - BGP << 2;
141                 pal[i] = moncols[~v & 3];
142                 pal[i+1] = moncols[~v >> 2 & 3];
143                 pal[i+2] = moncols[~v >> 4 & 3];
144                 pal[i+3] = moncols[~v >> 6 & 3];
145                 break;
146         case DMA:
147                 for(i = 0; i < 160; i++)
148                         oam[i] = memread(v << 8 | i);
149                 break;
150         case BCPS: v |= 0x40; break;
151         case OCPS: v |= 0x40; break;
152         case BCPD:
153                 if((mode & COL) == 0)
154                         break;
155                 ppusync();
156                 u = reg[BCPS] & 0x3f;
157                 palm[u] = v;
158                 colcol(u / 2, palm[u & 0xfe] | palm[u | 1] << 8);
159                 if((reg[BCPS] & 0x80) != 0)
160                         reg[BCPS] = reg[BCPS] + 1 - (u + 1 & 0x40);
161                 break;
162         case OCPD:
163                 if((mode & COL) == 0)
164                         break;
165                 ppusync();
166                 u = 0x40 | reg[OCPS] & 0x3f;
167                 palm[u] = v;
168                 colcol(u / 2, palm[u & 0xfe] | palm[u | 1] << 8);
169                 if((reg[OCPS] & 0x80) != 0)
170                         reg[OCPS] = reg[OCPS] + 1 - ((reg[OCPS] & 0x3f) + 1 & 0x40);
171                 break;
172         case IF: v |= 0xe0; break;
173         case IE: v &= 0x1f; break;
174         case KEY1: v |= 0x7e; break;
175         case HDMAC:
176                 if((mode & COL) == 0)
177                         goto ff;
178                 dma = (v & 0x80) != 0 ? -1 : 1;
179                 break;
180         case NR10: v |= 0x80; goto snd;
181         case NR14: case NR24: v |= 0x38; goto snd;
182         case NR30: v |= 0x7f; goto snd;
183         case NR32: v |= 0x9f; goto snd;
184         case NR41: v |= 0xc0; goto snd;
185         case NR44: v |= 0x3f; goto snd;
186         case NR52: v |= 0x70; goto snd;
187         case NR11: case NR12: case NR13:
188         case NR21: case NR22: case NR23:
189         case NR31: case NR33: case NR34:
190         case NR42: case NR43:
191         case NR50: case NR51:
192         snd:
193                 sndwrite(a, v);
194                 return;
195         case SB:
196         case TMA:
197                 break;
198         case HDMASL: case HDMASH: case HDMADL: case HDMADH: case RP:
199                 if((mode & COL) == 0)
200                         goto ff;
201                 break;
202         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
203         case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
204                 wavewrite(a & 0xf, v);
205                 return;
206         default:
207                 if(a >= 0x80)
208                         break;
209         ff:
210                 v = 0xff;
211         }
212         reg[a] = v;
213 }
214
215 static void
216 nope(int p)
217 {
218         print("unimplemented mapper function %d (mapper %d)\n", p, mbc);
219 }
220
221 static int
222 mbc0(int a, int)
223 {
224         if(a < 0)
225                 switch(a){
226                 case INIT:
227                         if(nback != 0)
228                                 eramb = back;
229                         return 0;
230                 case SAVE:
231                 case RSTR:
232                         return 0;
233                 case READ:
234                         return -1;
235                 default:
236                         nope(a);
237                 }
238         return 0;
239 }
240
241 static int
242 mbc1(int a, int v)
243 {
244         static u8int ramen, b0, b1, romram;
245         static Var mbc1vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(romram), {nil, 0, 0}};
246         u16int b;
247
248         if(a < 0)
249                 switch(a){
250                 case INIT:
251                         return 0;
252                 case SAVE:
253                         putvars(mbc1vars);
254                         break;
255                 case RSTR:
256                         getvars(mbc1vars);
257                         break;
258                 case READ:
259                         return -1;
260                 default:
261                         nope(a);
262                 }
263         switch(a >> 13){
264         case 0: ramen = (v & 0xf) == 0xa; break;
265         case 1: v &= 0x1f; b0 = v != 0 ? v : 1; break;
266         case 2: b1 = v & 3; b1 %= nbackbank; break;
267         case 3: romram = v & 1; break;
268         }
269         b = b0;
270         if(!romram)
271                 b |= b1 << 5;
272         b %= nrom >> 14;
273         romb = rom + (b << 14);
274         if(ramen)
275                 if(romram)
276                         eramb = back + (b1 << 13);
277                 else
278                         eramb = back;
279         else
280                 eramb = nil;
281         return 0;
282 }
283
284 static int
285 mbc2(int a, int v)
286 {
287         static int ramen, b;
288         static Var mbc2vars[] = {VAR(ramen), VAR(b), {nil, 0, 0}};
289
290         if(a < 0)
291                 switch(a){
292                 case INIT:
293                         return 0;
294                 case SAVE:
295                         putvars(mbc2vars);
296                         return 0;
297                 case RSTR:
298                         getvars(mbc2vars);
299                         romb = rom + (b << 14);
300                         return 0;
301                 case READ:
302                         if(ramen)
303                                 return back[a & 0x1ff];
304                         return 0xff;
305                 default:
306                         nope(a);
307                 }
308         if((a & 0xc100) == 0)
309                 ramen = (v & 0x0f) == 0x0a;
310         else if((a & 0xc100) == 0x100){
311                 b = v & 0x0f;
312                 if(b == 0)
313                         b++;
314                 b %= nrom >> 14;
315                 romb = rom + (b << 14);
316         }else if((a >> 12) == 0xa && ramen)
317                 back[a & 0x1ff] = v | 0xf0;
318         return 0;
319 }
320
321 void
322 timerforward(MBC3Timer *t)
323 {
324         vlong n, nd;
325         int x;
326         
327         n = nsec();
328         nd = n - t->ns;
329         if(nd < 0)
330                 return;
331         if((t->dh & 0x40) != 0){
332                 t->ns = n;
333                 return;
334         }
335         t->ns = n - nd % BILLION;
336         x = t->sec + t->min * 60 + t->hr * 3600 + t->dl * 86400 + t->dh * (256 * 86400);
337         x += nd / BILLION;
338         t->sec = x % 60;
339         x /= 60;
340         t->min = x % 60;
341         x /= 60;
342         t->hr = x % 24;
343         x /= 24;
344         t->dl = x & 0xff;
345         x >>= 8;
346         t->dh = t->dh & 0xfe | x & 1;
347         if(x >= 2) t->dh |= 0x80;
348 }
349
350 static int
351 mbc3(int a, int v)
352 {
353         static u8int ramen, b0, b1, latch;
354         static Var mbc3vars[] = {VAR(ramen), VAR(b0), VAR(b1), VAR(latch),
355                 VAR(timer.ns), VAR(timer.sec), VAR(timer.min), VAR(timer.hr), VAR(timer.dl), VAR(timer.dh),
356                 VAR(timerl.sec), VAR(timerl.min), VAR(timerl.hr), VAR(timerl.dl), VAR(timerl.dh), {nil, 0, 0}};
357
358         if(a < 0)
359                 switch(a){
360                 case INIT:
361                         return 0;
362                 case SAVE:
363                         putvars(mbc3vars);
364                         return 0;
365                 case RSTR:
366                         getvars(mbc3vars);
367                         romb = rom + (b0 << 14);
368                         break;
369                 case READ:
370                         if(!ramen)
371                                 return -1;
372                         switch(b1){
373                         case 8: return timerl.sec;
374                         case 9: return timerl.min;
375                         case 10: return timerl.hr;
376                         case 11: return timerl.dl;
377                         case 12: return timerl.dh;
378                         }
379                         return -1;
380                 default:
381                         nope(a);
382                 }
383         switch(a >> 13){
384         case 0: ramen = (v & 0xf) == 0xa; break;
385         case 1:
386                 v &= 0x7f;
387                 b0 = v != 0 ? v : 1;
388                 b0 %= nrom >> 14;
389                 romb = rom + (b0 << 14);
390                 return 0;
391         case 2: b1 = v & 15; break;
392         case 3:
393                 if(latch == 0 && v == 1){
394                         timerl = timer;
395                         timerforward(&timerl);
396                 }
397                 latch = v;
398                 break;
399         case 0xa:
400                 if(!ramen)
401                         return 0;
402                 switch(b1){
403                 case 8: timerforward(&timer); timer.sec = v; break;
404                 case 9: timerforward(&timer); timer.min = v; break;
405                 case 10: timerforward(&timer); timer.hr = v; break;
406                 case 11: timerforward(&timer); timer.dl = v; break;
407                 case 12: timerforward(&timer); timer.dh = v; break;
408                 }
409                 return 0;
410         }
411         eramb = ramen && b1 < nbackbank ? back + (b1 << 13) : nil;
412         return 0;
413 }
414
415 static int
416 mbc5(int a, int v)
417 {
418         static u8int ramen, b1;
419         static u16int b0;
420         static Var mbc5vars[] = {VAR(ramen), VAR(b0), VAR(b1), {nil, 0, 0}};
421
422         if(a < 0)
423                 switch(a){
424                 case INIT:
425                         return 0;
426                 case SAVE:
427                         putvars(mbc5vars);
428                         return 0;
429                 case RSTR:
430                         getvars(mbc5vars);
431                         break;
432                 case READ:
433                         return -1;
434                 default:
435                         nope(a);
436                 }
437         switch(a >> 12){
438         case 0: case 1: ramen = (v & 0xf) == 0xa; break;
439         case 2: b0 = b0 & 0x100 | v; break;
440         case 3: b0 = b0 & 0xff | v << 8 & 0x100; break;
441         case 4: b1 = v & 0xff; b1 %= nbackbank; break;
442         }
443         b0 %= nrom >> 14;
444         romb = rom + (b0 << 14); 
445         eramb = ramen ? back + (b1 << 13) : nil;
446         return 0;
447         
448 }
449
450 int (*mappers[7])(int, int) = {mbc0, mbc1, mbc2, mbc3, mbc0, mbc5, mbc0};
451 int (*mapper)(int, int);
452
453 u8int
454 memread(u16int a)
455 {
456         switch(a >> 12){
457         case 0: case 1: case 2: case 3:
458                 return rom[a];
459         case 4: case 5: case 6: case 7:
460                 return romb[a - 0x4000];
461         case 8: case 9:
462                 return vramb[a - 0x8000];
463         case 10: case 11:
464                 if(eramb != nil)
465                         return eramb[a - 0xa000];
466                 return mapper(READ, a);
467         case 12: case 14:
468                 return wram[a & 0xfff];
469         case 15:
470                 if(a >= 0xff00)
471                         return regread(a);
472                 else if(a >= 0xfe00)
473                         return oam[a - 0xfe00];
474         case 13:
475                 return wramb[a & 0xfff];
476         }
477         return 0xff;
478 }
479
480 void
481 memwrite(u16int a, u8int v)
482 {
483         switch(a >> 12){
484         case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
485                 mapper(a, v);
486                 return;
487         case 8: case 9:
488                 vramb[a - 0x8000] = v;
489                 return;
490         case 10: case 11:
491                 if(eramb != nil)
492                         eramb[a - 0xa000] = v;
493                 else
494                         mapper(a, v);
495                 writeback();
496                 return;
497         case 12: case 14:
498                 wram[a & 0xfff] = v;
499                 return;
500         case 15:
501                 if(a >= 0xff00){
502                         regwrite(a, v);
503                         return;
504                 }else if(a >= 0xfe00){
505                         oam[a - 0xfe00] = v;
506                         return;
507                 }
508         case 13:
509                 wramb[a & 0xfff] = v;
510         }
511 }
512
513 void
514 meminit(void)
515 {
516         union { u8int c[4]; u32int l; } c;
517
518         c.c[0] = c.c[1] = c.c[2] = 0;
519         c.c[3] = 1;
520         for(; c.l != 1; prish++)
521                 c.l >>= 1;
522         
523         c.c[0] = c.c[1] = c.c[2] = 0xff;
524         c.c[3] = 0;
525         white = c.l;
526
527         romb = rom + 0x4000;
528         wramb = wram + 0x1000;
529         vramb = vram;
530         mapper = mappers[mbc];
531         mapper(INIT, 0);
532         
533         reg[LCDC] = 0x91;
534         reg[VBK] = 0xfe;
535         reg[SVBK] = 0xf8;
536         reg[IF] = 0xe0;
537 }
538
539 void
540 memload(void)
541 {
542         int i;
543         u8int v;
544
545         if((mode & COL) != 0){
546                 for(i = 0; i < 64; i++)
547                         colcol(i, palm[2*i] | palm[2*i+1] << 8);
548                 vramb = vram + ((reg[VBK] & 1) << 13);
549                 wramb = wram + (reg[SVBK] + (reg[SVBK] - 1 >> 3 & 1) << 12);
550         }else{
551                 v = reg[BGP];
552                 pal[0] = moncols[~v & 3];
553                 pal[1] = moncols[~v >> 2 & 3];
554                 pal[2] = moncols[~v >> 4 & 3];
555                 pal[3] = moncols[~v >> 6 & 3];
556                 v = reg[OBP0];
557                 pal[4] = moncols[~v & 3];
558                 pal[5] = moncols[~v >> 2 & 3];
559                 pal[6] = moncols[~v >> 4 & 3];
560                 pal[7] = moncols[~v >> 6 & 3];
561                 v = reg[OBP1];
562                 pal[8] = moncols[~v & 3];
563                 pal[9] = moncols[~v >> 2 & 3];
564                 pal[10] = moncols[~v >> 4 & 3];
565                 pal[11] = moncols[~v >> 6 & 3];
566         }
567
568 }
569
570 int
571 dmastep(void)
572 {
573         int i;
574         u16int sa, da;
575         
576         sa = (reg[HDMASL] | reg[HDMASH] << 8) & 0xfff0;
577         da = (reg[HDMADL] | reg[HDMADH] << 8) & 0x1ff0 | 0x8000;
578         for(i = 0; i < 16; i++)
579                 memwrite(da++, memread(sa++));
580         reg[HDMASL] += 16;
581         if((reg[HDMASL] & 0xf0) == 0)
582                 reg[HDMASH]++;
583         reg[HDMADL] += 16;
584         if((reg[HDMADL] & 0xf0) == 0)
585                 reg[HDMADH]++;
586         if((reg[HDMAC] & 0x7f) == 0)
587                 dma = 0;
588         else{
589                 reg[HDMAC]--;
590                 if((reg[HDMAC] & 0x80) != 0)
591                         dma = 1;
592         }
593         return 64;
594 }