all repos — mgba @ 7b12516df45ac2bfc0597d6a584e80f8b4721255

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 <mgba/internal/gb/io.h>
  7
  8#include <mgba/internal/gb/gb.h>
  9#include <mgba/internal/gb/sio.h>
 10#include <mgba/internal/gb/serialize.h>
 11
 12mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O", "gb.io");
 13
 14const char* const GBIORegisterNames[] = {
 15	[REG_JOYP] = "JOYP",
 16	[REG_SB] = "SB",
 17	[REG_SC] = "SC",
 18	[REG_DIV] = "DIV",
 19	[REG_TIMA] = "TIMA",
 20	[REG_TMA] = "TMA",
 21	[REG_TAC] = "TAC",
 22	[REG_IF] = "IF",
 23	[REG_NR10] = "NR10",
 24	[REG_NR11] = "NR11",
 25	[REG_NR12] = "NR12",
 26	[REG_NR13] = "NR13",
 27	[REG_NR14] = "NR14",
 28	[REG_NR21] = "NR21",
 29	[REG_NR22] = "NR22",
 30	[REG_NR23] = "NR23",
 31	[REG_NR24] = "NR24",
 32	[REG_NR30] = "NR30",
 33	[REG_NR31] = "NR31",
 34	[REG_NR32] = "NR32",
 35	[REG_NR33] = "NR33",
 36	[REG_NR34] = "NR34",
 37	[REG_NR41] = "NR41",
 38	[REG_NR42] = "NR42",
 39	[REG_NR43] = "NR43",
 40	[REG_NR44] = "NR44",
 41	[REG_NR50] = "NR50",
 42	[REG_NR51] = "NR51",
 43	[REG_NR52] = "NR52",
 44	[REG_LCDC] = "LCDC",
 45	[REG_STAT] = "STAT",
 46	[REG_SCY] = "SCY",
 47	[REG_SCX] = "SCX",
 48	[REG_LY] = "LY",
 49	[REG_LYC] = "LYC",
 50	[REG_DMA] = "DMA",
 51	[REG_BGP] = "BGP",
 52	[REG_OBP0] = "OBP0",
 53	[REG_OBP1] = "OBP1",
 54	[REG_WY] = "WY",
 55	[REG_WX] = "WX",
 56	[REG_KEY1] = "KEY1",
 57	[REG_VBK] = "VBK",
 58	[REG_HDMA1] = "HDMA1",
 59	[REG_HDMA2] = "HDMA2",
 60	[REG_HDMA3] = "HDMA3",
 61	[REG_HDMA4] = "HDMA4",
 62	[REG_HDMA5] = "HDMA5",
 63	[REG_RP] = "RP",
 64	[REG_BCPS] = "BCPS",
 65	[REG_BCPD] = "BCPD",
 66	[REG_OCPS] = "OCPS",
 67	[REG_OCPD] = "OCPD",
 68	[REG_SVBK] = "SVBK",
 69	[REG_IE] = "IE",
 70};
 71
 72static const uint8_t _registerMask[] = {
 73	[REG_SC]   = 0x7E, // TODO: GBC differences
 74	[REG_IF]   = 0xE0,
 75	[REG_TAC]  = 0xF8,
 76	[REG_NR10] = 0x80,
 77	[REG_NR11] = 0x3F,
 78	[REG_NR12] = 0x00,
 79	[REG_NR13] = 0xFF,
 80	[REG_NR14] = 0xBF,
 81	[REG_NR21] = 0x3F,
 82	[REG_NR22] = 0x00,
 83	[REG_NR23] = 0xFF,
 84	[REG_NR24] = 0xBF,
 85	[REG_NR30] = 0x7F,
 86	[REG_NR31] = 0xFF,
 87	[REG_NR32] = 0x9F,
 88	[REG_NR33] = 0xFF,
 89	[REG_NR34] = 0xBF,
 90	[REG_NR41] = 0xFF,
 91	[REG_NR42] = 0x00,
 92	[REG_NR43] = 0x00,
 93	[REG_NR44] = 0xBF,
 94	[REG_NR50] = 0x00,
 95	[REG_NR51] = 0x00,
 96	[REG_NR52] = 0x70,
 97	[REG_STAT] = 0x80,
 98	[REG_KEY1] = 0x7E,
 99	[REG_VBK] = 0xFE,
100	[REG_OCPS] = 0x40,
101	[REG_BCPS] = 0x40,
102	[REG_UNK6C] = 0xFE,
103	[REG_SVBK] = 0xF8,
104	[REG_IE]   = 0xE0,
105};
106
107static uint8_t _readKeys(struct GB* gb);
108static uint8_t _readKeysFiltered(struct GB* gb);
109
110static void _writeSGBBits(struct GB* gb, int bits) {
111	if (!bits) {
112		gb->sgbBit = -1;
113		memset(gb->sgbPacket, 0, sizeof(gb->sgbPacket));
114	}
115	if (bits == gb->currentSgbBits) {
116		return;
117	}
118	gb->currentSgbBits = bits;
119	if (gb->sgbBit > 128) {
120		switch (bits) {
121		case 1:
122			gb->sgbBit |= 2;
123			break;
124		case 2:
125			gb->sgbBit |= 4;
126			break;
127		case 3:
128			if (gb->sgbBit == 135) {
129				gb->sgbBit &= ~6;
130				gb->sgbCurrentController = (gb->sgbCurrentController + 1) & gb->sgbControllers;
131			}
132			break;
133		}
134	}
135	if (gb->sgbBit == 128 && bits == 2) {
136		GBVideoWriteSGBPacket(&gb->video, gb->sgbPacket);
137		++gb->sgbBit;
138	}
139	if (gb->sgbBit >= 128) {
140		return;
141	}
142	switch (bits) {
143	case 1:
144		if (gb->sgbBit < 0) {
145			return;
146		}
147		gb->sgbPacket[gb->sgbBit >> 3] |= 1 << (gb->sgbBit & 7);
148		break;
149	case 3:
150		++gb->sgbBit;
151	default:
152		break;
153	}
154}
155
156void GBIOInit(struct GB* gb) {
157	memset(gb->memory.io, 0, sizeof(gb->memory.io));
158}
159
160void GBIOReset(struct GB* gb) {
161	memset(gb->memory.io, 0, sizeof(gb->memory.io));
162
163	GBIOWrite(gb, REG_TIMA, 0);
164	GBIOWrite(gb, REG_TMA, 0);
165	GBIOWrite(gb, REG_TAC, 0);
166	GBIOWrite(gb, REG_IF, 1);
167	GBIOWrite(gb, REG_NR52, 0xF1);
168	GBIOWrite(gb, REG_NR14, 0x3F);
169	GBIOWrite(gb, REG_NR10, 0x80);
170	GBIOWrite(gb, REG_NR11, 0xBF);
171	GBIOWrite(gb, REG_NR12, 0xF3);
172	GBIOWrite(gb, REG_NR13, 0xF3);
173	GBIOWrite(gb, REG_NR24, 0x3F);
174	GBIOWrite(gb, REG_NR21, 0x3F);
175	GBIOWrite(gb, REG_NR22, 0x00);
176	GBIOWrite(gb, REG_NR34, 0x3F);
177	GBIOWrite(gb, REG_NR30, 0x7F);
178	GBIOWrite(gb, REG_NR31, 0xFF);
179	GBIOWrite(gb, REG_NR32, 0x9F);
180	GBIOWrite(gb, REG_NR44, 0x3F);
181	GBIOWrite(gb, REG_NR41, 0xFF);
182	GBIOWrite(gb, REG_NR42, 0x00);
183	GBIOWrite(gb, REG_NR43, 0x00);
184	GBIOWrite(gb, REG_NR50, 0x77);
185	GBIOWrite(gb, REG_NR51, 0xF3);
186	if (!gb->biosVf) {
187		GBIOWrite(gb, REG_LCDC, 0x91);
188	} else {
189		GBIOWrite(gb, REG_LCDC, 0x00);
190	}
191	GBIOWrite(gb, REG_SCY, 0x00);
192	GBIOWrite(gb, REG_SCX, 0x00);
193	GBIOWrite(gb, REG_LYC, 0x00);
194	GBIOWrite(gb, REG_DMA, 0xFF);
195	GBIOWrite(gb, REG_BGP, 0xFC);
196	if (gb->model < GB_MODEL_CGB) {
197		GBIOWrite(gb, REG_OBP0, 0xFF);
198		GBIOWrite(gb, REG_OBP1, 0xFF);
199	}
200	GBIOWrite(gb, REG_WY, 0x00);
201	GBIOWrite(gb, REG_WX, 0x00);
202	if (gb->model & GB_MODEL_CGB) {
203		GBIOWrite(gb, REG_UNK4C, 0);
204		GBIOWrite(gb, REG_JOYP, 0xFF);
205		GBIOWrite(gb, REG_VBK, 0);
206		GBIOWrite(gb, REG_BCPS, 0);
207		GBIOWrite(gb, REG_OCPS, 0);
208		GBIOWrite(gb, REG_SVBK, 1);
209		GBIOWrite(gb, REG_HDMA1, 0xFF);
210		GBIOWrite(gb, REG_HDMA2, 0xFF);
211		GBIOWrite(gb, REG_HDMA3, 0xFF);
212		GBIOWrite(gb, REG_HDMA4, 0xFF);
213		gb->memory.io[REG_HDMA5] = 0xFF;
214	} else if (gb->model & GB_MODEL_SGB) {
215		GBIOWrite(gb, REG_JOYP, 0xFF);
216	}
217	GBIOWrite(gb, REG_IE, 0x00);
218}
219
220void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
221	switch (address) {
222	case REG_SB:
223		GBSIOWriteSB(&gb->sio, value);
224		break;
225	case REG_SC:
226		GBSIOWriteSC(&gb->sio, value);
227		break;
228	case REG_DIV:
229		GBTimerDivReset(&gb->timer);
230		return;
231	case REG_NR10:
232		if (gb->audio.enable) {
233			GBAudioWriteNR10(&gb->audio, value);
234		} else {
235			value = 0;
236		}
237		break;
238	case REG_NR11:
239		if (gb->audio.enable) {
240			GBAudioWriteNR11(&gb->audio, value);
241		} else {
242			if (gb->audio.style == GB_AUDIO_DMG) {
243				GBAudioWriteNR11(&gb->audio, value & _registerMask[REG_NR11]);
244			}
245			value = 0;
246		}
247		break;
248	case REG_NR12:
249		if (gb->audio.enable) {
250			GBAudioWriteNR12(&gb->audio, value);
251		} else {
252			value = 0;
253		}
254		break;
255	case REG_NR13:
256		if (gb->audio.enable) {
257			GBAudioWriteNR13(&gb->audio, value);
258		} else {
259			value = 0;
260		}
261		break;
262	case REG_NR14:
263		if (gb->audio.enable) {
264			GBAudioWriteNR14(&gb->audio, value);
265		} else {
266			value = 0;
267		}
268		break;
269	case REG_NR21:
270		if (gb->audio.enable) {
271			GBAudioWriteNR21(&gb->audio, value);
272		} else {
273			if (gb->audio.style == GB_AUDIO_DMG) {
274				GBAudioWriteNR21(&gb->audio, value & _registerMask[REG_NR21]);
275			}
276			value = 0;
277		}
278		break;
279	case REG_NR22:
280		if (gb->audio.enable) {
281			GBAudioWriteNR22(&gb->audio, value);
282		} else {
283			value = 0;
284		}
285		break;
286	case REG_NR23:
287		if (gb->audio.enable) {
288			GBAudioWriteNR23(&gb->audio, value);
289		} else {
290			value = 0;
291		}
292		break;
293	case REG_NR24:
294		if (gb->audio.enable) {
295			GBAudioWriteNR24(&gb->audio, value);
296		} else {
297			value = 0;
298		}
299		break;
300	case REG_NR30:
301		if (gb->audio.enable) {
302			GBAudioWriteNR30(&gb->audio, value);
303		} else {
304			value = 0;
305		}
306		break;
307	case REG_NR31:
308		if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) {
309			GBAudioWriteNR31(&gb->audio, value);
310		} else {
311			value = 0;
312		}
313		break;
314	case REG_NR32:
315		if (gb->audio.enable) {
316			GBAudioWriteNR32(&gb->audio, value);
317		} else {
318			value = 0;
319		}
320		break;
321	case REG_NR33:
322		if (gb->audio.enable) {
323			GBAudioWriteNR33(&gb->audio, value);
324		} else {
325			value = 0;
326		}
327		break;
328	case REG_NR34:
329		if (gb->audio.enable) {
330			GBAudioWriteNR34(&gb->audio, value);
331		} else {
332			value = 0;
333		}
334		break;
335	case REG_NR41:
336		if (gb->audio.enable || gb->audio.style == GB_AUDIO_DMG) {
337			GBAudioWriteNR41(&gb->audio, value);
338		} else {
339			value = 0;
340		}
341		break;
342	case REG_NR42:
343		if (gb->audio.enable) {
344			GBAudioWriteNR42(&gb->audio, value);
345		} else {
346			value = 0;
347		}
348		break;
349	case REG_NR43:
350		if (gb->audio.enable) {
351			GBAudioWriteNR43(&gb->audio, value);
352		} else {
353			value = 0;
354		}
355		break;
356	case REG_NR44:
357		if (gb->audio.enable) {
358			GBAudioWriteNR44(&gb->audio, value);
359		} else {
360			value = 0;
361		}
362		break;
363	case REG_NR50:
364		if (gb->audio.enable) {
365			GBAudioWriteNR50(&gb->audio, value);
366		} else {
367			value = 0;
368		}
369		break;
370	case REG_NR51:
371		if (gb->audio.enable) {
372			GBAudioWriteNR51(&gb->audio, value);
373		} else {
374			value = 0;
375		}
376		break;
377	case REG_NR52:
378		GBAudioWriteNR52(&gb->audio, value);
379		value &= 0x80;
380		value |= gb->memory.io[REG_NR52] & 0x0F;
381		break;
382	case REG_WAVE_0:
383	case REG_WAVE_1:
384	case REG_WAVE_2:
385	case REG_WAVE_3:
386	case REG_WAVE_4:
387	case REG_WAVE_5:
388	case REG_WAVE_6:
389	case REG_WAVE_7:
390	case REG_WAVE_8:
391	case REG_WAVE_9:
392	case REG_WAVE_A:
393	case REG_WAVE_B:
394	case REG_WAVE_C:
395	case REG_WAVE_D:
396	case REG_WAVE_E:
397	case REG_WAVE_F:
398		if (!gb->audio.playingCh3 || gb->audio.style != GB_AUDIO_DMG) {
399			gb->audio.ch3.wavedata8[address - REG_WAVE_0] = value;
400		} else if(gb->audio.ch3.readable) {
401			gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1] = value;
402		}
403		break;
404	case REG_JOYP:
405		gb->memory.io[REG_JOYP] = value | 0x0F;
406		_readKeys(gb);
407		if (gb->model & GB_MODEL_SGB) {
408			_writeSGBBits(gb, (value >> 4) & 3);
409		}
410		return;
411	case REG_TIMA:
412		if (value && mTimingUntil(&gb->timing, &gb->timer.irq) > 1) {
413			mTimingDeschedule(&gb->timing, &gb->timer.irq);
414		}
415		if (mTimingUntil(&gb->timing, &gb->timer.irq) == -1) {
416			return;
417		}
418		break;
419	case REG_TMA:
420		if (mTimingUntil(&gb->timing, &gb->timer.irq) == -1) {
421			gb->memory.io[REG_TIMA] = value;
422		}
423		break;
424	case REG_TAC:
425		value = GBTimerUpdateTAC(&gb->timer, value);
426		break;
427	case REG_IF:
428		gb->memory.io[REG_IF] = value | 0xE0;
429		GBUpdateIRQs(gb);
430		return;
431	case REG_LCDC:
432		// TODO: handle GBC differences
433		GBVideoProcessDots(&gb->video, 0);
434		value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
435		GBVideoWriteLCDC(&gb->video, value);
436		break;
437	case REG_LYC:
438		GBVideoWriteLYC(&gb->video, value);
439		break;
440	case REG_DMA:
441		GBMemoryDMA(gb, value << 8);
442		break;
443	case REG_SCY:
444	case REG_SCX:
445	case REG_WY:
446	case REG_WX:
447		GBVideoProcessDots(&gb->video, 0);
448		value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
449		break;
450	case REG_BGP:
451	case REG_OBP0:
452	case REG_OBP1:
453		GBVideoProcessDots(&gb->video, 0);
454		GBVideoWritePalette(&gb->video, address, value);
455		break;
456	case REG_STAT:
457		GBVideoWriteSTAT(&gb->video, value);
458		value = gb->video.stat;
459		break;
460	case 0x50:
461		GBUnmapBIOS(gb);
462		if (gb->model >= GB_MODEL_CGB && gb->memory.io[REG_UNK4C] < 0x80) {
463			gb->model = GB_MODEL_DMG;
464			GBVideoDisableCGB(&gb->video);
465		}
466		break;
467	case REG_IE:
468		gb->memory.ie = value;
469		GBUpdateIRQs(gb);
470		return;
471	default:
472		if (gb->model >= GB_MODEL_CGB) {
473			switch (address) {
474			case REG_UNK4C:
475				break;
476			case REG_KEY1:
477				value &= 0x1;
478				value |= gb->memory.io[address] & 0x80;
479				break;
480			case REG_VBK:
481				GBVideoSwitchBank(&gb->video, value);
482				break;
483			case REG_HDMA1:
484			case REG_HDMA2:
485			case REG_HDMA3:
486			case REG_HDMA4:
487				// Handled transparently by the registers
488				break;
489			case REG_HDMA5:
490				value = GBMemoryWriteHDMA5(gb, value);
491				break;
492			case REG_BCPS:
493				gb->video.bcpIndex = value & 0x3F;
494				gb->video.bcpIncrement = value & 0x80;
495				gb->memory.io[REG_BCPD] = gb->video.palette[gb->video.bcpIndex >> 1] >> (8 * (gb->video.bcpIndex & 1));
496				break;
497			case REG_BCPD:
498				if (gb->video.mode != 3) {
499					GBVideoProcessDots(&gb->video, 0);
500					GBVideoWritePalette(&gb->video, address, value);
501				}
502				return;
503			case REG_OCPS:
504				gb->video.ocpIndex = value & 0x3F;
505				gb->video.ocpIncrement = value & 0x80;
506				gb->memory.io[REG_OCPD] = gb->video.palette[8 * 4 + (gb->video.ocpIndex >> 1)] >> (8 * (gb->video.ocpIndex & 1));
507				break;
508			case REG_OCPD:
509				if (gb->video.mode != 3) {
510					GBVideoProcessDots(&gb->video, 0);
511					GBVideoWritePalette(&gb->video, address, value);
512				}
513				return;
514			case REG_SVBK:
515				GBMemorySwitchWramBank(&gb->memory, value);
516				value = gb->memory.wramCurrentBank;
517				break;
518			default:
519				goto failed;
520			}
521			goto success;
522		}
523		failed:
524		mLOG(GB_IO, STUB, "Writing to unknown register FF%02X:%02X", address, value);
525		if (address >= GB_SIZE_IO) {
526			return;
527		}
528		break;
529	}
530	success:
531	gb->memory.io[address] = value;
532}
533
534static uint8_t _readKeys(struct GB* gb) {
535	uint8_t keys = *gb->keySource;
536	if (gb->sgbCurrentController != 0) {
537		keys = 0;
538	}
539	uint8_t joyp = gb->memory.io[REG_JOYP];
540	switch (joyp & 0x30) {
541	case 0x30:
542		keys = gb->sgbCurrentController;
543		break;
544	case 0x20:
545		keys >>= 4;
546		break;
547	case 0x10:
548		break;
549	case 0x00:
550		keys |= keys >> 4;
551		break;
552	}
553	gb->memory.io[REG_JOYP] = (0xCF | joyp) ^ (keys & 0xF);
554	if (joyp & ~gb->memory.io[REG_JOYP] & 0xF) {
555		gb->memory.io[REG_IF] |= (1 << GB_IRQ_KEYPAD);
556		GBUpdateIRQs(gb);
557	}
558	return gb->memory.io[REG_JOYP];
559}
560
561static uint8_t _readKeysFiltered(struct GB* gb) {
562	uint8_t keys = _readKeys(gb);
563	if (!gb->allowOpposingDirections && (keys & 0x30) == 0x20) {
564		unsigned rl = keys & 0x03;
565		unsigned ud = keys & 0x0C;
566		if (!rl) {
567			keys |= 0x03;
568		}
569		if (!ud) {
570			keys |= 0x0C;
571		}
572	}
573	return keys;
574}
575
576uint8_t GBIORead(struct GB* gb, unsigned address) {
577	switch (address) {
578	case REG_JOYP:
579		{
580			size_t c;
581			for (c = 0; c < mCoreCallbacksListSize(&gb->coreCallbacks); ++c) {
582				struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gb->coreCallbacks, c);
583				if (callbacks->keysRead) {
584					callbacks->keysRead(callbacks->context);
585				}
586			}
587		}
588		return _readKeysFiltered(gb);
589	case REG_IE:
590		return gb->memory.ie;
591	case REG_WAVE_0:
592	case REG_WAVE_1:
593	case REG_WAVE_2:
594	case REG_WAVE_3:
595	case REG_WAVE_4:
596	case REG_WAVE_5:
597	case REG_WAVE_6:
598	case REG_WAVE_7:
599	case REG_WAVE_8:
600	case REG_WAVE_9:
601	case REG_WAVE_A:
602	case REG_WAVE_B:
603	case REG_WAVE_C:
604	case REG_WAVE_D:
605	case REG_WAVE_E:
606	case REG_WAVE_F:
607		if (gb->audio.playingCh3) {
608			if (gb->audio.ch3.readable || gb->audio.style != GB_AUDIO_DMG) {
609				return gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1];
610			} else {
611				return 0xFF;
612			}
613		} else {
614			return gb->audio.ch3.wavedata8[address - REG_WAVE_0];
615		}
616		break;
617	case REG_SB:
618	case REG_SC:
619	case REG_IF:
620	case REG_NR10:
621	case REG_NR11:
622	case REG_NR12:
623	case REG_NR14:
624	case REG_NR21:
625	case REG_NR22:
626	case REG_NR24:
627	case REG_NR30:
628	case REG_NR32:
629	case REG_NR34:
630	case REG_NR41:
631	case REG_NR42:
632	case REG_NR43:
633	case REG_NR44:
634	case REG_NR50:
635	case REG_NR51:
636	case REG_NR52:
637	case REG_DIV:
638	case REG_TIMA:
639	case REG_TMA:
640	case REG_TAC:
641	case REG_STAT:
642	case REG_LCDC:
643	case REG_SCY:
644	case REG_SCX:
645	case REG_LY:
646	case REG_LYC:
647	case REG_DMA:
648	case REG_BGP:
649	case REG_OBP0:
650	case REG_OBP1:
651	case REG_WY:
652	case REG_WX:
653		// Handled transparently by the registers
654		break;
655	default:
656		if (gb->model >= GB_MODEL_CGB) {
657			switch (address) {
658			case REG_KEY1:
659			case REG_VBK:
660			case REG_HDMA1:
661			case REG_HDMA2:
662			case REG_HDMA3:
663			case REG_HDMA4:
664			case REG_HDMA5:
665			case REG_BCPS:
666			case REG_BCPD:
667			case REG_OCPS:
668			case REG_OCPD:
669			case REG_SVBK:
670				// Handled transparently by the registers
671				goto success;
672			default:
673				break;
674			}
675		}
676		mLOG(GB_IO, STUB, "Reading from unknown register FF%02X", address);
677		return 0xFF;
678	}
679	success:
680	return gb->memory.io[address] | _registerMask[address];
681}
682
683void GBTestKeypadIRQ(struct GB* gb) {
684	_readKeys(gb);
685}
686
687struct GBSerializedState;
688void GBIOSerialize(const struct GB* gb, struct GBSerializedState* state) {
689	memcpy(state->io, gb->memory.io, GB_SIZE_IO);
690	state->ie = gb->memory.ie;
691}
692
693void GBIODeserialize(struct GB* gb, const struct GBSerializedState* state) {
694	memcpy(gb->memory.io, state->io, GB_SIZE_IO);
695	gb->memory.ie = state->ie;
696
697	if (GBAudioEnableGetEnable(*gb->audio.nr52)) {
698		GBIOWrite(gb, REG_NR10, gb->memory.io[REG_NR10]);
699		GBIOWrite(gb, REG_NR11, gb->memory.io[REG_NR11]);
700		GBIOWrite(gb, REG_NR12, gb->memory.io[REG_NR12]);
701		GBIOWrite(gb, REG_NR13, gb->memory.io[REG_NR13]);
702		gb->audio.ch1.control.frequency &= 0xFF;
703		gb->audio.ch1.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[REG_NR14] << 8);
704		gb->audio.ch1.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR14] << 8);
705		GBIOWrite(gb, REG_NR21, gb->memory.io[REG_NR21]);
706		GBIOWrite(gb, REG_NR22, gb->memory.io[REG_NR22]);
707		GBIOWrite(gb, REG_NR22, gb->memory.io[REG_NR23]);
708		gb->audio.ch2.control.frequency &= 0xFF;
709		gb->audio.ch2.control.frequency |= GBAudioRegisterControlGetFrequency(gb->memory.io[REG_NR24] << 8);
710		gb->audio.ch2.control.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR24] << 8);
711		GBIOWrite(gb, REG_NR30, gb->memory.io[REG_NR30]);
712		GBIOWrite(gb, REG_NR31, gb->memory.io[REG_NR31]);
713		GBIOWrite(gb, REG_NR32, gb->memory.io[REG_NR32]);
714		GBIOWrite(gb, REG_NR32, gb->memory.io[REG_NR33]);
715		gb->audio.ch3.rate &= 0xFF;
716		gb->audio.ch3.rate |= GBAudioRegisterControlGetRate(gb->memory.io[REG_NR34] << 8);
717		gb->audio.ch3.stop = GBAudioRegisterControlGetStop(gb->memory.io[REG_NR34] << 8);
718		GBIOWrite(gb, REG_NR41, gb->memory.io[REG_NR41]);
719		GBIOWrite(gb, REG_NR42, gb->memory.io[REG_NR42]);
720		GBIOWrite(gb, REG_NR43, gb->memory.io[REG_NR43]);
721		gb->audio.ch4.stop = GBAudioRegisterNoiseControlGetStop(gb->memory.io[REG_NR44]);
722		GBIOWrite(gb, REG_NR50, gb->memory.io[REG_NR50]);
723		GBIOWrite(gb, REG_NR51, gb->memory.io[REG_NR51]);
724	}
725
726	gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_LCDC, state->io[REG_LCDC]);
727	gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCY, state->io[REG_SCY]);
728	gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_SCX, state->io[REG_SCX]);
729	gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WY, state->io[REG_WY]);
730	gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_WX, state->io[REG_WX]);
731	if (gb->model & GB_MODEL_SGB) {
732		gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_BGP, state->io[REG_BGP]);
733		gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP0, state->io[REG_OBP0]);
734		gb->video.renderer->writeVideoRegister(gb->video.renderer, REG_OBP1, state->io[REG_OBP1]);
735	}
736	gb->video.stat = state->io[REG_STAT];
737}