diff --git a/src/gba/gba-gpio.c b/src/gba/gba-gpio.c index 023f87849..ee073c53d 100644 --- a/src/gba/gba-gpio.c +++ b/src/gba/gba-gpio.c @@ -1,6 +1,7 @@ #include "gba.h" #include "gba-gpio.h" +#include "gba-sensors.h" #include @@ -13,6 +14,8 @@ 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 0, // Empty @@ -45,7 +48,7 @@ void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t valu 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 @@ void _outputPins(struct GBACartridgeGPIO* gpio, unsigned pins) { old &= gpio->direction; gpio->gpioBase[0] = old | (pins & ~gpio->direction & 0xF); } -}; +} + +// == RTC void _rtcReadPins(struct GBACartridgeGPIO* gpio) { // Transfer sequence: @@ -115,7 +124,7 @@ void _rtcReadPins(struct GBACartridgeGPIO* gpio) { // 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 @@ void _rtcProcessByte(struct GBACartridgeGPIO* gpio) { 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 @@ void _rtcProcessByte(struct GBACartridgeGPIO* gpio) { 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 @@ unsigned _rtcBCD(unsigned value) { 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; +} diff --git a/src/gba/gba-gpio.h b/src/gba/gba-gpio.h index 667057584..075c34d85 100644 --- a/src/gba/gba-gpio.h +++ b/src/gba/gba-gpio.h @@ -64,6 +64,7 @@ struct GBARTC { }; struct GBACartridgeGPIO { + struct GBA* p; int gpioDevices; enum GPIODirection readWrite; uint16_t* gpioBase; @@ -89,6 +90,9 @@ struct GBACartridgeGPIO { }; struct GBARTC rtc; + + uint16_t gyroSample; + int gyroEdge; }; void GBAGPIOInit(struct GBACartridgeGPIO* gpio, uint16_t* gpioBase); @@ -96,4 +100,6 @@ void GBAGPIOWrite(struct GBACartridgeGPIO* gpio, uint32_t address, uint16_t valu void GBAGPIOInitRTC(struct GBACartridgeGPIO* gpio); +void GBAGPIOInitGyro(struct GBACartridgeGPIO* gpio); + #endif diff --git a/src/gba/gba-memory.c b/src/gba/gba-memory.c index 233e7a81a..84de49c5f 100644 --- a/src/gba/gba-memory.c +++ b/src/gba/gba-memory.c @@ -34,6 +34,7 @@ void GBAMemoryInit(struct GBAMemory* memory) { 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)); diff --git a/src/gba/gba-sensors.h b/src/gba/gba-sensors.h new file mode 100644 index 000000000..926631f08 --- /dev/null +++ b/src/gba/gba-sensors.h @@ -0,0 +1,15 @@ +#ifndef GBA_SENSORS_H +#define GBA_SENSORS_H + +#include + +struct GBARotationSource { + void (*sample)(struct GBARotationSource*); + + int32_t (*readTiltX)(struct GBARotationSource*); + int32_t (*readTiltY)(struct GBARotationSource*); + + int32_t (*readGyroZ)(struct GBARotationSource*); +}; + +#endif diff --git a/src/gba/gba.c b/src/gba/gba.c index af42d866f..59f8ad9b9 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -33,6 +33,7 @@ static const struct GBACartridgeOverride _overrides[] = { { '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 @@ void GBAInit(struct GBA* gba) { gba->springIRQ = 0; gba->keySource = 0; + gba->rotationSource = 0; gba->logLevel = GBA_LOG_INFO | GBA_LOG_WARN | GBA_LOG_ERROR; @@ -485,6 +487,10 @@ void _checkOverrides(struct GBA* gba, uint32_t id) { if (_overrides[i].gpio & GPIO_RTC) { GBAGPIOInitRTC(&gba->memory.gpio); } + + if (_overrides[i].gpio & GPIO_GYRO) { + GBAGPIOInitGyro(&gba->memory.gpio); + } return; } } diff --git a/src/gba/gba.h b/src/gba/gba.h index 1683d1f94..355f836f7 100644 --- a/src/gba/gba.h +++ b/src/gba/gba.h @@ -54,6 +54,8 @@ enum GBAKey { GBA_KEY_L = 9 }; +struct GBARotationSource; + struct GBABoard { struct ARMBoard d; struct GBA* p; @@ -85,6 +87,7 @@ struct GBA { int springIRQ; int* keySource; + struct GBARotationSource* rotationSource; const char* activeFile; const char* savefile;