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