src/gb/io.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "io.h"
7
8#include "gb/gb.h"
9
10mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O");
11
12static const uint8_t _registerMask[] = {
13 [REG_SC] = 0x7E, // TODO: GBC differences
14 [REG_IF] = 0xE0,
15 [REG_TAC] = 0xF8,
16 [REG_NR10] = 0x80,
17 [REG_NR11] = 0x3F,
18 [REG_NR12] = 0x00,
19 [REG_NR13] = 0xFF,
20 [REG_NR14] = 0xBF,
21 [REG_NR21] = 0x3F,
22 [REG_NR22] = 0x00,
23 [REG_NR23] = 0xFF,
24 [REG_NR24] = 0xBF,
25 [REG_NR30] = 0x7F,
26 [REG_NR31] = 0xFF,
27 [REG_NR32] = 0x9F,
28 [REG_NR33] = 0xFF,
29 [REG_NR34] = 0xBF,
30 [REG_NR41] = 0xFF,
31 [REG_NR42] = 0x00,
32 [REG_NR43] = 0x00,
33 [REG_NR44] = 0xBF,
34 [REG_NR50] = 0x00,
35 [REG_NR51] = 0x00,
36 [REG_NR52] = 0x70,
37 [REG_STAT] = 0x80,
38 [REG_KEY1] = 0x7E,
39 [REG_VBK] = 0xFE,
40 [REG_OCPS] = 0x40,
41 [REG_BCPS] = 0x40,
42 [REG_UNK6C] = 0xFE,
43 [REG_SVBK] = 0xF8,
44 [REG_UNK75] = 0x8F,
45 [REG_IE] = 0xE0,
46};
47
48void GBIOInit(struct GB* gb) {
49 memset(gb->memory.io, 0, sizeof(gb->memory.io));
50}
51
52void GBIOReset(struct GB* gb) {
53 memset(gb->memory.io, 0, sizeof(gb->memory.io));
54
55 GBIOWrite(gb, REG_TIMA, 0);
56 GBIOWrite(gb, REG_TMA, 0);
57 GBIOWrite(gb, REG_TAC, 0);
58 GBIOWrite(gb, REG_IF, 1);
59 GBIOWrite(gb, REG_NR52, 0xF1);
60 GBIOWrite(gb, REG_NR10, 0x80);
61 GBIOWrite(gb, REG_NR11, 0xBF);
62 GBIOWrite(gb, REG_NR12, 0xF3);
63 GBIOWrite(gb, REG_NR13, 0xF3);
64 GBIOWrite(gb, REG_NR14, 0xBF);
65 GBIOWrite(gb, REG_NR21, 0x3F);
66 GBIOWrite(gb, REG_NR22, 0x00);
67 GBIOWrite(gb, REG_NR24, 0xBF);
68 GBIOWrite(gb, REG_NR30, 0x7F);
69 GBIOWrite(gb, REG_NR31, 0xFF);
70 GBIOWrite(gb, REG_NR32, 0x9F);
71 GBIOWrite(gb, REG_NR34, 0xBF);
72 GBIOWrite(gb, REG_NR41, 0xFF);
73 GBIOWrite(gb, REG_NR42, 0x00);
74 GBIOWrite(gb, REG_NR43, 0x00);
75 GBIOWrite(gb, REG_NR44, 0xBF);
76 GBIOWrite(gb, REG_NR50, 0x77);
77 GBIOWrite(gb, REG_NR51, 0xF3);
78 GBIOWrite(gb, REG_LCDC, 0x91);
79 GBIOWrite(gb, REG_SCY, 0x00);
80 GBIOWrite(gb, REG_SCX, 0x00);
81 GBIOWrite(gb, REG_LYC, 0x00);
82 GBIOWrite(gb, REG_BGP, 0xFC);
83 GBIOWrite(gb, REG_OBP0, 0xFF);
84 GBIOWrite(gb, REG_OBP1, 0xFF);
85 GBIOWrite(gb, REG_WY, 0x00);
86 GBIOWrite(gb, REG_WX, 0x00);
87 GBIOWrite(gb, REG_VBK, 0);
88 GBIOWrite(gb, REG_BCPS, 0);
89 GBIOWrite(gb, REG_OCPS, 0);
90 GBIOWrite(gb, REG_SVBK, 1);
91 GBIOWrite(gb, REG_HDMA1, 0xFF);
92 GBIOWrite(gb, REG_HDMA2, 0xFF);
93 GBIOWrite(gb, REG_HDMA3, 0xFF);
94 GBIOWrite(gb, REG_HDMA4, 0xFF);
95 gb->memory.io[REG_HDMA5] = 0xFF;
96 GBIOWrite(gb, REG_IE, 0x00);
97}
98
99void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
100 switch (address) {
101 case REG_DIV:
102 GBTimerDivReset(&gb->timer);
103 return;
104 case REG_NR10:
105 if (gb->audio.enable) {
106 GBAudioWriteNR10(&gb->audio, value);
107 } else {
108 value = 0;
109 }
110 break;
111 case REG_NR11:
112 if (gb->audio.enable) {
113 GBAudioWriteNR11(&gb->audio, value);
114 } else {
115 if (gb->audio.style == GB_AUDIO_DMG) {
116 GBAudioWriteNR11(&gb->audio, value & _registerMask[REG_NR11]);
117 }
118 value = 0;
119 }
120 break;
121 case REG_NR12:
122 if (gb->audio.enable) {
123 GBAudioWriteNR12(&gb->audio, value);
124 } else {
125 value = 0;
126 }
127 break;
128 case REG_NR13:
129 if (gb->audio.enable) {
130 GBAudioWriteNR13(&gb->audio, value);
131 } else {
132 value = 0;
133 }
134 break;
135 case REG_NR14:
136 if (gb->audio.enable) {
137 GBAudioWriteNR14(&gb->audio, value);
138 } else {
139 value = 0;
140 }
141 break;
142 case REG_NR21:
143 if (gb->audio.enable) {
144 GBAudioWriteNR21(&gb->audio, value);
145 } else {
146 if (gb->audio.style == GB_AUDIO_DMG) {
147 GBAudioWriteNR21(&gb->audio, value & _registerMask[REG_NR21]);
148 }
149 value = 0;
150 }
151 break;
152 case REG_NR22:
153 if (gb->audio.enable) {
154 GBAudioWriteNR22(&gb->audio, value);
155 } else {
156 value = 0;
157 }
158 break;
159 case REG_NR23:
160 if (gb->audio.enable) {
161 GBAudioWriteNR23(&gb->audio, value);
162 } else {
163 value = 0;
164 }
165 break;
166 case REG_NR24:
167 if (gb->audio.enable) {
168 GBAudioWriteNR24(&gb->audio, value);
169 } else {
170 value = 0;
171 }
172 break;
173 case REG_NR30:
174 if (gb->audio.enable) {
175 GBAudioWriteNR30(&gb->audio, value);
176 } else {
177 value = 0;
178 }
179 break;
180 case REG_NR31:
181 if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) {
182 GBAudioWriteNR31(&gb->audio, value);
183 } else {
184 value = 0;
185 }
186 break;
187 case REG_NR32:
188 if (gb->audio.enable) {
189 GBAudioWriteNR32(&gb->audio, value);
190 } else {
191 value = 0;
192 }
193 break;
194 case REG_NR33:
195 if (gb->audio.enable) {
196 GBAudioWriteNR33(&gb->audio, value);
197 } else {
198 value = 0;
199 }
200 break;
201 case REG_NR34:
202 if (gb->audio.enable) {
203 GBAudioWriteNR34(&gb->audio, value);
204 } else {
205 value = 0;
206 }
207 break;
208 case REG_NR41:
209 if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) {
210 GBAudioWriteNR41(&gb->audio, value);
211 } else {
212 value = 0;
213 }
214 break;
215 case REG_NR42:
216 if (gb->audio.enable) {
217 GBAudioWriteNR42(&gb->audio, value);
218 } else {
219 value = 0;
220 }
221 break;
222 case REG_NR43:
223 if (gb->audio.enable) {
224 GBAudioWriteNR43(&gb->audio, value);
225 } else {
226 value = 0;
227 }
228 break;
229 case REG_NR44:
230 if (gb->audio.enable) {
231 GBAudioWriteNR44(&gb->audio, value);
232 } else {
233 value = 0;
234 }
235 break;
236 case REG_NR50:
237 if (gb->audio.enable) {
238 GBAudioWriteNR50(&gb->audio, value);
239 } else {
240 value = 0;
241 }
242 break;
243 case REG_NR51:
244 if (gb->audio.enable) {
245 GBAudioWriteNR51(&gb->audio, value);
246 } else {
247 value = 0;
248 }
249 break;
250 case REG_NR52:
251 GBAudioWriteNR52(&gb->audio, value);
252 value &= 0x80;
253 value |= gb->memory.io[REG_NR52] & 0x0F;
254 break;
255 case REG_WAVE_0:
256 case REG_WAVE_1:
257 case REG_WAVE_2:
258 case REG_WAVE_3:
259 case REG_WAVE_4:
260 case REG_WAVE_5:
261 case REG_WAVE_6:
262 case REG_WAVE_7:
263 case REG_WAVE_8:
264 case REG_WAVE_9:
265 case REG_WAVE_A:
266 case REG_WAVE_B:
267 case REG_WAVE_C:
268 case REG_WAVE_D:
269 case REG_WAVE_E:
270 case REG_WAVE_F:
271 if (!gb->audio.playingCh3 || gb->audio.style != GB_AUDIO_DMG) {
272 gb->audio.ch3.wavedata8[address - REG_WAVE_0] = value;
273 } else if(gb->audio.ch3.readable) {
274 gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1] = value;
275 }
276 break;
277 case REG_JOYP:
278 case REG_TIMA:
279 case REG_TMA:
280 case REG_LYC:
281 // Handled transparently by the registers
282 break;
283 case REG_TAC:
284 value = GBTimerUpdateTAC(&gb->timer, value);
285 break;
286 case REG_IF:
287 gb->memory.io[REG_IF] = value | 0xE0;
288 GBUpdateIRQs(gb);
289 return;
290 case REG_LCDC:
291 // TODO: handle GBC differences
292 value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
293 GBVideoWriteLCDC(&gb->video, value);
294 break;
295 case REG_DMA:
296 GBMemoryDMA(gb, value << 8);
297 break;
298 case REG_SCY:
299 case REG_SCX:
300 case REG_WY:
301 case REG_WX:
302 GBVideoProcessDots(&gb->video);
303 value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
304 break;
305 case REG_BGP:
306 case REG_OBP0:
307 case REG_OBP1:
308 GBVideoProcessDots(&gb->video);
309 GBVideoWritePalette(&gb->video, address, value);
310 break;
311 case REG_STAT:
312 GBVideoWriteSTAT(&gb->video, value);
313 break;
314 case 0x50:
315 if (gb->memory.romBase != gb->memory.rom) {
316 free(gb->memory.romBase);
317 gb->memory.romBase = gb->memory.rom;
318 }
319 break;
320 case REG_IE:
321 gb->memory.ie = value;
322 GBUpdateIRQs(gb);
323 return;
324 default:
325 if (gb->model >= GB_MODEL_CGB) {
326 switch (address) {
327 case REG_KEY1:
328 value &= 0x1;
329 value |= gb->memory.io[address] & 0x80;
330 break;
331 case REG_VBK:
332 GBVideoSwitchBank(&gb->video, value);
333 break;
334 case REG_HDMA1:
335 case REG_HDMA2:
336 case REG_HDMA3:
337 case REG_HDMA4:
338 // Handled transparently by the registers
339 break;
340 case REG_HDMA5:
341 GBMemoryWriteHDMA5(gb, value);
342 value &= 0x7F;
343 break;
344 case REG_BCPS:
345 gb->video.bcpIndex = value & 0x3F;
346 gb->video.bcpIncrement = value & 0x80;
347 gb->memory.io[REG_BCPD] = gb->video.palette[gb->video.bcpIndex >> 1] >> (8 * (gb->video.bcpIndex & 1));
348 break;
349 case REG_BCPD:
350 GBVideoProcessDots(&gb->video);
351 GBVideoWritePalette(&gb->video, address, value);
352 break;
353 case REG_OCPS:
354 gb->video.ocpIndex = value & 0x3F;
355 gb->video.ocpIncrement = value & 0x80;
356 gb->memory.io[REG_OCPD] = gb->video.palette[8 * 4 + (gb->video.ocpIndex >> 1)] >> (8 * (gb->video.ocpIndex & 1));
357 break;
358 case REG_OCPD:
359 GBVideoProcessDots(&gb->video);
360 GBVideoWritePalette(&gb->video, address, value);
361 break;
362 case REG_SVBK:
363 GBMemorySwitchWramBank(&gb->memory, value);
364 value = gb->memory.wramCurrentBank;
365 break;
366 default:
367 goto failed;
368 }
369 goto success;
370 }
371 failed:
372 mLOG(GB_IO, STUB, "Writing to unknown register FF%02X:%02X", address, value);
373 if (address >= GB_SIZE_IO) {
374 return;
375 }
376 break;
377 }
378 success:
379 gb->memory.io[address] = value;
380}
381
382static uint8_t _readKeys(struct GB* gb) {
383 uint8_t keys = *gb->keySource;
384 switch (gb->memory.io[REG_JOYP] & 0x30) {
385 case 0x30:
386 keys = 0;
387 break;
388 case 0x20:
389 keys >>= 4;
390 break;
391 case 0x10:
392 break;
393 case 0x00:
394 keys |= keys >> 4;
395 break;
396 }
397 return (0xC0 | (gb->memory.io[REG_JOYP] | 0xF)) ^ (keys & 0xF);
398}
399
400uint8_t GBIORead(struct GB* gb, unsigned address) {
401 switch (address) {
402 case REG_JOYP:
403 return _readKeys(gb);
404 case REG_SB:
405 case REG_SC:
406 // TODO
407 break;
408 case REG_IE:
409 return gb->memory.ie;
410 case REG_WAVE_0:
411 case REG_WAVE_1:
412 case REG_WAVE_2:
413 case REG_WAVE_3:
414 case REG_WAVE_4:
415 case REG_WAVE_5:
416 case REG_WAVE_6:
417 case REG_WAVE_7:
418 case REG_WAVE_8:
419 case REG_WAVE_9:
420 case REG_WAVE_A:
421 case REG_WAVE_B:
422 case REG_WAVE_C:
423 case REG_WAVE_D:
424 case REG_WAVE_E:
425 case REG_WAVE_F:
426 if (gb->audio.playingCh3) {
427 if (gb->audio.ch3.readable || gb->audio.style != GB_AUDIO_DMG) {
428 return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1];
429 } else {
430 return 0xFF;
431 }
432 } else {
433 return gb->audio.ch3.wavedata8[address - REG_WAVE_0];
434 }
435 break;
436 case REG_IF:
437 case REG_NR10:
438 case REG_NR11:
439 case REG_NR12:
440 case REG_NR14:
441 case REG_NR21:
442 case REG_NR22:
443 case REG_NR24:
444 case REG_NR30:
445 case REG_NR32:
446 case REG_NR34:
447 case REG_NR41:
448 case REG_NR42:
449 case REG_NR43:
450 case REG_NR44:
451 case REG_NR50:
452 case REG_NR51:
453 case REG_NR52:
454 case REG_DIV:
455 case REG_TIMA:
456 case REG_TMA:
457 case REG_TAC:
458 case REG_STAT:
459 case REG_LCDC:
460 case REG_SCY:
461 case REG_SCX:
462 case REG_LY:
463 case REG_LYC:
464 case REG_BGP:
465 case REG_OBP0:
466 case REG_OBP1:
467 case REG_WY:
468 case REG_WX:
469 // Handled transparently by the registers
470 break;
471 default:
472 if (gb->model >= GB_MODEL_CGB) {
473 switch (address) {
474 case REG_KEY1:
475 case REG_VBK:
476 case REG_HDMA1:
477 case REG_HDMA2:
478 case REG_HDMA3:
479 case REG_HDMA4:
480 case REG_HDMA5:
481 case REG_BCPD:
482 case REG_OCPD:
483 case REG_SVBK:
484 // Handled transparently by the registers
485 goto success;
486 default:
487 break;
488 }
489 }
490 mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address);
491 return 0xFF;
492 }
493 success:
494 return gb->memory.io[address] | _registerMask[address];
495}