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