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_JOYP:
59 case REG_TIMA:
60 case REG_TMA:
61 case REG_LYC:
62 // Handled transparently by the registers
63 break;
64 case REG_TAC:
65 value = GBTimerUpdateTAC(&gb->timer, value);
66 break;
67 case REG_IF:
68 gb->memory.io[REG_IF] = value | 0xE0;
69 GBUpdateIRQs(gb);
70 return;
71 case REG_LCDC:
72 // TODO: handle GBC differences
73 value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
74 GBVideoWriteLCDC(&gb->video, value);
75 break;
76 case REG_DMA:
77 GBMemoryDMA(gb, value << 8);
78 break;
79 case REG_SCY:
80 case REG_SCX:
81 case REG_WY:
82 case REG_WX:
83 case REG_BGP:
84 case REG_OBP0:
85 case REG_OBP1:
86 value = gb->video.renderer->writeVideoRegister(gb->video.renderer, address, value);
87 break;
88 case REG_STAT:
89 GBVideoWriteSTAT(&gb->video, value);
90 break;
91 case REG_IE:
92 gb->memory.ie = value;
93 GBUpdateIRQs(gb);
94 return;
95 default:
96 mLOG(GB_MBC, STUB, "Writing to unknown register FF%02X:%02X", address, value);
97 if (address >= GB_SIZE_IO) {
98 return;
99 }
100 break;
101 }
102 gb->memory.io[address] = value;
103}
104
105static uint8_t _readKeys(struct GB* gb) {
106 uint8_t keys = *gb->keySource;
107 switch (gb->memory.io[REG_JOYP] & 0x30) {
108 case 0x20:
109 keys >>= 4;
110 break;
111 case 0x10:
112 break;
113 default:
114 // ???
115 keys = 0;
116 break;
117 }
118 return 0xC0 | (gb->memory.io[REG_JOYP] | 0xF) ^ (keys & 0xF);
119}
120
121uint8_t GBIORead(struct GB* gb, unsigned address) {
122 switch (address) {
123 case REG_JOYP:
124 return _readKeys(gb);
125 case REG_IF:
126 break;
127 case REG_IE:
128 return gb->memory.ie;
129 case REG_DIV:
130 case REG_TIMA:
131 case REG_TMA:
132 case REG_TAC:
133 case REG_STAT:
134 case REG_LCDC:
135 case REG_SCY:
136 case REG_SCX:
137 case REG_LY:
138 case REG_LYC:
139 // Handled transparently by the registers
140 break;
141 default:
142 mLOG(GB_MBC, STUB, "Reading from unknown register FF%02X", address);
143 if (address >= GB_SIZE_IO) {
144 return 0;
145 }
146 break;
147 }
148 return gb->memory.io[address];
149}