src/gba/gba-gpio.c (view raw)
1/* Copyright (c) 2013-2014 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 "gba.h"
7
8#include "gba-gpio.h"
9#include "gba-sensors.h"
10#include "gba-serialize.h"
11
12#include <time.h>
13
14static void _readPins(struct GBACartridgeGPIO* gpio);
15static void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins);
16
17static void _rtcReadPins(struct GBACartridgeGPIO* gpio);
18static unsigned _rtcOutput(struct GBACartridgeGPIO* gpio);
19static void _rtcProcessByte(struct GBACartridgeGPIO* gpio);
20static void _rtcUpdateClock(struct GBACartridgeGPIO* gpio);
21static unsigned _rtcBCD(unsigned value);
22
23static void _gyroReadPins(struct GBACartridgeGPIO* gpio);
24
25static void _rumbleReadPins(struct GBACartridgeGPIO* gpio);
26
27static void _lightReadPins(struct GBACartridgeGPIO* gpio);
28
29static const int RTC_BYTES[8] = {
30 0, // Force reset
31 0, // Empty
32 7, // Date/Time
33 0, // Force IRQ
34 1, // Control register
35 0, // Empty
36 3, // Time
37 0 // Empty
38};
39
40void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* base) {
41 gpio->gpioDevices = GPIO_NONE;
42 gpio->direction = GPIO_WRITE_ONLY;
43 gpio->gpioBase = base;
44 gpio->pinState = 0;
45 gpio->direction = 0;
46}
47
48void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t value) {
49 switch (address) {
50 case GPIO_REG_DATA:
51 gpio->pinState &= ~gpio->direction;
52 gpio->pinState |= value;
53 if (gpio->readWrite) {
54 uint16_t old = gpio->gpioBase[0];
55 old &= ~gpio->direction;
56 gpio->gpioBase[0] = old | gpio->pinState;
57 }
58 _readPins(gpio);
59 break;
60 case GPIO_REG_DIRECTION:
61 gpio->direction = value;
62 break;
63 case GPIO_REG_CONTROL:
64 gpio->readWrite = value;
65 break;
66 default:
67 GBALog(gpio->p, GBA_LOG_WARN, "Invalid GPIO address");
68 }
69}
70
71void GBAGPIOInitRTC(struct GBACartridgeGPIO* gpio) {
72 gpio->gpioDevices |= GPIO_RTC;
73 gpio->rtc.bytesRemaining = 0;
74
75 gpio->rtc.transferStep = 0;
76
77 gpio->rtc.bitsRead = 0;
78 gpio->rtc.bits = 0;
79 gpio->rtc.commandActive = 0;
80 gpio->rtc.command.packed = 0;
81 gpio->rtc.control.packed = 0x40;
82 memset(gpio->rtc.time, 0, sizeof(gpio->rtc.time));
83}
84
85void _readPins(struct GBACartridgeGPIO* gpio) {
86 if (gpio->gpioDevices & GPIO_RTC) {
87 _rtcReadPins(gpio);
88 }
89
90 if (gpio->gpioDevices & GPIO_GYRO) {
91 _gyroReadPins(gpio);
92 }
93
94 if (gpio->gpioDevices & GPIO_RUMBLE) {
95 _rumbleReadPins(gpio);
96 }
97
98 if (gpio->gpioDevices & GPIO_LIGHT_SENSOR) {
99 _lightReadPins(gpio);
100 }
101}
102
103void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins) {
104 if (gpio->readWrite) {
105 uint16_t old = gpio->gpioBase[0];
106 old &= gpio->direction;
107 gpio->pinState = old | (pins & ~gpio->direction & 0xF);
108 gpio->gpioBase[0] = gpio->pinState;
109 }
110}
111
112// == RTC
113
114void _rtcReadPins(struct GBACartridgeGPIO* gpio) {
115 // Transfer sequence:
116 // P: 0 | 1 | 2 | 3
117 // == Initiate
118 // > HI | - | LO | -
119 // > HI | - | HI | -
120 // == Transfer bit (x8)
121 // > LO | x | HI | -
122 // > HI | - | HI | -
123 // < ?? | x | ?? | -
124 // == Terminate
125 // > - | - | LO | -
126 switch (gpio->rtc.transferStep) {
127 case 0:
128 if ((gpio->pinState & 5) == 1) {
129 gpio->rtc.transferStep = 1;
130 }
131 break;
132 case 1:
133 if ((gpio->pinState & 5) == 5) {
134 gpio->rtc.transferStep = 2;
135 }
136 break;
137 case 2:
138 if (!gpio->p0) {
139 gpio->rtc.bits &= ~(1 << gpio->rtc.bitsRead);
140 gpio->rtc.bits |= gpio->p1 << gpio->rtc.bitsRead;
141 } else {
142 if (gpio->p2) {
143 // GPIO direction should always != reading
144 if (gpio->dir1) {
145 if (gpio->rtc.command.reading) {
146 GBALog(gpio->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode");
147 }
148 ++gpio->rtc.bitsRead;
149 if (gpio->rtc.bitsRead == 8) {
150 _rtcProcessByte(gpio);
151 }
152 } else {
153 _outputPins(gpio, 5 | (_rtcOutput(gpio) << 1));
154 ++gpio->rtc.bitsRead;
155 if (gpio->rtc.bitsRead == 8) {
156 --gpio->rtc.bytesRemaining;
157 if (gpio->rtc.bytesRemaining <= 0) {
158 gpio->rtc.commandActive = 0;
159 gpio->rtc.command.reading = 0;
160 }
161 gpio->rtc.bitsRead = 0;
162 }
163 }
164 } else {
165 gpio->rtc.bitsRead = 0;
166 gpio->rtc.bytesRemaining = 0;
167 gpio->rtc.commandActive = 0;
168 gpio->rtc.command.reading = 0;
169 gpio->rtc.transferStep = 0;
170 }
171 }
172 break;
173 }
174}
175
176void _rtcProcessByte(struct GBACartridgeGPIO* gpio) {
177 --gpio->rtc.bytesRemaining;
178 if (!gpio->rtc.commandActive) {
179 union RTCCommandData command;
180 command.packed = gpio->rtc.bits;
181 if (command.magic == 0x06) {
182 gpio->rtc.command = command;
183
184 gpio->rtc.bytesRemaining = RTC_BYTES[gpio->rtc.command.command];
185 gpio->rtc.commandActive = gpio->rtc.bytesRemaining > 0;
186 switch (command.command) {
187 case RTC_RESET:
188 gpio->rtc.control.packed = 0;
189 break;
190 case RTC_DATETIME:
191 case RTC_TIME:
192 _rtcUpdateClock(gpio);
193 break;
194 case RTC_FORCE_IRQ:
195 case RTC_CONTROL:
196 break;
197 }
198 } else {
199 GBALog(gpio->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", gpio->rtc.bits);
200 }
201 } else {
202 switch (gpio->rtc.command.command) {
203 case RTC_CONTROL:
204 gpio->rtc.control.packed = gpio->rtc.bits;
205 break;
206 case RTC_FORCE_IRQ:
207 GBALog(gpio->p, GBA_LOG_STUB, "Unimplemented RTC command %u", gpio->rtc.command.command);
208 break;
209 case RTC_RESET:
210 case RTC_DATETIME:
211 case RTC_TIME:
212 break;
213 }
214 }
215
216 gpio->rtc.bits = 0;
217 gpio->rtc.bitsRead = 0;
218 if (!gpio->rtc.bytesRemaining) {
219 gpio->rtc.commandActive = 0;
220 gpio->rtc.command.reading = 0;
221 }
222}
223
224unsigned _rtcOutput(struct GBACartridgeGPIO* gpio) {
225 uint8_t outputByte = 0;
226 switch (gpio->rtc.command.command) {
227 case RTC_CONTROL:
228 outputByte = gpio->rtc.control.packed;
229 break;
230 case RTC_DATETIME:
231 case RTC_TIME:
232 outputByte = gpio->rtc.time[7 - gpio->rtc.bytesRemaining];
233 break;
234 case RTC_FORCE_IRQ:
235 case RTC_RESET:
236 break;
237 }
238 unsigned output = (outputByte >> gpio->rtc.bitsRead) & 1;
239 return output;
240}
241
242void _rtcUpdateClock(struct GBACartridgeGPIO* gpio) {
243 time_t t = time(0);
244 struct tm date;
245#ifdef _WIN32
246 date = *localtime(&t);
247#else
248 localtime_r(&t, &date);
249#endif
250 gpio->rtc.time[0] = _rtcBCD(date.tm_year - 100);
251 gpio->rtc.time[1] = _rtcBCD(date.tm_mon + 1);
252 gpio->rtc.time[2] = _rtcBCD(date.tm_mday);
253 gpio->rtc.time[3] = _rtcBCD(date.tm_wday);
254 if (gpio->rtc.control.hour24) {
255 gpio->rtc.time[4] = _rtcBCD(date.tm_hour);
256 } else {
257 gpio->rtc.time[4] = _rtcBCD(date.tm_hour % 12);
258 }
259 gpio->rtc.time[5] = _rtcBCD(date.tm_min);
260 gpio->rtc.time[6] = _rtcBCD(date.tm_sec);
261}
262
263unsigned _rtcBCD(unsigned value) {
264 int counter = value % 10;
265 value /= 10;
266 counter += (value % 10) << 4;
267 return counter;
268}
269
270// == Gyro
271
272void GBAGPIOInitGyro(struct GBACartridgeGPIO* gpio) {
273 gpio->gpioDevices |= GPIO_GYRO;
274 gpio->gyroSample = 0;
275 gpio->gyroEdge = 0;
276}
277
278void _gyroReadPins(struct GBACartridgeGPIO* gpio) {
279 struct GBARotationSource* gyro = gpio->p->rotationSource;
280 if (!gyro) {
281 return;
282 }
283
284 if (gpio->p0) {
285 if (gyro->sample) {
286 gyro->sample(gyro);
287 }
288 int32_t sample = gyro->readGyroZ(gyro);
289
290 // Normalize to ~12 bits, focused on 0x6C0
291 gpio->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative
292 }
293
294 if (gpio->gyroEdge && !gpio->p1) {
295 // Write bit on falling edge
296 unsigned bit = gpio->gyroSample >> 15;
297 gpio->gyroSample <<= 1;
298 _outputPins(gpio, bit << 2);
299 }
300
301 gpio->gyroEdge = gpio->p1;
302}
303
304// == Rumble
305
306void GBAGPIOInitRumble(struct GBACartridgeGPIO* gpio) {
307 gpio->gpioDevices |= GPIO_RUMBLE;
308}
309
310void _rumbleReadPins(struct GBACartridgeGPIO* gpio) {
311 struct GBARumble* rumble = gpio->p->rumble;
312 if (!rumble) {
313 return;
314 }
315
316 rumble->setRumble(rumble, gpio->p3);
317}
318
319// == Light sensor
320
321void GBAGPIOInitLightSensor(struct GBACartridgeGPIO* gpio) {
322 gpio->gpioDevices |= GPIO_LIGHT_SENSOR;
323 gpio->lightCounter = 0;
324 gpio->lightEdge = false;
325 gpio->lightSample = 0xFF;
326}
327
328void _lightReadPins(struct GBACartridgeGPIO* gpio) {
329 if (gpio->p2) {
330 // Boktai chip select
331 return;
332 }
333 if (gpio->p1) {
334 struct GBALuminanceSource* lux = gpio->p->luminanceSource;
335 GBALog(0, GBA_LOG_DEBUG, "[SOLAR] Got reset");
336 gpio->lightCounter = 0;
337 if (lux) {
338 lux->sample(lux);
339 gpio->lightSample = lux->readLuminance(lux);
340 } else {
341 gpio->lightSample = 0xFF;
342 }
343 }
344 if (gpio->p0 && gpio->lightEdge) {
345 ++gpio->lightCounter;
346 }
347 gpio->lightEdge = !gpio->p0;
348
349 bool sendBit = gpio->lightCounter >= gpio->lightSample;
350 _outputPins(gpio, sendBit << 3);
351 GBALog(0, GBA_LOG_DEBUG, "[SOLAR] Output %u with pins %u", gpio->lightCounter, gpio->pinState);
352}
353
354// == Serialization
355
356void GBAGPIOSerialize(struct GBACartridgeGPIO* gpio, struct GBASerializedState* state) {
357 state->gpio.readWrite = gpio->readWrite;
358 state->gpio.pinState = gpio->pinState;
359 state->gpio.pinDirection = gpio->direction;
360 state->gpio.devices = gpio->gpioDevices;
361 state->gpio.rtc = gpio->rtc;
362 state->gpio.gyroSample = gpio->gyroSample;
363 state->gpio.gyroEdge = gpio->gyroEdge;
364}
365
366void GBAGPIODeserialize(struct GBACartridgeGPIO* gpio, struct GBASerializedState* state) {
367 gpio->readWrite = state->gpio.readWrite;
368 gpio->pinState = state->gpio.pinState;
369 gpio->direction = state->gpio.pinDirection;
370 // TODO: Deterministic RTC
371 gpio->rtc = state->gpio.rtc;
372 gpio->gyroSample = state->gpio.gyroSample;
373 gpio->gyroEdge = state->gpio.gyroEdge;
374}