all repos — mgba @ 245a13af63adec5b26e087950e1bb5f649f872fb

mGBA Game Boy Advance Emulator

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