]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/snes/mem.c
9716b7387882ae8878b125eb4886337f16cb37f3
[plan9front.git] / sys / src / games / snes / mem.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include "dat.h"
5 #include "fns.h"
6
7 u8int reg[32768];
8 u8int mem[131072];
9 u8int oam[544], vram[65536];
10 u16int cgram[256];
11 u16int oamaddr, vramlatch;
12 u32int keylatch, lastkeys;
13 int memcyc;
14 enum {
15         OAMLATCH,
16         CGLATCH,
17         CGLH,
18         OFSPREV,
19         M7PREV,
20         OPCTLATCH,
21         OPHCTH,
22         OPVCTH,
23 };
24
25 extern void calc7(void);
26
27 static u16int
28 vrammap(u16int a)
29 {
30         switch(reg[0x2115] & 12){
31         default: return a << 1;
32         case  4: return a << 1 & 0xfe00 | a << 4 & 0x01f0 | a >> 4 & 0x000e;
33         case  8: return a << 1 & 0xfc00 | a << 4 & 0x03f0 | a >> 5 & 0x000e;
34         case 12: return a << 1 & 0xf800 | a << 4 & 0x07f0 | a >> 6 & 0x000e;
35         }
36 }
37
38 static void
39 incvram(int i, int r)
40 {
41         u16int a, b;
42         int c;
43         
44         c = reg[0x2115];
45         if((c >> 7) != i)
46                 return;
47         a = reg[0x2116] | reg[0x2117] << 8;
48         if(r){
49                 b = vrammap(a);
50                 vramlatch = vram[b++];
51                 vramlatch |= vram[b] << 8;
52         }
53         switch(c & 3){
54         case 0: a++; break;
55         case 1: a += 32; break;
56         default: a += 128; break;
57         }
58         reg[0x2116] = a;
59         reg[0x2117] = (a >> 8) & 0x7f;
60 }
61
62 static void
63 incwram(void)
64 {
65         if(++reg[0x2181] == 0)
66                 if(++reg[0x2182] == 0)
67                         reg[0x2183] ^= 1;
68 }
69
70 static void
71 hvlatch(void)
72 {
73         reg[0x213c] = ppux;
74         reg[OPHCTH] = ppux >> 8;
75         reg[0x213d] = ppuy;
76         reg[OPVCTH] = ppuy >> 8;
77         reg[OPCTLATCH] |= 0x40;
78 }
79
80 static u16int
81 swaprb(u16int a)
82 {
83         return (a & 0x83e0) | (a & 0x7c00) >> 10 | (a & 0x001f) << 10;
84 }
85
86 static void
87 mouselatch(void)
88 {
89         int x, y;
90         u32int v;
91         
92         v = keys & 0xffff0000;
93         x = (keys & 0xff) - (lastkeys & 0xff);
94         y = (keys >> 8 & 0xff) - (lastkeys >> 8 & 0xff);
95         if(x < 0){
96                 v |= 0x80;
97                 x = -x;
98         }
99         if(y < 0){
100                 v |= 0x8000;
101                 y = -y;
102         }
103         if(x > 127)
104                 x = 127;
105         if(y > 127)
106                 y = 127;
107         keylatch = v | x | y << 8;
108         lastkeys = keys;
109 }
110
111 u8int
112 regread(u16int p)
113 {
114         u8int v;
115         u16int a;
116         int r;
117
118         if(p < 0x2000)
119                 return mem[p];
120         switch(p){
121         case 0x2134: case 0x2135: case 0x2136:
122                 r = ((signed short)m7[0] * (signed char)reg[0x211c]) & 0xffffff;
123                 return r >> 8 * (p - 0x2134);
124         case 0x2137:
125                 if((reg[0x4201] & 0x80) != 0)
126                         hvlatch();
127                 return 0;
128         case 0x2138:
129                 if(oamaddr < 0x200)
130                         v = oam[oamaddr];
131                 else
132                         v = oam[oamaddr & 0x21f];
133                 oamaddr = (oamaddr + 1) & 0x3ff;
134                 return v;
135         case 0x2139:
136                 v = vramlatch;
137                 incvram(0, 1);
138                 return v;
139         case 0x213a:
140                 v = vramlatch >> 8;
141                 incvram(1, 1);
142                 return v;
143         case 0x213b:
144                 a = swaprb(cgram[reg[0x2121]]);
145                 if(reg[CGLH] != 0){
146                         a >>= 8;
147                         reg[0x2121]++;
148                 }
149                 reg[CGLH] ^= 1;
150                 return a;
151         case 0x213c:
152                 reg[OPCTLATCH] ^= 1;
153                 if((reg[OPCTLATCH] & 1) == 0)
154                         return reg[OPHCTH];
155                 break;
156         case 0x213d:
157                 reg[OPCTLATCH] ^= 2;
158                 if((reg[OPCTLATCH] & 2) == 0)
159                         return reg[OPVCTH];
160                 break;
161         case 0x213f:
162                 v = 2 | reg[OPCTLATCH] & 0x40;
163                 if((reg[0x4201] & 0x80) != 0)
164                         reg[OPCTLATCH] &= ~0x43;
165                 else
166                         reg[OPCTLATCH] &= ~3;
167                 return v;
168         case 0x2180:
169                 v = memread(0x7e0000 | reg[0x2181] | reg[0x2182] << 8 | (reg[0x2183] & 1) << 16);
170                 incwram();
171                 return v;
172         case 0x4016:
173                 if((reg[0x4016] & 1) != 0){
174                         if(mouse)
175                                 if((keys & 0x300000) == 0x300000)
176                                         keys &= ~0x300000;
177                                 else
178                                         keys += 0x100000;
179                         return keys >> 31;
180                 }
181                 v = keylatch >> 31;
182                 keylatch = (keylatch << 1) | 1;
183                 return v;
184         case 0x4017:
185                 return 0;
186         case 0x4211:
187                 v = irq;
188                 irq &= ~IRQPPU;
189                 return v;
190         case 0x4212:
191                 v = 0;
192                 if(ppux >= 274 || ppux == 0)
193                         v |= 0x40;
194                 a = (reg[SETINI] & OVERSCAN) != 0 ? 0xf0 : 0xe1;
195                 if(ppuy >= a){
196                         v |= 0x80;
197                         if(ppuy <= a + 2 && (reg[NMITIMEN] & AUTOJOY) != 0)
198                                 v |= 1;
199                 }
200                 return v;
201         }
202         if((p & 0xff40) == 0x2140)
203                 return spcmem[0xf4 | p & 3];
204         return reg[p];
205 }
206
207 void
208 regwrite(u16int p, u8int v)
209 {
210         u16int a;
211
212         if(p < 0x2000){
213                 mem[p] = v;
214                 return;
215         }
216         switch(p){
217         case 0x2102:
218                 oamaddr = (reg[0x2103] & 1) << 9 | v << 1;
219                 break;
220         case 0x2103:
221                 oamaddr = (v & 1) << 9 | reg[0x2102];
222                 break;
223         case 0x2104:
224                 if((oamaddr & 1) == 0)
225                         reg[OAMLATCH] = v;
226                 if(oamaddr < 0x200){
227                         if((oamaddr & 1) != 0){
228                                 oam[oamaddr - 1] = reg[OAMLATCH];
229                                 oam[oamaddr] = v;
230                         }
231                 }else
232                         oam[oamaddr & 0x21f] = v;
233                 oamaddr = (oamaddr + 1) & 0x3ff;
234                 return;
235         case 0x2105:
236                 reg[p] = v;
237                 calc7();
238                 return;
239         case 0x210d:
240                 hofs[4] = (v & 0x1f) << 8 | reg[M7PREV];
241                 if((v & 0x10) != 0)
242                         hofs[4] |= 0xe000;
243                 reg[M7PREV] = v;
244                 calc7();
245         case 0x210f: case 0x2111: case 0x2113:
246                 a = (p - 0x210d) >> 1;
247                 hofs[a] = v << 8 | reg[OFSPREV] & ~7 | (hofs[a] >> 8) & 7;
248                 reg[OFSPREV] = v;
249                 break;
250         case 0x210e:
251                 vofs[4] = (v & 0x1f) << 8 | reg[M7PREV];
252                 if((v & 0x10) != 0)
253                         vofs[4] |= 0xe000;
254                 reg[M7PREV] = v;
255                 calc7();
256         case 0x2110: case 0x2112: case 0x2114:
257                 vofs[(p - 0x210e) >> 1] = v << 8 | reg[OFSPREV];
258                 reg[OFSPREV] = v;
259                 break;
260         case 0x2116:
261                 break;
262         case 0x2117:
263                 v &= 0x7f;
264                 break;
265         case 0x2118:
266                 a = vrammap(reg[0x2116] | reg[0x2117] << 8);
267                 vram[a] = v;
268                 incvram(0, 0);
269                 return;
270         case 0x2119:
271                 a = vrammap(reg[0x2116] | reg[0x2117] << 8);
272                 vram[a|1] = v;
273                 incvram(1, 0);
274                 return;
275         case 0x211b: case 0x211c: case 0x211d:
276         case 0x211e: case 0x211f: case 0x2120:
277                 m7[p - 0x211b] = v << 8 | reg[M7PREV];
278                 if(p >= 0x211f)
279                         if((v & 0x10) != 0)
280                                 m7[p - 0x211b] |= 0xe000;
281                         else
282                                 m7[p - 0x211b] &= 0x1fff;
283                 reg[M7PREV] = v;
284                 calc7();
285                 break;
286         case 0x2121:
287                 reg[CGLH] = 0;
288                 break;
289         case 0x2122:
290                 if(reg[CGLH] == 0)
291                         reg[CGLATCH] = v;
292                 else
293                         cgram[reg[0x2121]++] = swaprb(reg[CGLATCH] | v << 8);
294                 reg[CGLH] ^= 1;
295                 break;
296         case 0x2132:
297                 if((v & 0x80) != 0) subcolor = subcolor & 0x7fe0 | v & 0x1f;
298                 if((v & 0x40) != 0) subcolor = subcolor & 0x7c1f | (v & 0x1f) << 5;
299                 if((v & 0x20) != 0) subcolor = subcolor & 0x03ff | (v & 0x1f) << 10;
300                 return;
301         case 0x213e:
302                 return;
303         case 0x2180:
304                 memwrite(0x7e0000 | reg[0x2181] | reg[0x2182] << 8 | (reg[0x2183] & 1) << 16, v);
305                 incwram();
306                 return;
307         case 0x4016:
308                 if((reg[0x4016] & 1) != 0 && (v & 1) == 0){
309                         if(mouse)
310                                 mouselatch();
311                         else
312                                 keylatch = keys;
313                 }
314                 break;
315         case 0x4200:
316                 if((reg[0x4200] & 0x80) == 0 && (v & 0x80) != 0 && (reg[RDNMI] & 0x80) != 0)
317                         nmi = 2;
318                 if((v & (HCNTIRQ|VCNTIRQ)) == 0)
319                         irq &= ~IRQPPU;
320                 break;
321         case 0x4201:
322                 if((reg[0x4201] & 0x80) == 0 && (v & 0x80) != 0)
323                         hvlatch();
324                 break;
325         case 0x4203:
326                 a = reg[0x4202] * v;
327                 reg[0x4216] = a;
328                 reg[0x4217] = a >> 8;
329                 break;
330         case 0x4206:
331                 if(v == 0){
332                         reg[0x4214] = 0xff;
333                         reg[0x4215] = 0xff;
334                         reg[0x4216] = reg[0x4204];
335                         reg[0x4217] = reg[0x4205];
336                 }else{
337                         a = reg[0x4204] | reg[0x4205] << 8;
338                         reg[0x4214] = a / v;
339                         reg[0x4215] = (a / v) >> 8;
340                         reg[0x4216] = a % v;
341                         reg[0x4217] = (a % v) >> 8;
342                 }
343                 break;
344         case 0x4207:
345                 htime = htime & 0x100 | v;
346                 break;
347         case 0x4208:
348                 htime = htime & 0xff | (v & 1) << 8;
349                 break;
350         case 0x4209:
351                 vtime = vtime & 0x100 | v;
352                 break;
353         case 0x420a:
354                 vtime = vtime & 0xff | (v & 1) << 8;
355                 break;
356         case 0x420b:
357                 dma |= v & ~(reg[0x420c] & ~hdma >> 24);
358                 break;
359         case 0x4210:
360                 return;
361         case 0x4211:
362                 irq &= ~IRQPPU;
363                 return;
364         case 0x4216: case 0x4217:
365         case 0x4218: case 0x4219: case 0x421a: case 0x421b:
366         case 0x421c: case 0x421d: case 0x421e: case 0x421f:
367                 return;
368         }
369         if((p & 0xff40) == 0x2140)
370                 p &= 0xff43;
371         reg[p] = v;
372 }
373
374 u8int
375 memread(u32int a)
376 {
377         u16int al;
378         u8int b;
379
380         al = a;
381         b = (a>>16) & 0x7f;
382         if(al < 0x8000){
383                 if(b < 0x40){
384                         if(hirom && al >= 0x6000 && nsram != 0)
385                                 return sram[(b << 13 | al & 0x1ffff) & (nsram - 1)];
386                         return regread(al);
387                 }
388                 if(!hirom && (b & 0xf8) == 0x70 && nsram != 0){
389                         if(a < 0x800000 || (reg[MEMSEL] & 1) == 0)
390                                 memcyc += 2;
391                         return sram[a & 0x07ffff & (nsram - 1)];
392                 }
393         }
394         if(b >= 0x7e && (a & (1<<23)) == 0){
395                 memcyc += 2;
396                 return mem[a - 0x7e0000];
397         }
398         if(a < 0x800000 || (reg[MEMSEL] & 1) == 0)
399                 memcyc += 2;
400         if(hirom)
401                 return prg[((b & 0x3f) % nprg) << 16 | al];
402         return prg[(b%nprg) << 15 | al & 0x7fff];
403 }
404
405 void
406 memwrite(u32int a, u8int v)
407 {
408         u16int al;
409         u8int b;
410
411         al = a;
412         b = (a>>16) & 0x7f;
413         if(b >= 0x7e && a < 0x800000){
414                 memcyc += 2;
415                 mem[a - 0x7e0000] = v;
416         }
417         if(al < 0x8000){
418                 if(b < 0x40){
419                         if(hirom && al >= 0x6000 && nsram != 0){
420                                 sram[(b << 13 | al & 0x1fff) & (nsram - 1)] = v;
421                                 goto save;
422                         }
423                         regwrite(a, v);
424                         return;
425                 }
426                 if(!hirom && (b & 0xf8) == 0x70 && nsram != 0){
427                         sram[a & 0x07ffff & (nsram - 1)] = v;
428                 save:
429                         if(a < 0x800000 || (reg[MEMSEL] & 1) == 0)
430                                 memcyc += 2;    
431                         if(saveclock == 0)
432                                 saveclock = SAVEFREQ;
433                         return;
434                 }
435         }
436 }
437
438 static u8int nbytes[] = {1, 2, 2, 4, 4, 4, 2, 4};
439 static u8int modes[] = {0x00, 0x04, 0x00, 0x50, 0xe4, 0x44, 0x00, 0x50};
440
441 static int
442 dmavalid(int a, int b)
443 {
444         if(b)
445                 return 1;
446         if((a & 0x400000) != 0)
447                 return 1;
448         switch(a >> 8){
449         case 0x21: return 0;
450         case 0x42: return a != 0x420b && a != 0x420c;
451         case 0x43: return 0;
452         }
453         return 1;
454 }
455
456 int
457 dmastep(void)
458 {
459         int i, j, n, m, cyc;
460         u32int a;
461         u8int b, c, *p;
462         u32int v;
463         
464         cyc = 0;
465         for(i = 0; i < 8; i++)
466                 if((dma & (1<<i)) != 0)
467                         break;
468         if(i == 8)
469                 return 0;
470         p = reg + 0x4300 + (i << 4);
471         c = *p;
472         n = nbytes[c & 7];
473         m = modes[c & 7];
474         for(j = 0; j < n; j++){
475                 a = p[2] | p[3] << 8 | p[4] << 16;
476                 b = p[1] + (m & 3);
477                 if((c & 0x80) != 0){
478                         v = dmavalid(b, 1) ? memread(0x2100 | b) : 0;
479                         if(dmavalid(a, 0))
480                                 memwrite(a, v);
481                 }else{
482                         v = dmavalid(a, 0) ? memread(a) : 0;
483                         if(dmavalid(b, 1))
484                                 memwrite(0x2100 | b, v);
485                 }
486                 cyc++;
487                 m >>= 2;
488                 if((c & 0x08) == 0){
489                         if((c & 0x10) != 0){
490                                 if(--p[2] == 0xff)
491                                         p[3]--;
492                         }else{
493                                 if(++p[2] == 0x00)
494                                         p[3]++;
495                         }
496                 }
497                 if(p[5] == 0){
498                         p[5] = 0xff;
499                         p[6]--;
500                 }else if(--p[5] == 0 && p[6] == 0){
501                         dma &= ~(1<<i);
502                         break;
503                 }
504         }
505         return cyc;
506 }
507
508 static int
509 hdmaload(u8int *p)
510 {
511         u32int a;
512
513         a = p[8] | p[9] << 8 | p[4] << 16;
514         p[10] = dmavalid(a, 0) ? memread(a) : 0;
515         a++;
516         if((p[0] & 0x40) != 0){
517                 p[5] = dmavalid(a, 0) ? memread(a) : 0;
518                 a++;
519                 p[6] = dmavalid(a, 0) ? memread(a) : 0;
520                 a++;
521         }
522         p[8] = a;
523         p[9] = a >> 8;
524         return (p[0] & 0x40) != 0 ? 3 : 1;
525 }
526
527 int
528 hdmastep(void)
529 {
530         int i, j, cyc;
531         u8int *p, *q, n, m, b, v, c;
532         u32int a, br;
533         
534         cyc = 0;
535         if(dma != 0)
536                 dma &= ~((hdma & 0xff00) >> 8 | (hdma & 0xff));
537         if((hdma & 0xff) == 0)
538                 goto init;
539         cyc += 2;
540         for(i = 0; i < 8; i++){
541                 if(((hdma >> i) & (1<<24|1)) != 1)
542                         continue;
543                 p = reg + 0x4300 + (i << 4);
544                 c = p[0];
545                 if((hdma & (1<<(16+i))) != 0){
546                         n = nbytes[c & 7];
547                         m = modes[c & 7];
548                         if((c & 0x40) != 0){
549                                 q = p + 5;
550                                 br = p[7] << 16;
551                         }else{
552                                 q = p + 8;
553                                 br = p[4] << 16;
554                         }
555                         for(j = 0; j < n; j++){
556                                 a = q[0] | q[1] << 8 | br;
557                                 b = p[1] + (m & 3);
558                                 if((c & 0x80) != 0){
559                                         v = dmavalid(b, 1) ? memread(0x2100 | b) : 0;
560                                         if(dmavalid(a, 0))
561                                                 memwrite(a, v);
562                                 }else{
563                                         v = dmavalid(a, 0) ? memread(a) : 0;
564                                         if(dmavalid(b, 1))
565                                                 memwrite(0x2100 | b, v);
566                                 }
567                                 if(++q[0] == 0)
568                                         q[1]++;
569                                 cyc++;
570                                 m >>= 2;
571                         }
572                 }
573                 p[10]--;
574                 hdma = (hdma & ~(1<<(16+i))) | ((p[10] & 0x80) << (9+i));
575                 cyc++;
576                 if((p[10] & 0x7f) == 0){
577                         cyc += hdmaload(p)-1;
578                         if(p[10] == 0)
579                                 hdma |= 1<<(24+i);
580                         hdma |= 1<<(16+i);
581                 }
582         }
583         hdma &= ~0xff;
584         if((hdma & 0xff00) == 0)
585                 return cyc;
586 init:
587         for(i = 0; i < 8; i++){
588                 if((hdma & (1<<(8+i))) == 0)
589                         continue;
590                 p = reg + 0x4300 + (i << 4);
591                 p[8] = p[2];
592                 p[9] = p[3];
593                 cyc += hdmaload(p);
594                 if(p[10] == 0)
595                         hdma |= 1<<(24+i);
596                 hdma |= 1<<(16+i);
597         }
598         cyc += 2;
599         hdma &= ~0xff00;
600         return cyc;
601 }
602
603 void
604 memreset(void)
605 {
606         reg[0x213e] = 1;
607         reg[0x4201] = 0xff;
608         reg[0x4210] = 2;
609 }