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