mirror of https://github.com/mgba-emu/mgba.git
Implement gyro
This commit is contained in:
parent
c77ed8c11e
commit
0458184a5e
|
@ -1,6 +1,7 @@
|
|||
#include "gba.h"
|
||||
|
||||
#include "gba-gpio.h"
|
||||
#include "gba-sensors.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue