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 REG_IE:
315 gb->memory.ie = value;
316 GBUpdateIRQs(gb);
317 return;
318 default:
319 if (gb->model >= GB_MODEL_CGB) {
320 switch (address) {
321 case REG_KEY1:
322 value &= 0x1;
323 value |= gb->memory.io[address] & 0x80;
324 break;
325 case REG_VBK:
326 GBVideoSwitchBank(&gb->video, value);
327 break;
328 case REG_HDMA1:
329 case REG_HDMA2:
330 case REG_HDMA3:
331 case REG_HDMA4:
332 // Handled transparently by the registers
333 break;
334 case REG_HDMA5:
335 GBMemoryWriteHDMA5(gb, value);
336 value &= 0x7F;
337 break;
338 case REG_BCPS:
339 gb->video.bcpIndex = value & 0x3F;
340 gb->video.bcpIncrement = value & 0x80;
341 gb->memory.io[REG_BCPD] = gb->video.palette[gb->video.bcpIndex >> 1] >> (8 * (gb->video.bcpIndex & 1));
342 break;
343 case REG_BCPD:
344 GBVideoProcessDots(&gb->video);
345 GBVideoWritePalette(&gb->video, address, value);
346 break;
347 case REG_OCPS:
348 gb->video.ocpIndex = value & 0x3F;
349 gb->video.ocpIncrement = value & 0x80;
350 gb->memory.io[REG_OCPD] = gb->video.palette[8 * 4 + (gb->video.ocpIndex >> 1)] >> (8 * (gb->video.ocpIndex & 1));
351 break;
352 case REG_OCPD:
353 GBVideoProcessDots(&gb->video);
354 GBVideoWritePalette(&gb->video, address, value);
355 break;
356 case REG_SVBK:
357 GBMemorySwitchWramBank(&gb->memory, value);
358 value = gb->memory.wramCurrentBank;
359 break;
360 default:
361 goto failed;
362 }
363 goto success;
364 }
365 failed:
366 mLOG(GB_IO, STUB, "Writing to unknown register FF%02X:%02X", address, value);
367 if (address >= GB_SIZE_IO) {
368 return;
369 }
370 break;
371 }
372 success:
373 gb->memory.io[address] = value;
374}
375
376static uint8_t _readKeys(struct GB* gb) {
377 uint8_t keys = *gb->keySource;
378 switch (gb->memory.io[REG_JOYP] & 0x30) {
379 case 0x30:
380 keys = 0;
381 break;
382 case 0x20:
383 keys >>= 4;
384 break;
385 case 0x10:
386 break;
387 case 0x00:
388 keys |= keys >> 4;
389 break;
390 }
391 return (0xC0 | (gb->memory.io[REG_JOYP] | 0xF)) ^ (keys & 0xF);
392}
393
394uint8_t GBIORead(struct GB* gb, unsigned address) {
395 switch (address) {
396 case REG_JOYP:
397 return _readKeys(gb);
398 case REG_SB:
399 case REG_SC:
400 // TODO
401 break;
402 case REG_IE:
403 return gb->memory.ie;
404 case REG_WAVE_0:
405 case REG_WAVE_1:
406 case REG_WAVE_2:
407 case REG_WAVE_3:
408 case REG_WAVE_4:
409 case REG_WAVE_5:
410 case REG_WAVE_6:
411 case REG_WAVE_7:
412 case REG_WAVE_8:
413 case REG_WAVE_9:
414 case REG_WAVE_A:
415 case REG_WAVE_B:
416 case REG_WAVE_C:
417 case REG_WAVE_D:
418 case REG_WAVE_E:
419 case REG_WAVE_F:
420 if (gb->audio.playingCh3) {
421 if (gb->audio.ch3.readable || gb->audio.style != GB_AUDIO_DMG) {
422 return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1];
423 } else {
424 return 0xFF;
425 }
426 } else {
427 return gb->audio.ch3.wavedata8[address - REG_WAVE_0];
428 }
429 break;
430 case REG_IF:
431 case REG_NR10:
432 case REG_NR11:
433 case REG_NR12:
434 case REG_NR14:
435 case REG_NR21:
436 case REG_NR22:
437 case REG_NR24:
438 case REG_NR30:
439 case REG_NR32:
440 case REG_NR34:
441 case REG_NR41:
442 case REG_NR42:
443 case REG_NR43:
444 case REG_NR44:
445 case REG_NR50:
446 case REG_NR51:
447 case REG_NR52:
448 case REG_DIV:
449 case REG_TIMA:
450 case REG_TMA:
451 case REG_TAC:
452 case REG_STAT:
453 case REG_LCDC:
454 case REG_SCY:
455 case REG_SCX:
456 case REG_LY:
457 case REG_LYC:
458 case REG_BGP:
459 case REG_OBP0:
460 case REG_OBP1:
461 case REG_WY:
462 case REG_WX:
463 // Handled transparently by the registers
464 break;
465 default:
466 if (gb->model >= GB_MODEL_CGB) {
467 switch (address) {
468 case REG_KEY1:
469 case REG_VBK:
470 case REG_HDMA1:
471 case REG_HDMA2:
472 case REG_HDMA3:
473 case REG_HDMA4:
474 case REG_HDMA5:
475 case REG_BCPD:
476 case REG_OCPD:
477 case REG_SVBK:
478 // Handled transparently by the registers
479 goto success;
480 default:
481 break;
482 }
483 }
484 mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address);
485 return 0xFF;
486 }
487 success:
488 return gb->memory.io[address] | _registerMask[address];
489}