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