]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gba/mem.c
games/mahjongg: off by one in bmatch(), fix hint() redraw (thanks Kenji)
[plan9front.git] / sys / src / games / gba / mem.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 uchar bios[16*KB], wram0[32*KB], wram1[256*KB];
8 uchar vram[96*KB];
9 u16int pram[512], oam[512];
10 uchar *rom, *back;
11 int nrom, nback;
12 u16int reg[512];
13 int dmaact;
14 enum {
15         DMASRC,
16         DMADST,
17         DMACNT
18 };
19 u32int dmar[16];
20 u8int waitst[16] = {5, 5, 5, 5, 3, 5, 5, 9, 8, 10, 10, 14};
21 u32int eepstart;
22
23 Var memvars[] = {
24         ARR(wram0), ARR(wram1), ARR(vram), ARR(pram), ARR(oam), ARR(reg),
25         VAR(dmaact), ARR(dmar), ARR(waitst),
26         {nil, 0, 0},
27 };
28
29 extern int cyc;
30
31 static int eepromread(void);
32 static void eepromwrite(int);
33 static u8int flashread(u16int);
34 static void flashwrite(u16int, u8int);
35
36 static u32int
37 arread(uchar *c, int n)
38 {
39         switch(n){
40         default:
41                 return c[0];
42         case 2:
43                 return c[0] | c[1] << 8;
44         case 4:
45                 return c[0] | c[1] << 8 | c[2] << 16 | c[3] << 24;
46         }
47 }
48
49 static void
50 arwrite(uchar *c, u32int v, int n)
51 {
52         switch(n){
53         case 4:
54                 c[3] = v >> 24;
55                 c[2] = v >> 16;
56         case 2:
57                 c[1] = v >> 8;
58         default:
59                 c[0] = v;
60         }
61 }
62
63 static u32int
64 ar16read(u16int *c, int h, int n)
65 {
66         switch(n){
67         case 1:
68                 return c[0] >> (h << 3);
69         default:
70                 return c[0];
71         case 4:
72                 return c[0] | c[1] << 16;
73         }
74 }
75
76 static void
77 ar16write(u16int *c, int h, u32int v, int n)
78 {
79         switch(n){
80         case 1:
81                 if(h)
82                         c[0] = c[0] & 0xff | ((u8int)v) << 8;
83                 else
84                         c[0] = c[0] & 0xff00 | (u8int)v;
85                 break;
86         case 2:
87                 c[0] = v;
88                 break;
89         case 4:
90                 c[0] = v;
91                 c[1] = v >> 16;
92                 break;
93         }
94 }
95
96 static u32int
97 regread(u32int a)
98 {
99         u32int v;
100
101         switch(a){
102         case DISPSTAT*2:
103                 v = reg[a/2] & ~7;
104                 
105                 if(ppuy >= 160 && ppuy != 227)
106                         v |= 1;
107                 if(hblank)
108                         v |= 2;
109                 if(ppuy == v >> 8)
110                         v |= 4;
111                 return v;
112         case 0x006:
113                 return ppuy;
114         case 0x100: case 0x104: case 0x108: case 0x10c:
115                 return timerget((a - 0x100) / 4);
116         case 0x130:
117                 return keys ^ 0x3ff;
118         default:
119                 return reg[a/2];
120         }
121 }
122
123 static void
124 regwrite16(u32int a, u16int v)
125 {
126         u16int *p;
127         int i;
128         static u8int ws0[4] = {5,4,3,9};
129
130         if(a < 0x56)
131                 ppuwrite(a, v);
132         else if(a < 0xa0)
133                 sndwrite(a, v);
134         p = &reg[a/2];
135         switch(a){
136         case IF*2:
137                 *p &= ~v;
138                 setif(0);
139                 return;
140         case IME*2: case IE*2:
141                 *p = v;
142                 setif(0);
143                 return;
144         case DMA0CNTH*2: case DMA1CNTH*2: case DMA2CNTH*2: case DMA3CNTH*2:
145                 i = (a - DMA0CNTH*2) / 12;
146                 if((v & DMAEN) != 0){
147                         if((v >> DMAWHEN & 3) == 0)
148                                 dmaact |= 1<<i;
149                         if(i == 3 && (v >> DMAWHEN & 3) == 3)
150                                 print("DMA video capture mode\n");
151                         dmar[4*i + DMASRC] = p[-5] | p[-4] << 16;
152                         dmar[4*i + DMADST] = p[-3] | p[-2] << 16;
153                         dmar[4*i + DMACNT] = p[-1];
154                 }else
155                         dmaact &= ~1<<i;
156                 break;
157         case SOUNDCNTH*2:
158                 soundcnth(v);
159                 break;
160         case FIFOAH*2: case FIFOBH*2:
161                 fifoput(a >> 2 & 1, p[-1] | v << 16);
162                 break;
163         case 0x102: case 0x106: case 0x10a: case 0x10e:
164                 timerset((a - 0x102) / 4, v);
165                 break;
166         case WAITCNT*2:
167                 waitst[3] = waitst[7] = ws0[v & 3];
168                 waitst[0] = ws0[v >> 2 & 3];
169                 waitst[4] = ((v & 1<<4) == 0) + 2;
170                 waitst[1] = ws0[v >> 5 & 3];
171                 waitst[5] = (v & 1<<7) == 0 ? 5 : 2;
172                 waitst[2] = ws0[v >> 8 & 3];
173                 waitst[6] = (v & 1<<10) == 0 ? 9 : 2;
174                 for(i = 0; i < 8; i++)
175                         waitst[8 + i] = waitst[i] + waitst[i | 4];
176                 break;
177         case 0x301:
178                 cpuhalt = 1;
179                 break;
180         }
181         *p = v;
182 }
183
184 static void
185 regwrite(u32int a, u32int v, int n)
186 {
187         u16int w;
188
189         switch(n){
190         case 1:
191                 if((a & ~1) == IF)
192                         w = 0;
193                 else
194                         w = regread(a);
195                 if((a & 1) == 0)
196                         w = w & 0xff00 | (u8int)v;
197                 else
198                         w = w & 0xff | v << 8;
199                 regwrite16(a & ~1, w);
200                 break;
201         default:
202                 regwrite16(a, v);
203                 break;
204         case 4:
205                 regwrite16(a, v);
206                 regwrite16(a + 2, v >> 16);
207                 break;
208         }
209 }
210
211 void
212 setif(u16int v)
213 {
214         reg[IF] |= v;
215         irq = (reg[IME] & 1) != 0 && (reg[IF] & reg[IE]) != 0;
216         if(irq)
217                 cpuhalt = 0;
218 }
219
220 u32int
221 memread(u32int a, int n, int seq)
222 {
223         u32int b;
224         assert((a & n-1) == 0);
225
226         switch(a >> 24){
227         case 0:
228                 b = a & sizeof(bios) - 1;
229                 cyc++;
230                 return arread(bios + b, n);
231         case 2:
232                 b = a & sizeof(wram1) - 1;
233                 cyc += n > 2 ? 6 : 3;
234                 return arread(wram1 + b, n);
235         case 3:
236                 b = a & sizeof(wram0) - 1;
237                 cyc++;
238                 return arread(wram0 + b, n);
239         case 4:
240                 b = a & 0xffffff;
241                 if(b >= sizeof(reg)) goto fault;
242                 cyc++;
243                 if(n == 4)
244                         return regread(b) | regread(b+2) << 16;
245                 else if(n == 1)
246                         if((b & 1) != 0)
247                                 return regread(b) >> 8;
248                         else
249                                 return regread(b) & 0xff;
250                 return regread(b);
251         case 5:
252                 b = a & sizeof(pram) - 1;
253                 cyc += (n+1) >> 1;
254                 return ar16read(pram + b/2, b & 1, n);
255         case 6:
256                 b = a & 128*KB - 1;
257                 if(b >= 64*KB)
258                         b &= ~(32*KB);
259                 cyc += (n+1) >> 1;
260                 return arread(vram + b, n);
261         case 7:
262                 b = a & sizeof(oam) - 1;
263                 cyc++;
264                 return ar16read(oam + b/2, b & 1, n);
265         case 8: case 9: case 10: case 11: case 12: case 13:
266                 b = a & 0x1ffffff;
267                 cyc += waitst[(a >> 25) - 4 | seq << 2 | (n > 2) << 3];
268                 if(b >= nrom){
269                         if(b >= eepstart)
270                                 return eepromread();
271                         return 0;
272                 }
273                 return arread(rom + b, n);
274         case 14:
275                 if(backup == SRAM){
276                         b = a & nback - 1;
277                         return arread(back + b, n);
278                 }
279                 if(backup == FLASH)
280                         return flashread(a);
281                 return 0;
282         default:
283         fault:
284                 print("read from %#.8ux (pc=%#.8ux)\n", a, curpc);
285                 return 0;
286         }
287 }
288
289 void
290 memwrite(u32int a, u32int v, int n)
291 {
292         u32int b;
293         assert((a & n-1) == 0);
294
295         switch(a >> 24){
296         case 0:
297                 return;
298         case 2:
299                 b = a & sizeof(wram1) - 1;
300                 cyc += n > 2 ? 6 : 3;
301                 arwrite(wram1 + b, v, n);
302                 return;
303         case 3:
304                 b = a & sizeof(wram0) - 1;
305                 cyc++;
306                 arwrite(wram0 + b, v, n);
307                 return;
308         case 4:
309                 cyc++;
310                 b = a & 0xffffff;
311                 if(b == 0x410) return;
312                 if(b >= sizeof(reg)) goto fault;
313                 regwrite(b, v, n);
314                 return;
315         case 5:
316                 b = a & sizeof(pram) - 1;
317                 cyc += (n+1) >> 1;
318                 ar16write(pram + b/2, b & 1, v, n);
319                 return;
320         case 6:
321                 b = a & 128*KB - 1;
322                 if(b >= 64*KB)
323                         b &= ~(32*KB);
324                 cyc += (n+1) >> 1;
325                 arwrite(vram + b, v, n);
326                 return;
327         case 7:
328                 b = a & sizeof(oam) - 1;
329                 cyc++;
330                 ar16write(oam + b/2, b & 1, v, n);
331                 return;
332         case 8: case 9: case 10: case 11: case 12: case 13:
333                 if(backup == EEPROM){
334                         b = a & 0x01ffffff;
335                         if(b >= eepstart)
336                                 eepromwrite(v & 1);
337                 }
338                 return;
339         case 14:
340                 if(backup == SRAM){
341                         b = a & nback - 1;
342                         arwrite(back + b, v, n);
343                         writeback();
344                         return;
345                 }
346                 if(backup == FLASH){
347                         flashwrite(a, v);
348                         return;
349                 }
350                 return;
351         default:
352         fault:
353                 print("write to %#.8ux, value %#.8ux (pc=%#.8ux)\n", a, v, curpc);
354         }
355 }
356
357 void
358 memreset(void)
359 {
360         reg[0x88/2] = 0x200;
361         reg[BG2PA] = reg[BG2PD] = 0x100;
362         if(backup == EEPROM)
363                 if(nrom <= 16*KB*KB)
364                         eepstart = 0x1000000;
365                 else
366                         eepstart = 0x1ffff00;
367         else
368                 eepstart = -1;
369 }
370
371 int
372 dmastep(void)
373 {
374         int i;
375         u16int *cntp, cnt;
376         u32int *dr;
377         u32int v;
378         int sz, snd;
379         
380         cyc = 0;
381         for(i = 0; i < 4; i++)
382                 if((dmaact & 1<<i) != 0)
383                         break;
384         if(i == 4)
385                 return cyc;
386         curpc = -1;
387         cntp = reg + DMA0CNTH + i * 6;
388         cnt = *cntp;
389         dr = dmar + 4 * i;
390         snd = (cnt >> DMAWHEN & 3) == 3 && (i == 1 || i == 2);
391         if(snd)
392                 cnt = cnt & ~(3 << DMADCNT) | DMAFIX << DMADCNT | DMAWIDE;
393
394         sz = (cnt & DMAWIDE) != 0 ? 4 : 2;
395         if(i == 0)
396                 dr[DMASRC] &= 0x07FFFFFF;
397         else
398                 dr[DMASRC] &= 0x0FFFFFFF;
399         if(i != 3)
400                 dr[DMADST] &= 0x7FFFFFFF;
401         else
402                 dr[DMADST] &= 0x0FFFFFFF;
403         v = memread(dr[DMASRC] & -sz, sz, 1);
404         memwrite(dr[DMADST] & -sz, v, sz);
405         switch(cnt >> DMADCNT & 3){
406         case DMAINC: case DMAINCREL: dr[DMADST] += sz; break;
407         case DMADEC: dr[DMADST] -= sz; break;
408         }
409         switch(cnt >> DMASCNT & 3){
410         case DMAINC: dr[DMASRC] += sz; break;
411         case DMADEC: dr[DMASRC] -= sz; break;
412         }
413         if(dr[DMACNT] == 0)
414                 dr[DMACNT] = i != 3 ? 0x4000 : 0x10000;
415         if(--dr[DMACNT] == 0){
416                 dmaact &= ~(1<<i);
417                 if((cnt & DMAREP) != 0){
418                         dr[DMACNT] = cntp[-1];
419                         if((cnt >> DMADCNT & 3) == DMAINCREL)
420                                 dr[DMADST] = cntp[-3] | cntp[-2] << 16;
421                 }else
422                         *cntp &= ~DMAEN;
423                 if((cnt & DMAIRQ) != 0)
424                         setif(IRQDMA0 << i);
425         }
426         return cyc;
427 }
428
429 void
430 dmastart(int cond)
431 {
432         int i;
433         u16int *cntp, cnt, c;
434         
435         cntp = reg + DMA0CNTH;
436         for(i = 0; i < 4; i++, cntp += 6){
437                 cnt = *cntp;
438                 if((cnt & DMAEN) == 0)
439                         continue;
440                 c = cnt >> DMAWHEN & 3;
441                 if(c == 3)
442                         c += (i + 1) / 2;
443                 if(c == cond){
444                         dmaact |= 1<<i;
445                         if(c == DMASOUND)
446                                 dmar[i * 4 + DMACNT] = 4;
447                 }
448         }
449 }
450
451 int eepromstate, eeprompos, eepromaddr;
452 u64int eepromdata;
453
454 enum {
455         EEPROMCMD,
456         EEPROMRDCMD,
457         EEPROMRDRESP,
458         EEPROMWRCMD,
459         EEPROMWRDATA,
460         EEPROMWRRESP,
461 };
462
463 static int
464 eepromread(void)
465 {
466         int v;
467
468         switch(eepromstate){
469         case EEPROMRDRESP:
470                 eeprompos++;
471                 if(eeprompos <= 4)
472                         return 0;
473                 if(eeprompos == 68){
474                         eepromstate = EEPROMCMD;
475                         eeprompos = 0;
476                 }
477                 v = eepromdata >> 63;
478                 eepromdata <<= 1;
479                 return v;
480         case EEPROMWRRESP:
481                 if(++eeprompos == 1000){
482                         eepromstate = EEPROMCMD;
483                         eeprompos = 0;
484                         return 1;
485                 }
486                 return 0;
487         default:
488                 return 0;
489         }
490 }
491
492 static void
493 eepromwrite(int n)
494 {
495         uchar *p;
496
497         switch(eepromstate){
498         case EEPROMCMD:
499                 eepromaddr = eepromaddr << 1 | n;
500                 if(++eeprompos >= 2){
501                         switch(eepromaddr & 3){
502                         case 2:
503                                 eepromstate = EEPROMWRCMD;
504                                 break;
505                         case 3:
506                                 eepromstate = EEPROMRDCMD;
507                                 break;
508                         }
509                         eeprompos = 0;
510                 }
511                 break;
512         case EEPROMRDCMD:
513         case EEPROMWRCMD:
514                 eepromaddr = eepromaddr << 1 | n;
515                 eeprompos++;
516                 if(nback == 512){
517                         if(eeprompos >= 7)
518                                 eepromaddr = eepromaddr >> 1 & 0x3f;
519                         else
520                                 break;
521                 }else{
522                         if(eeprompos >= 15)
523                                 eepromaddr = eepromaddr >> 1 & 0x3fff;
524                         else
525                                 break;
526                 }
527                 if(eepromstate == EEPROMRDCMD){
528                         p = back + eepromaddr * 8;
529                         eepromdata = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24 | (u64int)p[4] << 32 | 
530                                 (u64int)p[5] << 40 | (u64int)p[6] << 48 | (u64int)p[7] << 56;
531                         eeprompos = 0;
532                         eepromstate = EEPROMRDRESP;
533                         break;
534                 }else{
535                         eepromdata = n;
536                         eeprompos = 1;
537                         eepromstate = EEPROMWRDATA;
538                         break;
539                 }
540         case EEPROMWRDATA:
541                 if(eeprompos == 64){
542                         p = back + eepromaddr * 8;
543                         p[0] = eepromdata;
544                         p[1] = eepromdata >> 8;
545                         p[2] = eepromdata >> 16;
546                         p[3] = eepromdata >> 24;
547                         p[4] = eepromdata >> 32;
548                         p[5] = eepromdata >> 40;
549                         p[6] = eepromdata >> 48;
550                         p[7] = eepromdata >> 56;
551                         eepromstate = EEPROMWRRESP;
552                         eeprompos = 0;
553                         writeback();
554                         break;
555                 }
556                 eepromdata = eepromdata << 1 | n;
557                 eeprompos++;
558                 break;
559         }
560 }
561
562 int flashstate, flashmode, flashbank;
563
564 enum {
565         FLASHCMD0,
566         FLASHCMD1,
567         FLASHCMD2,
568         FLASHBANK,
569         FLASHWRITE,
570         
571         FLASHID = 1,
572         FLASHERASE = 2,
573 };
574
575 static u8int
576 flashread(u16int a)
577 {
578         if((flashmode & FLASHID) != 0)
579                 return (a & 1) != 0 ? 0xd4 : 0xbf;
580         return back[(flashbank << 16) + a];
581 }
582
583 static void
584 flashwrite(u16int a, u8int v)
585 {
586         int erase;
587
588         switch(flashstate){
589         case FLASHCMD0:
590                 if(a == 0x5555 && v == 0xaa)
591                         flashstate = FLASHCMD1;
592                 break;
593         case FLASHCMD1:
594                 if(a == 0x2aaa && v == 0x55)
595                         flashstate = FLASHCMD2;
596                 else
597                         flashstate = FLASHCMD0;
598                 break;
599         case FLASHCMD2:
600                 flashstate = FLASHCMD0;
601                 erase = flashmode & FLASHERASE;
602                 flashmode &= ~FLASHERASE;
603                 switch(v){
604                 case 0x90: flashmode |= FLASHID; break;
605                 case 0xF0: flashmode &= ~FLASHID; break;
606                 case 0x80: flashmode |= FLASHERASE; break;
607                 case 0x10:
608                         if(erase){
609                                 memset(back, 0xff, nback);
610                                 writeback();
611                         }
612                         break;
613                 case 0x30:
614                         if(erase){
615                                 memset(back + (a & 0xf000) + (flashbank << 16), 0xff, 4096);
616                                 writeback();
617                         }
618                         break;
619                 case 0xA0:
620                         writeback();
621                         flashstate = FLASHWRITE;
622                         break;
623                 case 0xB0: flashstate = FLASHBANK; break;
624                 default:
625                         print("unknown flash cmd %x\n", v);
626                 }
627                 break;
628         case FLASHBANK:
629                 flashbank = v % (nback >> 16);
630                 flashstate = FLASHCMD0;
631                 break;
632         case FLASHWRITE:
633                 back[(flashbank << 16) + a] &= v;
634                 writeback();
635                 flashstate = FLASHCMD0;
636                 break;
637         }
638 }
639