A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 569 lines 13 kB view raw
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}