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