all repos — mgba @ bac417d270b5259612bee9434e16de744f5e24a4

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);
 11
 12void GBIOInit(struct GB* gb) {
 13	memset(gb->memory.io, 0, sizeof(gb->memory.io));
 14}
 15
 16void GBIOReset(struct GB* gb) {
 17	memset(gb->memory.io, 0, sizeof(gb->memory.io));
 18
 19	GBIOWrite(gb, 0x05, 0);
 20	GBIOWrite(gb, 0x06, 0);
 21	GBIOWrite(gb, 0x07, 0);
 22	GBIOWrite(gb, 0x10, 0x80);
 23	GBIOWrite(gb, 0x11, 0xBF);
 24	GBIOWrite(gb, 0x12, 0xF3);
 25	GBIOWrite(gb, 0x12, 0xF3);
 26	GBIOWrite(gb, 0x14, 0xBF);
 27	GBIOWrite(gb, 0x16, 0x3F);
 28	GBIOWrite(gb, 0x17, 0x00);
 29	GBIOWrite(gb, 0x19, 0xBF);
 30	GBIOWrite(gb, 0x1A, 0x7F);
 31	GBIOWrite(gb, 0x1B, 0xFF);
 32	GBIOWrite(gb, 0x1C, 0x9F);
 33	GBIOWrite(gb, 0x1E, 0xBF);
 34	GBIOWrite(gb, 0x20, 0xFF);
 35	GBIOWrite(gb, 0x21, 0x00);
 36	GBIOWrite(gb, 0x22, 0x00);
 37	GBIOWrite(gb, 0x23, 0xBF);
 38	GBIOWrite(gb, 0x24, 0x77);
 39	GBIOWrite(gb, 0x25, 0xF3);
 40	GBIOWrite(gb, 0x26, 0xF1);
 41	GBIOWrite(gb, 0x40, 0x91);
 42	GBIOWrite(gb, 0x42, 0x00);
 43	GBIOWrite(gb, 0x43, 0x00);
 44	GBIOWrite(gb, 0x45, 0x00);
 45	GBIOWrite(gb, 0x47, 0xFC);
 46	GBIOWrite(gb, 0x48, 0xFF);
 47	GBIOWrite(gb, 0x49, 0xFF);
 48	GBIOWrite(gb, 0x4A, 0x00);
 49	GBIOWrite(gb, 0x4B, 0x00);
 50	GBIOWrite(gb, 0xFF, 0x00);
 51}
 52
 53void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
 54	switch (address) {
 55	case REG_DIV:
 56		GBTimerDivReset(&gb->timer);
 57		return;
 58	case REG_TIMA:
 59		// ???
 60		return;
 61	case REG_JOYP:
 62	case REG_TMA:
 63	case REG_LYC:
 64		// Handled transparently by the registers
 65		break;
 66	case REG_TAC:
 67		value = GBTimerUpdateTAC(&gb->timer, value);
 68		break;
 69	case REG_IF:
 70		gb->memory.io[REG_IF] = value | 0xE0;
 71		GBUpdateIRQs(gb);
 72		return;
 73	case REG_LCDC:
 74		// TODO: handle GBC differences
 75		value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
 76		GBVideoWriteLCDC(&gb->video, value);
 77		break;
 78	case REG_DMA:
 79		GBMemoryDMA(gb, value << 8);
 80		break;
 81	case REG_SCY:
 82	case REG_SCX:
 83	case REG_WY:
 84	case REG_WX:
 85	case REG_BGP:
 86	case REG_OBP0:
 87	case REG_OBP1:
 88		value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
 89		break;
 90	case REG_STAT:
 91		GBVideoWriteSTAT(&gb->video, value);
 92		break;
 93	case REG_IE:
 94		gb->memory.ie = value;
 95		GBUpdateIRQs(gb);
 96		return;
 97	default:
 98		mLOG(GB_MBC, STUB, "Writing to unknown register FF%02X:%02X", address, value);
 99		if (address >= GB_SIZE_IO) {
100			return;
101		}
102		break;
103	}
104	gb->memory.io[address] = value;
105}
106
107static uint8_t _readKeys(struct GB* gb) {
108	uint8_t keys = *gb->keySource;
109	switch (gb->memory.io[REG_JOYP] & 0x30) {
110	case 0x20:
111		keys >>= 4;
112		break;
113	case 0x10:
114		break;
115	default:
116		// ???
117		keys = 0;
118		break;
119	}
120	return 0xC0 | (gb->memory.io[REG_JOYP] | 0xF) ^ (keys & 0xF);
121}
122
123uint8_t GBIORead(struct GB* gb, unsigned address) {
124	switch (address) {
125	case REG_JOYP:
126		return _readKeys(gb);
127	case REG_IF:
128		break;
129	case REG_IE:
130		return gb->memory.ie;
131	case REG_DIV:
132	case REG_TIMA:
133	case REG_TMA:
134	case REG_TAC:
135	case REG_LCDC:
136	case REG_LY:
137	case REG_LYC:
138		// Handled transparently by the registers
139		break;
140	default:
141		mLOG(GB_MBC, STUB, "Reading from unknown register FF%02X", address);
142		if (address >= GB_SIZE_IO) {
143			return 0;
144		}
145		break;
146	}
147	return gb->memory.io[address];
148}