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