]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/gb/mem.c
games/gb: better audio, scaling, fixed serious MMC5 bug
[plan9front.git] / sys / src / games / gb / mem.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <draw.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 uchar mem[65536];
9 int rombank, rambank, ramen, battery, ramrom;
10 extern int savefd;
11
12 u8int
13 memread(u16int p)
14 {
15         extern int keys;
16
17         if((p & 0xFF80) == 0xFF00)
18                 switch(p){
19                 case 0xFF00:
20                         if((mem[0xFF00] & (1<<5)) == 0)
21                                 return (mem[0xFF00] & 0xF0) | ~(keys >> 4);
22                         if((mem[0xFF00] & (1<<6)) == 0)
23                                 return (mem[0xFF00] & 0xF0) | ~(keys & 0x0F);
24                         return (mem[0xFF00] & 0xF0) | 0x0F;
25                 }
26         if(!ramen && ((p & 0xE000) == 0xA000))
27                 return 0xFF;
28         return mem[p];
29 }
30
31 static void
32 ramswitch(int state, int bank)
33 {
34         if(ramen){
35                 memcpy(ram + 8192 * rambank, mem + 0xA000, 8192);
36                 if(battery && savefd > 0){
37                         seek(savefd, rambank * 8192, 0);
38                         write(savefd, ram + 8192 * rambank, 8192);
39                 }
40                 ramen = 0;
41         }
42         rambank = bank;
43         if(state){
44                 if(bank >= rambanks)
45                         sysfatal("invalid RAM bank %d selected (pc = %.4x)", bank, curpc);
46                 memcpy(mem + 0xA000, ram + 8192 * rambank, 8192);
47                 ramen = 1;
48         }
49 }
50
51 void
52 flushram(void)
53 {
54         if(ramen)
55                 ramswitch(ramen, rambank);
56 }
57
58 static void
59 romswitch(int bank)
60 {
61         if(bank >= rombanks)
62                 sysfatal("invalid ROM bank %d selected (pc = %.4x)", bank, curpc);
63         rombank = bank;
64         memcpy(mem + 0x4000, cart + 0x4000 * bank, 0x4000);
65 }
66
67 void
68 memwrite(u16int p, u8int v)
69 {
70         if(p < 0x8000){
71                 switch(mbc){
72                 case 0:
73                         return;
74                 case 1:
75                 case 2:
76                         switch(p >> 13){
77                         case 0:
78                                 if((v & 0x0F) == 0x0A)
79                                         ramswitch(1, rambank);
80                                 else
81                                         ramswitch(0, rambank);
82                                 return;
83                         case 1:
84                                 v &= 0x1F;
85                                 if(v == 0)
86                                         v++;
87                                 romswitch((rombank & 0xE0) | v);
88                                 return;
89                         case 2:
90                                 if(ramrom)
91                                         ramswitch(ramen, v & 3);
92                                 else
93                                         romswitch(((v & 3) << 5) | (rombank & 0x1F));
94                                 return;
95                         case 3:
96                                 ramrom = v;
97                                 return;
98                         }
99                         return;
100                 case 3:
101                         switch(p >> 13){
102                         case 0:
103                                 if((v & 0x0F) == 0x0A)
104                                         ramswitch(1, rambank);
105                                 else
106                                         ramswitch(0, rambank);
107                                 return;
108                         case 1:
109                                 v &= 0x7F;
110                                 if(v == 0)
111                                         v++;
112                                 romswitch(v);
113                                 return;
114                         case 2:
115                                 if(v < 4)
116                                         ramswitch(ramen, v);
117                                 return;
118                         }
119                         return;
120                 case 5:
121                         switch(p >> 12){
122                         case 0: case 1:
123                                 if((v & 0x0F) == 0x0A)
124                                         ramswitch(1, rambank);
125                                 else
126                                         ramswitch(0, rambank);
127                                 return;
128                         case 2:
129                                 romswitch((rombank & 0x100) | v);
130                                 return;
131                         case 3:
132                                 romswitch((((int)v & 1) << 8) | (rombank & 0xFF));
133                                 return;
134                         case 4:
135                                 ramswitch(ramen, v & 15);
136                                 return;
137                         
138                         }
139                         return;
140                 default:
141                         sysfatal("mbc %d unimplemented", mbc);
142                 }
143         }
144         if((p & 0xFF80) == 0xFF00)
145                 switch(p){
146                 case 0xFF04:
147                         v = 0;
148                         break;
149                 case 0xFF07:
150                         timer = (v & 4) != 0;
151                         switch(v & 3){
152                         case 0:
153                                 timerfreq = 1024;
154                                 break;
155                         case 1:
156                                 timerfreq = 16;
157                                 break;
158                         case 2:
159                                 timerfreq = 64;
160                                 break;
161                         default:
162                                 timerfreq = 256;
163                         }
164                         break;
165                 case 0xFF26:
166                         v = (v & 0xF0) | (mem[p] & 0x0F);
167                 case 0xFF41:
168                         v &= ~7;
169                         v |= mem[p] & 7;
170                         break;
171                 case 0xFF46:
172                         memcpy(mem + 0xFE00, mem + (((int)v) << 8), 0xA0);
173                         break;
174                 }
175         mem[p] = v;
176 }