fuzev2: prevent button light flickering when accessing µSD
[kugel-rb.git] / apps / plugins / rockboy / mem.c
blobe00dadfa3c0ceb11423bb81c5012f328364aa081
3 #include "rockmacros.h"
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"
14 struct mbc mbc IBSS_ATTR;
15 struct rom rom IBSS_ATTR;
16 struct ram ram;
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.
27 * mem_updatemap is called whenever bank changes or other operations
28 * make the old maps potentially invalid.
31 void mem_updatemap(void)
33 int n;
34 static byte **map;
36 map = mbc.rmap;
37 map[0x0] = rom.bank[0];
38 map[0x1] = rom.bank[0];
39 map[0x2] = rom.bank[0];
40 map[0x3] = rom.bank[0];
41 if (mbc.rombank < mbc.romsize)
43 map[0x4] = rom.bank[mbc.rombank] - 0x4000;
44 map[0x5] = rom.bank[mbc.rombank] - 0x4000;
45 map[0x6] = rom.bank[mbc.rombank] - 0x4000;
46 map[0x7] = rom.bank[mbc.rombank] - 0x4000;
48 else map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
49 if (R_VBK & 1)
51 map[0x8] = lcd.vbank[1] - 0x8000;
52 map[0x9] = lcd.vbank[1] - 0x8000;
54 else
56 map[0x8] = lcd.vbank[0]/*[R_VBK & 1]*/ - 0x8000;
57 map[0x9] = lcd.vbank[0]/*[R_VBK & 1]*/ - 0x8000;
60 if (mbc.enableram && !(rtc.sel&8))
62 map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
63 map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
65 else map[0xA] = map[0xB] = NULL;
66 map[0xC] = ram.ibank[0] - 0xC000;
67 n = R_SVBK & 0x07;
68 map[0xD] = ram.ibank[n?n:1] - 0xD000;
69 map[0xE] = ram.ibank[0] - 0xE000;
70 map[0xF] = NULL;
72 map = mbc.wmap;
73 map[0x0] = map[0x1] = map[0x2] = map[0x3] = NULL;
74 map[0x4] = map[0x5] = map[0x6] = map[0x7] = NULL;
75 map[0x8] = map[0x9] = NULL;
76 if (mbc.enableram && !(rtc.sel&8))
78 map[0xA] = ram.sbank[mbc.rambank] - 0xA000;
79 map[0xB] = ram.sbank[mbc.rambank] - 0xA000;
81 else map[0xA] = map[0xB] = NULL;
82 map[0xC] = ram.ibank[0] - 0xC000;
83 n = R_SVBK & 0x07;
84 map[0xD] = ram.ibank[n?n:1] - 0xD000;
85 map[0xE] = ram.ibank[0] - 0xE000;
86 map[0xF] = NULL;
91 * ioreg_write handles output to io registers in the FF00-FF7F,FFFF
92 * range. It takes the register number (low byte of the address) and a
93 * byte value to be written.
96 static void ioreg_write(byte r, byte b) ICODE_ATTR;
97 static void ioreg_write(byte r, byte b)
99 if (!hw.cgb)
102 switch (r)
104 case RI_VBK:
105 case RI_BCPS:
106 case RI_OCPS:
107 case RI_BCPD:
108 case RI_OCPD:
109 case RI_SVBK:
110 case RI_KEY1:
111 case RI_HDMA1:
112 case RI_HDMA2:
113 case RI_HDMA3:
114 case RI_HDMA4:
115 case RI_HDMA5:
116 return;
119 switch(r)
121 case RI_TIMA:
122 case RI_TMA:
123 case RI_TAC:
124 case RI_SCY:
125 case RI_SCX:
126 case RI_WY:
127 case RI_WX:
128 REG(r) = b;
129 break;
130 case RI_BGP:
131 if (R_BGP == b) break;
132 pal_write_dmg(0, 0, b);
133 pal_write_dmg(8, 1, b);
134 R_BGP = b;
135 break;
136 case RI_OBP0:
137 if (R_OBP0 == b) break;
138 pal_write_dmg(64, 2, b);
139 R_OBP0 = b;
140 break;
141 case RI_OBP1:
142 if (R_OBP1 == b) break;
143 pal_write_dmg(72, 3, b);
144 R_OBP1 = b;
145 break;
146 case RI_IF:
147 case RI_IE:
148 REG(r) = b & 0x1F;
149 break;
150 case RI_P1:
151 REG(r) = b;
152 pad_refresh();
153 break;
154 case RI_SC:
155 /* FIXME - this is a hack for stupid roms that probe serial */
156 if ((b & 0x81) == 0x81)
158 R_SB = 0xff;
159 hw_interrupt(IF_SERIAL, IF_SERIAL);
160 hw_interrupt(0, IF_SERIAL);
162 R_SC = b; /* & 0x7f; */
163 break;
164 case RI_DIV:
165 REG(r) = 0;
166 break;
167 case RI_LCDC:
168 lcdc_change(b);
169 break;
170 case RI_STAT:
171 REG(r) = (REG(r) & 0x07) | (b & 0x78);
172 stat_trigger();
173 break;
174 case RI_LYC:
175 REG(r) = b;
176 stat_trigger();
177 break;
178 case RI_VBK:
179 REG(r) = b | 0xFE;
180 mem_updatemap();
181 break;
182 case RI_BCPS:
183 R_BCPS = b & 0xBF;
184 R_BCPD = lcd.pal[b & 0x3F];
185 break;
186 case RI_OCPS:
187 R_OCPS = b & 0xBF;
188 R_OCPD = lcd.pal[64 + (b & 0x3F)];
189 break;
190 case RI_BCPD:
191 R_BCPD = b;
192 pal_write(R_BCPS & 0x3F, b);
193 if (R_BCPS & 0x80) R_BCPS = (R_BCPS+1) & 0xBF;
194 break;
195 case RI_OCPD:
196 R_OCPD = b;
197 pal_write(64 + (R_OCPS & 0x3F), b);
198 if (R_OCPS & 0x80) R_OCPS = (R_OCPS+1) & 0xBF;
199 break;
200 case RI_SVBK:
201 REG(r) = b & 0x07;
202 mem_updatemap();
203 break;
204 case RI_DMA:
205 hw_dma(b);
206 break;
207 case RI_KEY1:
208 REG(r) = (REG(r) & 0x80) | (b & 0x01);
209 break;
210 case RI_HDMA1:
211 REG(r) = b;
212 break;
213 case RI_HDMA2:
214 REG(r) = b & 0xF0;
215 break;
216 case RI_HDMA3:
217 REG(r) = b & 0x1F;
218 break;
219 case RI_HDMA4:
220 REG(r) = b & 0xF0;
221 break;
222 case RI_HDMA5:
223 hw_hdma_cmd(b);
224 break;
229 static byte ioreg_read(byte r)
231 switch(r)
233 case RI_SC:
234 r = R_SC;
235 R_SC &= 0x7f;
236 return r;
237 case RI_P1:
238 case RI_SB:
239 case RI_DIV:
240 case RI_TIMA:
241 case RI_TMA:
242 case RI_TAC:
243 case RI_LCDC:
244 case RI_STAT:
245 case RI_SCY:
246 case RI_SCX:
247 case RI_LY:
248 case RI_LYC:
249 case RI_BGP:
250 case RI_OBP0:
251 case RI_OBP1:
252 case RI_WY:
253 case RI_WX:
254 case RI_IE:
255 case RI_IF:
256 return REG(r);
257 case RI_VBK:
258 case RI_BCPS:
259 case RI_OCPS:
260 case RI_BCPD:
261 case RI_OCPD:
262 case RI_SVBK:
263 case RI_KEY1:
264 case RI_HDMA1:
265 case RI_HDMA2:
266 case RI_HDMA3:
267 case RI_HDMA4:
268 case RI_HDMA5:
269 if (hw.cgb) return REG(r);
270 default:
271 return 0xff;
278 * Memory bank controllers typically intercept write attempts to
279 * 0000-7FFF, using the address and byte written as instructions to
280 * change rom or sram banks, control special hardware, etc.
282 * mbc_write takes an address (which should be in the proper range)
283 * and a byte value written to the address.
286 static void mbc_write(int a, byte b) ICODE_ATTR;
287 static void mbc_write(int a, byte b)
289 byte ha = (a>>12);
291 /* printf("mbc %d: rom bank %02X -[%04X:%02X]-> ", mbc.type, mbc.rombank, a, b); */
292 switch (mbc.type)
294 case MBC_MBC1:
295 switch (ha & 0xE)
297 case 0x0:
298 mbc.enableram = ((b & 0x0F) == 0x0A);
299 break;
300 case 0x2:
301 if ((b & 0x1F) == 0) b = 0x01;
302 mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
303 break;
304 case 0x4:
305 if (mbc.model)
307 mbc.rambank = b & 0x03;
308 break;
310 mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
311 break;
312 case 0x6:
313 mbc.model = b & 0x1;
314 break;
316 break;
317 case MBC_MBC2: /* is this at all right? */
318 if ((a & 0x0100) == 0x0000)
320 mbc.enableram = ((b & 0x0F) == 0x0A);
321 break;
323 if ((a & 0xE100) == 0x2100)
325 mbc.rombank = b & 0x0F;
326 break;
328 break;
329 case MBC_MBC3:
330 switch (ha & 0xE)
332 case 0x0:
333 mbc.enableram = ((b & 0x0F) == 0x0A);
334 break;
335 case 0x2:
336 if ((b & 0x7F) == 0) b = 0x01;
337 mbc.rombank = b & 0x7F;
338 break;
339 case 0x4:
340 rtc.sel = b & 0x0f;
341 mbc.rambank = b & 0x03;
342 break;
343 case 0x6:
344 rtc_latch(b);
345 break;
347 break;
348 case MBC_RUMBLE:
349 switch (ha & 0xF)
351 case 0x4:
352 case 0x5:
353 /* FIXME - save high bit as rumble state */
354 /* mask off high bit */
355 b &= 0x7;
356 break;
358 /* fall thru */
359 case MBC_MBC5:
360 switch (ha & 0xF)
362 case 0x0:
363 case 0x1:
364 mbc.enableram = ((b & 0x0F) == 0x0A);
365 break;
366 case 0x2:
367 if ((b & 0xFF) == 0) b = 0x01;
368 mbc.rombank = (mbc.rombank & 0x100) | (b & 0xFF);
369 break;
370 case 0x3:
371 mbc.rombank = (mbc.rombank & 0xFF) | ((int)(b&1)<<8);
372 break;
373 case 0x4:
374 case 0x5:
375 mbc.rambank = b & 0x0f;
376 break;
378 break;
379 case MBC_HUC1: /* FIXME - this is all guesswork -- is it right??? */
380 switch (ha & 0xE)
382 case 0x0:
383 mbc.enableram = ((b & 0x0F) == 0x0A);
384 break;
385 case 0x2:
386 if ((b & 0x1F) == 0) b = 0x01;
387 mbc.rombank = (mbc.rombank & 0x60) | (b & 0x1F);
388 break;
389 case 0x4:
390 if (mbc.model)
392 mbc.rambank = b & 0x03;
393 break;
395 mbc.rombank = (mbc.rombank & 0x1F) | ((int)(b&3)<<5);
396 break;
397 case 0x6:
398 mbc.model = b & 0x1;
399 break;
401 break;
402 case MBC_HUC3: /* FIXME - this is all guesswork -- is it right??? */
403 switch (ha & 0xE)
405 case 0x0:
406 mbc.enableram = ((b & 0x0F) == 0x0A);
407 break;
408 case 0x2:
409 if (!b) b = 1;
410 mbc.rombank = b;
411 break;
412 case 0x4:
413 if (mbc.model)
415 mbc.rambank = b & 0x03;
416 break;
418 break;
419 case 0x6:
420 mbc.model = b & 1;
421 break;
423 break;
425 mbc.rombank &= (mbc.romsize - 1);
426 mbc.rambank &= (mbc.ramsize - 1);
427 mem_updatemap();
432 * mem_write is the basic write function. Although it should only be
433 * called when the write map contains a NULL for the requested address
434 * region, it accepts writes to any address.
437 void mem_write(int a, byte b)
439 int n;
440 byte ha = (a>>12) & 0xE;
442 /* printf("write to 0x%04X: 0x%02X\n", a, b); */
443 switch (ha)
445 case 0x0:
446 case 0x2:
447 case 0x4:
448 case 0x6:
449 mbc_write(a, b);
450 break;
451 case 0x8:
452 /* if ((R_STAT & 0x03) == 0x03) break; */
453 vram_write(a & 0x1FFF, b);
454 break;
455 case 0xA:
456 if (!mbc.enableram) break;
457 if (rtc.sel&8)
459 rtc_write(b);
460 break;
462 ram.sbank[mbc.rambank][a & 0x1FFF] = b;
463 break;
464 case 0xC:
465 if ((a & 0xF000) == 0xC000)
467 ram.ibank[0][a & 0x0FFF] = b;
468 break;
470 n = R_SVBK & 0x07;
471 ram.ibank[n?n:1][a & 0x0FFF] = b;
472 break;
473 case 0xE:
474 if (a < 0xFE00)
476 mem_write(a & 0xDFFF, b);
477 break;
479 if ((a & 0xFF00) == 0xFE00)
481 /* if (R_STAT & 0x02) break; */
482 if (a < 0xFEA0) lcd.oam.mem[a & 0xFF] = b;
483 break;
485 /* return writehi(a & 0xFF, b); */
486 if (a >= 0xFF10 && a <= 0xFF3F)
488 if(options.sound)
489 sound_write(a & 0xFF, b);
490 break;
492 if ((a & 0xFF80) == 0xFF80 && a != 0xFFFF)
494 ram.hi[a & 0xFF] = b;
495 break;
497 ioreg_write(a & 0xFF, b);
503 * mem_read is the basic read function...not useful for much anymore
504 * with the read map, but it's still necessary for the final messy
505 * region.
508 byte mem_read(int a)
510 int n;
511 byte ha = (a>>12) & 0xE;
513 /* printf("read %04x\n", a); */
514 switch (ha)
516 case 0x0:
517 case 0x2:
518 return rom.bank[0][a];
519 case 0x4:
520 case 0x6:
521 return rom.bank[mbc.rombank][a & 0x3FFF];
522 case 0x8:
523 /* if ((R_STAT & 0x03) == 0x03) return 0xFF; */
524 return lcd.vbank[R_VBK&1][a & 0x1FFF];
525 case 0xA:
526 if (!mbc.enableram)
527 return 0xFF;
528 if (rtc.sel&8)
529 return rtc.regs[rtc.sel&7];
530 return ram.sbank[mbc.rambank][a & 0x1FFF];
531 case 0xC:
532 if ((a & 0xF000) == 0xC000)
533 return ram.ibank[0][a & 0x0FFF];
534 n = R_SVBK & 0x07;
535 return ram.ibank[n?n:1][a & 0x0FFF];
536 case 0xE:
537 if (a < 0xFE00) return mem_read(a & 0xDFFF);
538 if ((a & 0xFF00) == 0xFE00)
540 /* if (R_STAT & 0x02) return 0xFF; */
541 if (a < 0xFEA0) return lcd.oam.mem[a & 0xFF];
542 return 0xFF;
544 /* return readhi(a & 0xFF); */
545 if (a == 0xFFFF) return REG(0xFF);
546 if (a >= 0xFF10 && a <= 0xFF3F)
548 if(options.sound)
549 return sound_read(a & 0xFF);
550 else
551 return 1;
553 if ((a & 0xFF80) == 0xFF80)
554 return ram.hi[a & 0xFF];
555 return ioreg_read(a & 0xFF);
557 return 0xff; /* not reached */
560 void mbc_reset(void)
562 mbc.rombank = 1;
563 mbc.rambank = 0;
564 mbc.enableram = 0;
565 mem_updatemap();