all repos — mgba @ 0458184a5e2ab6a852525c894a3a7d6a08595764

mGBA Game Boy Advance Emulator

Implement gyro
Jeffrey Pfau jeffrey@endrift.com
Mon, 21 Oct 2013 02:54:52 -0700
commit

0458184a5e2ab6a852525c894a3a7d6a08595764

parent

c77ed8c11e03a2bb22bfb8111ac2d4fb8698d786

M src/gba/gba-gpio.csrc/gba/gba-gpio.c

@@ -1,6 +1,7 @@

#include "gba.h" #include "gba-gpio.h" +#include "gba-sensors.h" #include <time.h>

@@ -12,6 +13,8 @@ static unsigned _rtcOutput(struct GBACartridgeGPIO* gpio);

static void _rtcProcessByte(struct GBACartridgeGPIO* gpio); static void _rtcUpdateClock(struct GBACartridgeGPIO* gpio); static unsigned _rtcBCD(unsigned value); + +static void _gyroReadPins(struct GBACartridgeGPIO* gpio); static const int RTC_BYTES[8] = { 0, // Force reset

@@ -45,7 +48,7 @@ case GPIO_REG_CONTROL:

gpio->readWrite = value; break; default: - GBALog(0, GBA_LOG_WARN, "Invalid GPIO address"); + GBALog(gpio->p, GBA_LOG_WARN, "Invalid GPIO address"); } if (gpio->readWrite) {

@@ -73,6 +76,10 @@ void _readPins(struct GBACartridgeGPIO* gpio) {

if (gpio->gpioDevices & GPIO_RTC) { _rtcReadPins(gpio); } + + if (gpio->gpioDevices & GPIO_GYRO) { + _gyroReadPins(gpio); + } } void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins) {

@@ -81,7 +88,9 @@ uint16_t old = gpio->gpioBase[0];

old &= gpio->direction; gpio->gpioBase[0] = old | (pins & ~gpio->direction & 0xF); } -}; +} + +// == RTC void _rtcReadPins(struct GBACartridgeGPIO* gpio) { // Transfer sequence:

@@ -115,7 +124,7 @@ if (gpio->p2) {

// GPIO direction should always != reading if (gpio->dir1) { if (gpio->rtc.command.reading) { - GBALog(0, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode"); + GBALog(gpio->p, GBA_LOG_GAME_ERROR, "Attempting to write to RTC while in read mode"); } ++gpio->rtc.bitsRead; if (gpio->rtc.bitsRead == 8) {

@@ -168,7 +177,7 @@ case RTC_CONTROL:

break; } } else { - GBALog(0, GBA_LOG_WARN, "Invalid RTC command byte: %02X", gpio->rtc.bits); + GBALog(gpio->p, GBA_LOG_WARN, "Invalid RTC command byte: %02X", gpio->rtc.bits); } } else { switch (gpio->rtc.command.command) {

@@ -176,7 +185,7 @@ case RTC_CONTROL:

gpio->rtc.control.packed = gpio->rtc.bits; break; case RTC_FORCE_IRQ: - GBALog(0, GBA_LOG_STUB, "Unimplemented RTC command %u", gpio->rtc.command.command); + GBALog(gpio->p, GBA_LOG_STUB, "Unimplemented RTC command %u", gpio->rtc.command.command); break; case RTC_RESET: case RTC_DATETIME:

@@ -234,3 +243,38 @@ value /= 10;

counter += (value % 10) << 4; return counter; } + +// == Gyro + +void GBAGPIOInitGyro(struct GBACartridgeGPIO* gpio) { + gpio->gpioDevices |= GPIO_GYRO; + gpio->gyroSample = 0; + gpio->gyroEdge = 0; +} + + +void _gyroReadPins(struct GBACartridgeGPIO* gpio) { + struct GBARotationSource* gyro = gpio->p->rotationSource; + if (!gyro) { + return; + } + + if (gpio->p0) { + if (gyro->sample) { + gyro->sample(gyro); + } + int32_t sample = gyro->readGyroZ(gyro); + + // Normalize to ~12 bits, focused on 0x6C0 + gpio->gyroSample = (sample >> 21) + 0x6C0; // Crop off an extra bit so that we can't go negative + } + + if (gpio->gyroEdge && !gpio->p1) { + // Write bit on falling edge + unsigned bit = gpio->gyroSample >> 15; + gpio->gyroSample <<= 1; + _outputPins(gpio, bit << 2); + } + + gpio->gyroEdge = gpio->p1; +}
M src/gba/gba-gpio.hsrc/gba/gba-gpio.h

@@ -64,6 +64,7 @@ uint8_t time[7];

}; struct GBACartridgeGPIO { + struct GBA* p; int gpioDevices; enum GPIODirection readWrite; uint16_t* gpioBase;

@@ -89,11 +90,16 @@ uint16_t direction;

}; struct GBARTC rtc; + + uint16_t gyroSample; + int gyroEdge; }; void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* gpioBase); void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t value); void GBAGPIOInitRTC(struct GBACartridgeGPIO* gpio); + +void GBAGPIOInitGyro(struct GBACartridgeGPIO* gpio); #endif
M src/gba/gba-memory.csrc/gba/gba-memory.c

@@ -34,6 +34,7 @@ memory->fullBios = 0;

memory->wram = mmap(0, SIZE_WORKING_RAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); memory->iwram = mmap(0, SIZE_WORKING_IRAM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); memory->rom = 0; + memory->gpio.p = memory->p; memset(memory->io, 0, sizeof(memory->io)); memset(memory->dma, 0, sizeof(memory->dma));
A src/gba/gba-sensors.h

@@ -0,0 +1,15 @@

+#ifndef GBA_SENSORS_H +#define GBA_SENSORS_H + +#include <stdint.h> + +struct GBARotationSource { + void (*sample)(struct GBARotationSource*); + + int32_t (*readTiltX)(struct GBARotationSource*); + int32_t (*readTiltY)(struct GBARotationSource*); + + int32_t (*readGyroZ)(struct GBARotationSource*); +}; + +#endif
M src/gba/gba.csrc/gba/gba.c

@@ -33,6 +33,7 @@ { 'EPXA', SAVEDATA_FLASH1M, GPIO_RTC },

{ 'EVXA', SAVEDATA_FLASH1M, GPIO_RTC }, { 'E4XA', SAVEDATA_FLASH1M, GPIO_NONE }, { 'EEPB', SAVEDATA_FLASH1M, GPIO_RTC }, + { 'EWZR', SAVEDATA_SRAM, GPIO_RUMBLE | GPIO_GYRO }, { 0, 0, 0 } };

@@ -69,6 +70,7 @@ memset(gba->timers, 0, sizeof(gba->timers));

gba->springIRQ = 0; gba->keySource = 0; + gba->rotationSource = 0; gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR;

@@ -484,6 +486,10 @@ }

if (_overrides[i].gpio & GPIO_RTC) { GBAGPIOInitRTC(&gba->memory.gpio); + } + + if (_overrides[i].gpio & GPIO_GYRO) { + GBAGPIOInitGyro(&gba->memory.gpio); } return; }
M src/gba/gba.hsrc/gba/gba.h

@@ -54,6 +54,8 @@ GBA_KEY_R = 8,

GBA_KEY_L = 9 }; +struct GBARotationSource; + struct GBABoard { struct ARMBoard d; struct GBA* p;

@@ -85,6 +87,7 @@ } timers[4];

int springIRQ; int* keySource; + struct GBARotationSource* rotationSource; const char* activeFile; const char* savefile;