SayoriOS 0.3.3

mem.c
1 #include "lib/string.h"
2 #include "mem.h"
3 #include "rom.h"
4 #include "lcd.h"
5 #include "mbc.h"
6 #include "interrupt.h"
7 #include "timer.h"
8 #include "sdl.h"
9 #include "cpu.h"
10
11 static unsigned const char bootrom[256] =
12 {
13 0x31, 0xFE, 0xFF, 0xAF, 0x21, 0xFF, 0x9F, 0x32, 0xCB, 0x7C, 0x20, 0xFB, 0x21, 0x26, 0xFF, 0x0E,
14 0x11, 0x3E, 0x80, 0x32, 0xE2, 0x0C, 0x3E, 0xF3, 0xE2, 0x32, 0x3E, 0x77, 0x77, 0x3E, 0xFC, 0xE0,
15 0x47, 0x11, 0x04, 0x01, 0x21, 0x10, 0x80, 0x1A, 0xCD, 0x95, 0x00, 0xCD, 0x96, 0x00, 0x13, 0x7B,
16 0xFE, 0x34, 0x20, 0xF3, 0x11, 0xD8, 0x00, 0x06, 0x08, 0x1A, 0x13, 0x22, 0x23, 0x05, 0x20, 0xF9,
17 0x3E, 0x19, 0xEA, 0x10, 0x99, 0x21, 0x2F, 0x99, 0x0E, 0x0C, 0x3D, 0x28, 0x08, 0x32, 0x0D, 0x20,
18 0xF9, 0x2E, 0x0F, 0x18, 0xF3, 0x67, 0x3E, 0x64, 0x57, 0xE0, 0x42, 0x3E, 0x91, 0xE0, 0x40, 0x04,
19 0x1E, 0x02, 0x0E, 0x0C, 0xF0, 0x44, 0xFE, 0x90, 0x20, 0xFA, 0x0D, 0x20, 0xF7, 0x1D, 0x20, 0xF2,
20 0x0E, 0x13, 0x24, 0x7C, 0x1E, 0x83, 0xFE, 0x62, 0x28, 0x06, 0x1E, 0xC1, 0xFE, 0x64, 0x20, 0x06,
21 0x7B, 0xE2, 0x0C, 0x3E, 0x87, 0xE2, 0xF0, 0x42, 0x90, 0xE0, 0x42, 0x15, 0x20, 0xD2, 0x05, 0x20,
22 0x4F, 0x16, 0x20, 0x18, 0xCB, 0x4F, 0x06, 0x04, 0xC5, 0xCB, 0x11, 0x17, 0xC1, 0xCB, 0x11, 0x17,
23 0x05, 0x20, 0xF5, 0x22, 0x23, 0x22, 0x23, 0xC9, 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
24 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,
25 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,
26 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E, 0x3C, 0x42, 0xB9, 0xA5, 0xB9, 0xA5, 0x42, 0x3C,
27 0x21, 0x04, 0x01, 0x11, 0xA8, 0x00, 0x1A, 0x13, 0xBE, 0x20, 0xFE, 0x23, 0x7D, 0xFE, 0x34, 0x20,
28 0xF5, 0x06, 0x19, 0x78, 0x86, 0x23, 0x05, 0x20, 0xFB, 0x86, 0x20, 0xFE, 0x3E, 0x01, 0xE0, 0x50
29 };
30
31 #ifdef DEBUG
32 static int bootrom_enabled = 0;
33 #else
34 static int bootrom_enabled = 1;
35 #endif
36
37 static unsigned char *mem;
38
39 static unsigned int DMA_pending;
40 static unsigned short DMA_src;
41 static int DMA_copied;
42
43 static int joypad_select_buttons, joypad_select_directions;
44
45 void mem_bank_switch(unsigned int n)
46 {
47 unsigned char *b = rom_getbytes();
48
49 if(!rom_bank_valid(n))
50 {
51 printf("Bank switch to illegal bank %d, ignoring.\n", n);
52 return;
53 }
54
55 memcpy(&mem[0x4000], &b[n * 0x4000], 0x4000);
56 }
57
58 /* LCD's access to VRAM */
59 unsigned char mem_get_raw(unsigned short p)
60 {
61 return mem[p];
62 }
63
64 unsigned char mem_get_byte(unsigned short i)
65 {
66 unsigned char mask = 0;
67
68 if(i < 0x100 && bootrom_enabled)
69 return bootrom[i];
70
71 if(DMA_pending && cpu_get_cycles() >= DMA_pending)
72 {
73 unsigned long elapsed;
74
75 if(!DMA_copied)
76 {
77 memcpy(&mem[0xFE00], &mem[DMA_src], 0xA0);
78 DMA_copied = 1;
79 }
80
81 elapsed = cpu_get_cycles() - DMA_pending;
82
83 if(elapsed >= 160)
84 DMA_pending = 0;
85 else if(i < 0xFF00)
86 {
87 /* Reading from OAM during DMA always gives 0xFF */
88 if(i >= 0xFE00 && i <= 0xFEA0)
89 return 0xFF;
90
91 /* !A ^ B checks if A and B are both 0 or both 1 */
92 if(!(((DMA_src >> 13) == 4) ^ ((i >> 13) == 4)))
93 return mem[0xFE00+elapsed];
94 }
95 }
96
97 switch(i)
98 {
99 case 0xFF00: /* Joypad */
100 if(!joypad_select_buttons)
101 mask = sdl_get_buttons();
102 if(!joypad_select_directions)
103 mask = sdl_get_directions();
104 return 0xC0 | (0xF^mask) | (joypad_select_buttons | joypad_select_directions);
105 break;
106 case 0xFF04:
107 return timer_get_div();
108 break;
109 case 0xFF05:
110 return timer_get_counter();
111 break;
112 case 0xFF06:
113 return timer_get_modulo();
114 break;
115 case 0xFF07:
116 return timer_get_tac();
117 break;
118 case 0xFF0F:
119 return interrupt_get_IF();
120 break;
121 case 0xFF41:
122 return lcd_get_stat();
123 break;
124 case 0xFF44:
125 return lcd_get_line();
126 break;
127 case 0xFF45:
128 return lcd_get_ly_compare();
129 break;
130 case 0xFF4D: /* GBC speed switch */
131 return 0xFF;
132 break;
133 case 0xFFFF:
134 return interrupt_get_mask();
135 break;
136 }
137
138 if(i >= 0xE000 && i <= 0xFDFF)
139 i -= 0x2000;
140
141 if(i >= 0x8000 && i <= 0x9FFF && (lcd_get_stat() & 3) == 3)
142 return 0xFF;
143
144 return mem[i];
145 }
146
147 unsigned short mem_get_word(unsigned short i)
148 {
149 return mem_get_byte(i) | (mem_get_byte(i+1)<<8);
150 }
151
152 void mem_write_byte(unsigned short d, unsigned char i)
153 {
154 unsigned int filtered = 0;
155
156 if(DMA_pending && DMA_pending <= cpu_get_cycles())
157 {
158 long elapsed;
159
160 if(!DMA_copied)
161 {
162 memcpy(&mem[0xFE00], &mem[DMA_src], 0xA0);
163 DMA_copied = 1;
164 }
165
166 elapsed = cpu_get_cycles() - DMA_pending;
167
168 if(elapsed >= 160)
169 DMA_pending = 0;
170 else if(d >= 0xFE00 && d <= 0xFEA0)
171 return;
172
173 else if(!(((DMA_src >> 13) == 4) ^ ((d >> 13) == 4)))
174 return;
175 }
176
177 switch(rom_get_mapper())
178 {
179 case NROM:
180 if(d < 0x8000)
181 filtered = 1;
182 break;
183 case MBC2:
184 case MBC3:
185 case MBC5:
186 filtered = MBC3_write_byte(d, i);
187 break;
188 case MBC1:
189 filtered = MBC1_write_byte(d, i);
190 break;
191 }
192
193 if(filtered)
194 return;
195
196 switch(d)
197 {
198 case 0xFF00: /* Joypad */
199 joypad_select_buttons = i&0x20;
200 joypad_select_directions = i&0x10;
201 break;
202 case 0xFF01: /* Link port data */
203 break;
204 case 0xFF04:
205 timer_set_div(i);
206 break;
207 case 0xFF05:
208 timer_set_counter(i);
209 break;
210 case 0xFF06:
211 timer_set_modulo(i);
212 break;
213 case 0xFF07:
214 timer_set_tac(i);
215 break;
216 case 0xFF0F:
217 interrupt_set_IF(i);
218 break;
219 case 0xFF40:
220 lcd_write_control(i);
221 break;
222 case 0xFF41:
223 lcd_write_stat(i);
224 break;
225 case 0xFF42:
226 lcd_write_scroll_y(i);
227 break;
228 case 0xFF43:
229 lcd_write_scroll_x(i);
230 break;
231 case 0xFF45:
232 lcd_set_ly_compare(i);
233 break;
234 case 0xFF46: /* OAM DMA */
235 /* This is the dead cycle where OAM DMA is busy, can't restart */
236 if(DMA_pending == cpu_get_cycles())
237 break;
238
239 /* Start or restart OAM DMA */
240 DMA_pending = cpu_get_cycles()+2;
241 DMA_src = i * 0x100;
242 DMA_copied = 0;
243 break;
244 case 0xFF47:
245 lcd_write_bg_palette(i);
246 break;
247 case 0xFF48:
248 lcd_write_spr_palette1(i);
249 break;
250 case 0xFF49:
251 lcd_write_spr_palette2(i);
252 break;
253 case 0xFF4A:
254 lcd_set_window_y(i);
255 break;
256 case 0xFF4B:
257 lcd_set_window_x(i);
258 break;
259 case 0xFF50:
260 bootrom_enabled = 0;
261 break;
262 case 0xFFFF:
263 interrupt_set_mask(i);
264 return;
265 break;
266 }
267
268 #ifndef DEBUG
269 if(d > 0x8000 && d < 0x9FFF && (lcd_get_stat() & 3) == 3)
270 return;
271 #endif
272
273 /* RAM mirror */
274 if(d >= 0xE000 && d <= 0xFDFF)
275 d -= 0x2000;
276
277 mem[d] = i;
278 }
279
280 void mem_write_word(unsigned short d, unsigned short i)
281 {
282 mem_write_byte(d, i&0xFF);
283 mem_write_byte(d+1, i>>8);
284 }
285
286 void mem_init(void)
287 {
288 unsigned char *bytes = rom_getbytes();
289
290 mem = calloc(1, 0x10000);
291
292 memcpy(&mem[0x0000], &bytes[0x0000], 0x4000);
293 memcpy(&mem[0x4000], &bytes[0x4000], 0x4000);
294
295 mem[0xFF02] = 0x7E;
296 mem[0xFF10] = 0x80;
297 mem[0xFF11] = 0xBF;
298 mem[0xFF12] = 0xF3;
299 mem[0xFF14] = 0xBF;
300 mem[0xFF16] = 0x3F;
301 mem[0xFF19] = 0xBF;
302 mem[0xFF1A] = 0x7F;
303 mem[0xFF1B] = 0xFF;
304 mem[0xFF1C] = 0x9F;
305 mem[0xFF1E] = 0xBF;
306 mem[0xFF20] = 0xFF;
307 mem[0xFF23] = 0xBF;
308 mem[0xFF24] = 0x77;
309 mem[0xFF25] = 0xF3;
310 mem[0xFF26] = 0xF1;
311 mem[0xFF40] = 0x91;
312 mem[0xFF47] = 0xFC;
313 mem[0xFF48] = 0xFF;
314 mem[0xFF49] = 0xFF;
315 }
memcpy
void * memcpy(void *restrict destination, const void *restrict source, size_t n)
Копирование непересекающихся массивов используя SSE.
Definition: string.c:173