A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1
2
3#include "rockmacros.h"
4
5#include "defs.h"
6#include "hw.h"
7#include "regs.h"
8#include "mem.h"
9#include "rtc-gb.h"
10#include "lcd-gb.h"
11#include "lcdc.h"
12#include "sound.h"
13
14struct mbc mbc IBSS_ATTR;
15struct rom rom IBSS_ATTR;
16struct ram ram;
17
18
19/*
20 * In order to make reads and writes efficient, we keep tables
21 * (indexed by the high nibble of the address) specifying which
22 * regions can be read/written without a function call. For such
23 * ranges, the pointer in the map table points to the base of the
24 * region in host system memory. For ranges that require special
25 * processing, the pointer is NULL.
26 *
27 * mem_updatemap is called whenever bank changes or other operations
28 * make the old maps potentially invalid.
29 */
30
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Warray-bounds"
33void mem_updatemap(void)
34{
35 int n;
36 static byte **map;
37
38 map = mbc.rmap;
39 map[0x0] = rom.bank[0];
40 map[0x1] = rom.bank[0];
41 map[0x2] = rom.bank[0];
42 map[0x3] = rom.bank[0];
43 if (mbc.rombank < mbc.romsize)
44 {
45 map[0x4] = rom.bank[mbc.rombank] - 0x4000;
46 map[0x5] = rom.bank[mbc.rombank] - 0x4000;
47 map[0x6] = rom.bank[mbc.rombank] - 0x4000;
48 map[0x7] = rom.bank[mbc.rombank] - 0x4000;
49 }
50 else map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
51 if (0 && (R_STAT & 0x03) == 0x03)
52 {
53 map[0x8] = NULL;
54 map[0x9] = NULL;
55 }
56 else
57 {
58 map[0x8] = lcd.vbank[R_VBK & 1] - 0x8000;
59 map[0x9] = lcd.vbank[R_VBK & 1] - 0x8000;
60 }
61
62 if (mbc.enableram && !(rtc.sel&8))
63 {
64 map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
65 map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
66 }
67 else map[0xA] = map[0xB] = NULL;
68 map[0xC] = ram.ibank[0] - 0xC000; // XXX
69 n = R_SVBK & 0x07;
70 map[0xD] = ram.ibank[n?n:1] - 0xD000;
71 map[0xE] = ram.ibank[0] - 0xE000; // XXX
72 map[0xF] = NULL;
73
74 map = mbc.wmap;
75 map[0x0] = map[0x1] = map[0x2] = map[0x3] = NULL;
76 map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
77 map[0x8] = map[0x9] = NULL;
78 if (mbc.enableram && !(rtc.sel&8))
79 {
80 map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
81 map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
82 }
83 else map[0xA] = map[0xB] = NULL;
84 map[0xC] = ram.ibank[0] - 0xC000; // XXX
85 n = R_SVBK & 0x07;
86 map[0xD] = ram.ibank[n?n:1] - 0xD000;
87 map[0xE] = ram.ibank[0] - 0xE000; // XXX
88 map[0xF] = NULL;
89}
90#pragma GCC diagnostic pop
91
92/*
93 * ioreg_write handles output to io registers in the FF00-FF7F,FFFF
94 * range. It takes the register number (low byte of the address) and a
95 * byte value to be written.
96 */
97
98static void ioreg_write(byte r, byte b) ICODE_ATTR;
99static void ioreg_write(byte r, byte b)
100{
101 if (!hw.cgb)
102 {
103
104 switch (r)
105 {
106 case RI_VBK:
107 case RI_BCPS:
108 case RI_OCPS:
109 case RI_BCPD:
110 case RI_OCPD:
111 case RI_SVBK:
112 case RI_KEY1:
113 case RI_HDMA1:
114 case RI_HDMA2:
115 case RI_HDMA3:
116 case RI_HDMA4:
117 case RI_HDMA5:
118 return;
119 }
120 }
121 switch(r)
122 {
123 case RI_TIMA:
124 case RI_TMA:
125 case RI_TAC:
126 case RI_SCY:
127 case RI_SCX:
128 case RI_WY:
129 case RI_WX:
130 REG(r) = b;
131 break;
132 case RI_BGP:
133 if (R_BGP == b) break;
134 pal_write_dmg(0, 0, b);
135 pal_write_dmg(8, 1, b);
136 R_BGP = b;
137 break;
138 case RI_OBP0:
139 if (R_OBP0 == b) break;
140 pal_write_dmg(64, 2, b);
141 R_OBP0 = b;
142 break;
143 case RI_OBP1:
144 if (R_OBP1 == b) break;
145 pal_write_dmg(72, 3, b);
146 R_OBP1 = b;
147 break;
148 case RI_IF:
149 case RI_IE:
150 REG(r) = b & 0x1F;
151 break;
152 case RI_P1:
153 REG(r) = b;
154 pad_refresh();
155 break;
156 case RI_SC:
157 /* FIXME - this is a hack for stupid roms that probe serial */
158 if ((b & 0x81) == 0x81)
159 {
160 R_SB = 0xff;
161 hw_interrupt(IF_SERIAL, IF_SERIAL);
162 hw_interrupt(0, IF_SERIAL);
163 }
164 R_SC = b; /* & 0x7f; */
165 break;
166 case RI_DIV:
167 REG(r) = 0;
168 break;
169 case RI_LCDC:
170 lcdc_change(b);
171 break;
172 case RI_STAT:
173 REG(r) = (REG(r) & 0x07) | (b & 0x78);
174 stat_trigger();
175 break;
176 case RI_LYC:
177 REG(r) = b;
178 stat_trigger();
179 break;
180 case RI_VBK:
181 REG(r) = b | 0xFE;
182 mem_updatemap();
183 break;
184 case RI_BCPS:
185 R_BCPS = b & 0xBF;
186 R_BCPD = lcd.pal[b & 0x3F];
187 break;
188 case RI_OCPS:
189 R_OCPS = b & 0xBF;
190 R_OCPD = lcd.pal[64 + (b & 0x3F)];
191 break;
192 case RI_BCPD:
193 R_BCPD = b;
194 pal_write(R_BCPS & 0x3F, b);
195 if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF;
196 break;
197 case RI_OCPD:
198 R_OCPD = b;
199 pal_write(64 + (R_OCPS & 0x3F), b);
200 if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF;
201 break;
202 case RI_SVBK:
203 REG(r) = b & 0x07;
204 mem_updatemap();
205 break;
206 case RI_DMA:
207 hw_dma(b);
208 break;
209 case RI_KEY1:
210 REG(r) = (REG(r) & 0x80) | (b & 0x01);
211 break;
212 case RI_HDMA1:
213 REG(r) = b;
214 break;
215 case RI_HDMA2:
216 REG(r) = b & 0xF0;
217 break;
218 case RI_HDMA3:
219 REG(r) = b & 0x1F;
220 break;
221 case RI_HDMA4:
222 REG(r) = b & 0xF0;
223 break;
224 case RI_HDMA5:
225 hw_hdma_cmd(b);
226 break;
227 }
228}
229
230
231static byte ioreg_read(byte r)
232{
233 switch(r)
234 {
235 case RI_SC:
236 r = R_SC;
237 R_SC &= 0x7f;
238 return r;
239 case RI_P1:
240 case RI_SB:
241 case RI_DIV:
242 case RI_TIMA:
243 case RI_TMA:
244 case RI_TAC:
245 case RI_LCDC:
246 case RI_STAT:
247 case RI_SCY:
248 case RI_SCX:
249 case RI_LY:
250 case RI_LYC:
251 case RI_BGP:
252 case RI_OBP0:
253 case RI_OBP1:
254 case RI_WY:
255 case RI_WX:
256 case RI_IE:
257 case RI_IF:
258 return REG(r);
259 case RI_VBK:
260 case RI_BCPS:
261 case RI_OCPS:
262 case RI_BCPD:
263 case RI_OCPD:
264 case RI_SVBK:
265 case RI_KEY1:
266 case RI_HDMA1:
267 case RI_HDMA2:
268 case RI_HDMA3:
269 case RI_HDMA4:
270 case RI_HDMA5:
271 if (hw.cgb) return REG(r);
272 /* Intentional fallthrough */
273 default:
274 return 0xff;
275 }
276}
277
278
279
280/*
281 * Memory bank controllers typically intercept write attempts to
282 * 0000-7FFF, using the address and byte written as instructions to
283 * change rom or sram banks, control special hardware, etc.
284 *
285 * mbc_write takes an address (which should be in the proper range)
286 * and a byte value written to the address.
287 */
288
289static void mbc_write(int a, byte b) ICODE_ATTR;
290static void mbc_write(int a, byte b)
291{
292 byte ha = (a>>12);
293
294 /* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */
295 switch (mbc.type)
296 {
297 case MBC_MBC1:
298 switch (ha & 0xE)
299 {
300 case 0x0:
301 mbc.enableram = ((b & 0x0F) == 0x0A);
302 break;
303 case 0x2:
304 if ((b & 0x1F) == 0) b = 0x01;
305 mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
306 break;
307 case 0x4:
308 if (mbc.model)
309 {
310 mbc.rambank = b & 0x03;
311 break;
312 }
313 mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
314 break;
315 case 0x6:
316 mbc.model = b & 0x1;
317 break;
318 }
319 break;
320 case MBC_MBC2: /* is this at all right? */
321 if ((a & 0x0100) == 0x0000)
322 {
323 mbc.enableram = ((b & 0x0F) == 0x0A);
324 break;
325 }
326 if ((a & 0xE100) == 0x2100)
327 {
328 mbc.rombank = b & 0x0F;
329 break;
330 }
331 break;
332 case MBC_MBC3:
333 switch (ha & 0xE)
334 {
335 case 0x0:
336 mbc.enableram = ((b & 0x0F) == 0x0A);
337 break;
338 case 0x2:
339 if ((b & 0x7F) == 0) b = 0x01;
340 mbc.rombank = b & 0x7F;
341 break;
342 case 0x4:
343 rtc.sel = b & 0x0f;
344 mbc.rambank = b & 0x03;
345 break;
346 case 0x6:
347 rtc_latch(b);
348 break;
349 }
350 break;
351 case MBC_RUMBLE:
352 switch (ha & 0xF)
353 {
354 case 0x4:
355 case 0x5:
356 /* FIXME - save high bit as rumble state */
357 /* mask off high bit */
358 b &= 0x7;
359 break;
360 }
361 /* fall thru */
362 case MBC_MBC5:
363 switch (ha & 0xF)
364 {
365 case 0x0:
366 case 0x1:
367 mbc.enableram = ((b & 0x0F) == 0x0A);
368 break;
369 case 0x2:
370 if ((b & 0xFF) == 0) b = 0x01;
371 mbc.rombank = (mbc.rombank & 0x100) | (b & 0xFF);
372 break;
373 case 0x3:
374 mbc.rombank = (mbc.rombank & 0xFF) | ((int)(b&1)<<8);
375 break;
376 case 0x4:
377 case 0x5:
378 mbc.rambank = b & 0x0f;
379 break;
380 }
381 break;
382 case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */
383 switch (ha & 0xE)
384 {
385 case 0x0:
386 mbc.enableram = ((b & 0x0F) == 0x0A);
387 break;
388 case 0x2:
389 if ((b & 0x1F) == 0) b = 0x01;
390 mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
391 break;
392 case 0x4:
393 if (mbc.model)
394 {
395 mbc.rambank = b & 0x03;
396 break;
397 }
398 mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
399 break;
400 case 0x6:
401 mbc.model = b & 0x1;
402 break;
403 }
404 break;
405 case MBC_HUC3: /* FIXME - this is all guesswork -- is it right??? */
406 switch (ha & 0xE)
407 {
408 case 0x0:
409 mbc.enableram = ((b & 0x0F) == 0x0A);
410 break;
411 case 0x2:
412 if (!b) b = 1;
413 mbc.rombank = b;
414 break;
415 case 0x4:
416 if (mbc.model)
417 {
418 mbc.rambank = b & 0x03;
419 break;
420 }
421 break;
422 case 0x6:
423 mbc.model = b & 1;
424 break;
425 }
426 break;
427 }
428 mbc.rombank &= (mbc.romsize - 1);
429 mbc.rambank &= (mbc.ramsize - 1);
430 mem_updatemap();
431}
432
433
434/*
435 * mem_write is the basic write function. Although it should only be
436 * called when the write map contains a NULL for the requested address
437 * region, it accepts writes to any address.
438 */
439
440void mem_write(int a, byte b)
441{
442 int n;
443 byte ha = (a>>12) & 0xE;
444
445 /* printf("write to 0x%04X: 0x%02X\n", a, b); */
446 switch (ha)
447 {
448 case 0x0:
449 case 0x2:
450 case 0x4:
451 case 0x6:
452 mbc_write(a, b);
453 break;
454 case 0x8:
455 /* if ((R_STAT & 0x03) == 0x03) break; */
456 vram_write(a & 0x1FFF, b);
457 break;
458 case 0xA:
459 if (!mbc.enableram) break;
460 if (rtc.sel&8)
461 {
462 rtc_write(b);
463 break;
464 }
465 ram.sbank[mbc.rambank][a & 0x1FFF] = b;
466 break;
467 case 0xC:
468 if ((a & 0xF000) == 0xC000)
469 {
470 ram.ibank[0][a & 0x0FFF] = b;
471 break;
472 }
473 n = R_SVBK & 0x07;
474 ram.ibank[n?n:1][a & 0x0FFF] = b;
475 break;
476 case 0xE:
477 if (a < 0xFE00)
478 {
479 mem_write(a & 0xDFFF, b);
480 break;
481 }
482 if ((a & 0xFF00) == 0xFE00)
483 {
484 /* if (R_STAT & 0x02) break; */
485 if (a < 0xFEA0) lcd.oam.mem[a & 0xFF] = b;
486 break;
487 }
488 /* return writehi(a & 0xFF, b); */
489 if (a >= 0xFF10 && a <= 0xFF3F)
490 {
491 if(options.sound)
492 sound_write(a & 0xFF, b);
493 break;
494 }
495 if ((a & 0xFF80) == 0xFF80 && a != 0xFFFF)
496 {
497 ram.hi[a & 0xFF] = b;
498 break;
499 }
500 ioreg_write(a & 0xFF, b);
501 }
502}
503
504
505/*
506 * mem_read is the basic read function...not useful for much anymore
507 * with the read map, but it's still necessary for the final messy
508 * region.
509 */
510
511byte mem_read(int a)
512{
513 int n;
514 byte ha = (a>>12) & 0xE;
515
516 /* printf("read %04x\n", a); */
517 switch (ha)
518 {
519 case 0x0:
520 case 0x2:
521 return rom.bank[0][a];
522 case 0x4:
523 case 0x6:
524 return rom.bank[mbc.rombank][a & 0x3FFF];
525 case 0x8:
526 /* if ((R_STAT & 0x03) == 0x03) return 0xFF; */
527 return lcd.vbank[R_VBK&1][a & 0x1FFF];
528 case 0xA:
529 if (!mbc.enableram)
530 return 0xFF;
531 if (rtc.sel&8)
532 return rtc.regs[rtc.sel&7];
533 return ram.sbank[mbc.rambank][a & 0x1FFF];
534 case 0xC:
535 if ((a & 0xF000) == 0xC000)
536 return ram.ibank[0][a & 0x0FFF];
537 n = R_SVBK & 0x07;
538 return ram.ibank[n?n:1][a & 0x0FFF];
539 case 0xE:
540 if (a < 0xFE00) return mem_read(a & 0xDFFF);
541 if ((a & 0xFF00) == 0xFE00)
542 {
543 /* if (R_STAT & 0x02) return 0xFF; */
544 if (a < 0xFEA0) return lcd.oam.mem[a & 0xFF];
545 return 0xFF;
546 }
547 /* return readhi(a & 0xFF); */
548 if (a == 0xFFFF) return REG(0xFF);
549 if (a >= 0xFF10 && a <= 0xFF3F)
550 {
551 if(options.sound)
552 return sound_read(a & 0xFF);
553 else
554 return 1;
555 }
556 if ((a & 0xFF80) == 0xFF80)
557 return ram.hi[a & 0xFF];
558 return ioreg_read(a & 0xFF);
559 }
560 return 0xff; /* not reached */
561}
562
563void mbc_reset(void)
564{
565 mbc.rombank = 1;
566 mbc.rambank = 0;
567 mbc.enableram = 0;
568 mem_updatemap();
569}