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