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