mirror of https://github.com/mgba-emu/mgba.git
GBA Cart: Refactor hardware.c into cart/gpio.c etc
This commit is contained in:
parent
9a192d9ab1
commit
bc16a1bfe3
|
@ -13,13 +13,10 @@ CXX_GUARD_START
|
|||
#include <mgba/core/log.h>
|
||||
#include <mgba/core/timing.h>
|
||||
#include <mgba/gba/interface.h>
|
||||
#include <mgba/internal/gba/cart/ereader.h>
|
||||
|
||||
mLOG_DECLARE_CATEGORY(GBA_HW);
|
||||
|
||||
#define EREADER_DOTCODE_STRIDE 1420
|
||||
#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40)
|
||||
#define EREADER_CARDS_MAX 16
|
||||
|
||||
#define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL)
|
||||
|
||||
struct GBARTCGenericSource {
|
||||
|
@ -82,57 +79,8 @@ struct GBARTC {
|
|||
uint8_t time[7];
|
||||
};
|
||||
|
||||
struct GBAGBPKeyCallback {
|
||||
struct mKeyCallback d;
|
||||
struct GBACartridgeHardware* p;
|
||||
};
|
||||
|
||||
struct GBAGBPSIODriver {
|
||||
struct GBASIODriver d;
|
||||
struct GBACartridgeHardware* p;
|
||||
};
|
||||
|
||||
DECL_BITFIELD(GPIOPin, uint16_t);
|
||||
|
||||
DECL_BITFIELD(EReaderControl0, uint8_t);
|
||||
DECL_BIT(EReaderControl0, Data, 0);
|
||||
DECL_BIT(EReaderControl0, Clock, 1);
|
||||
DECL_BIT(EReaderControl0, Direction, 2);
|
||||
DECL_BIT(EReaderControl0, LedEnable, 3);
|
||||
DECL_BIT(EReaderControl0, Scan, 4);
|
||||
DECL_BIT(EReaderControl0, Phi, 5);
|
||||
DECL_BIT(EReaderControl0, PowerEnable, 6);
|
||||
DECL_BITFIELD(EReaderControl1, uint8_t);
|
||||
DECL_BIT(EReaderControl1, Scanline, 1);
|
||||
DECL_BIT(EReaderControl1, Unk1, 4);
|
||||
DECL_BIT(EReaderControl1, Voltage, 5);
|
||||
|
||||
enum EReaderStateMachine {
|
||||
EREADER_SERIAL_INACTIVE = 0,
|
||||
EREADER_SERIAL_STARTING,
|
||||
EREADER_SERIAL_BIT_0,
|
||||
EREADER_SERIAL_BIT_1,
|
||||
EREADER_SERIAL_BIT_2,
|
||||
EREADER_SERIAL_BIT_3,
|
||||
EREADER_SERIAL_BIT_4,
|
||||
EREADER_SERIAL_BIT_5,
|
||||
EREADER_SERIAL_BIT_6,
|
||||
EREADER_SERIAL_BIT_7,
|
||||
EREADER_SERIAL_END_BIT,
|
||||
};
|
||||
|
||||
enum EReaderCommand {
|
||||
EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware
|
||||
EREADER_COMMAND_WRITE_DATA = 1,
|
||||
EREADER_COMMAND_SET_INDEX = 0x22,
|
||||
EREADER_COMMAND_READ_DATA = 0x23,
|
||||
};
|
||||
|
||||
struct EReaderCard {
|
||||
void* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct GBACartridgeHardware {
|
||||
struct GBA* p;
|
||||
uint32_t devices;
|
||||
|
@ -155,12 +103,6 @@ struct GBACartridgeHardware {
|
|||
uint16_t tiltY;
|
||||
int tiltState;
|
||||
|
||||
unsigned gbpInputsPosted;
|
||||
int gbpTxPosition;
|
||||
struct mTimingEvent gbpNextEvent;
|
||||
struct GBAGBPKeyCallback gbpCallback;
|
||||
struct GBAGBPSIODriver gbpDriver;
|
||||
|
||||
uint16_t eReaderData[44];
|
||||
uint8_t eReaderSerial[92];
|
||||
uint16_t eReaderRegisterUnk;
|
||||
|
@ -193,17 +135,6 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* gpio, uint32_t address, u
|
|||
void GBAHardwareTiltWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint8_t value);
|
||||
uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* gpio, uint32_t address);
|
||||
|
||||
struct GBAVideo;
|
||||
void GBAHardwarePlayerUpdate(struct GBA* gba);
|
||||
bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video);
|
||||
|
||||
void GBAHardwareInitEReader(struct GBACartridgeHardware* hw);
|
||||
void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value);
|
||||
void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value);
|
||||
uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address);
|
||||
uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address);
|
||||
void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size);
|
||||
|
||||
void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba);
|
||||
|
||||
struct GBASerializedState;
|
|
@ -14,10 +14,10 @@ CXX_GUARD_START
|
|||
|
||||
#include <mgba/internal/arm/arm.h>
|
||||
#include <mgba/internal/gba/dma.h>
|
||||
#include <mgba/internal/gba/hardware.h>
|
||||
#include <mgba/internal/gba/savedata.h>
|
||||
#include <mgba/internal/gba/vfame.h>
|
||||
#include <mgba/internal/gba/matrix.h>
|
||||
#include <mgba/internal/gba/cart/gpio.h>
|
||||
#include <mgba/internal/gba/cart/matrix.h>
|
||||
#include <mgba/internal/gba/cart/vfame.h>
|
||||
|
||||
enum GBAMemoryRegion {
|
||||
REGION_BIOS = 0x0,
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/gba/interface.h>
|
||||
#include <mgba/core/log.h>
|
||||
#include <mgba/gba/interface.h>
|
||||
#include <mgba/internal/gba/sio/gbp.h>
|
||||
|
||||
#define MAX_GBAS 4
|
||||
|
||||
|
@ -69,6 +70,8 @@ struct GBASIO {
|
|||
|
||||
uint16_t rcnt;
|
||||
uint16_t siocnt;
|
||||
|
||||
struct GBASIOPlayer gbp;
|
||||
};
|
||||
|
||||
void GBASIOInit(struct GBASIO* sio);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (c) 2013-2021 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef GBA_GBP_H
|
||||
#define GBA_GBP_H
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
struct GBASIOPlayer;
|
||||
struct GBASIOPlayerKeyCallback {
|
||||
struct mKeyCallback d;
|
||||
struct GBASIOPlayer* p;
|
||||
};
|
||||
|
||||
struct GBASIOPlayer {
|
||||
struct GBASIODriver d;
|
||||
struct GBA* p;
|
||||
unsigned inputsPosted;
|
||||
int txPosition;
|
||||
struct mTimingEvent event;
|
||||
struct GBASIOPlayerKeyCallback callback;
|
||||
};
|
||||
|
||||
void GBASIOPlayerInit(struct GBASIOPlayer* gbp);
|
||||
void GBASIOPlayerReset(struct GBASIOPlayer* gbp);
|
||||
|
||||
struct GBAVideo;
|
||||
void GBASIOPlayerUpdate(struct GBA* gba);
|
||||
bool GBASIOPlayerCheckScreen(const struct GBAVideo* video);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
|
@ -3,19 +3,20 @@ set(SOURCE_FILES
|
|||
../gb/audio.c
|
||||
audio.c
|
||||
bios.c
|
||||
cart/ereader.c
|
||||
cart/gpio.c
|
||||
cart/matrix.c
|
||||
cart/vfame.c
|
||||
cheats.c
|
||||
cheats/codebreaker.c
|
||||
cheats/gameshark.c
|
||||
cheats/parv3.c
|
||||
core.c
|
||||
dma.c
|
||||
ereader.c
|
||||
gba.c
|
||||
hardware.c
|
||||
hle-bios.c
|
||||
input.c
|
||||
io.c
|
||||
matrix.c
|
||||
memory.c
|
||||
overrides.c
|
||||
renderers/cache-set.c
|
||||
|
@ -29,13 +30,13 @@ set(SOURCE_FILES
|
|||
serialize.c
|
||||
sharkport.c
|
||||
sio.c
|
||||
sio/gbp.c
|
||||
sio/joybus.c
|
||||
timer.c
|
||||
vfame.c
|
||||
video.c)
|
||||
|
||||
set(SIO_FILES
|
||||
sio/dolphin.c
|
||||
sio/joybus.c
|
||||
sio/lockstep.c)
|
||||
|
||||
set(EXTRA_FILES
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/hardware.h>
|
||||
#include <mgba/internal/gba/cart/ereader.h>
|
||||
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/gba/gba.h>
|
|
@ -1,9 +1,9 @@
|
|||
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||
/* Copyright (c) 2013-2021 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/hardware.h>
|
||||
#include <mgba/internal/gba/cart/gpio.h>
|
||||
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/gba/io.h>
|
||||
|
@ -33,10 +33,6 @@ static void _rumbleReadPins(struct GBACartridgeHardware* hw);
|
|||
|
||||
static void _lightReadPins(struct GBACartridgeHardware* hw);
|
||||
|
||||
static uint16_t _gbpRead(struct mKeyCallback*);
|
||||
static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
|
||||
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
|
||||
static const int RTC_BYTES[8] = {
|
||||
0, // Force reset
|
||||
0, // Empty
|
||||
|
@ -53,19 +49,6 @@ void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) {
|
|||
hw->eReaderDots = NULL;
|
||||
memset(hw->eReaderCards, 0, sizeof(hw->eReaderCards));
|
||||
GBAHardwareClear(hw);
|
||||
|
||||
hw->gbpCallback.d.readKeys = _gbpRead;
|
||||
hw->gbpCallback.p = hw;
|
||||
hw->gbpDriver.d.init = 0;
|
||||
hw->gbpDriver.d.deinit = 0;
|
||||
hw->gbpDriver.d.load = 0;
|
||||
hw->gbpDriver.d.unload = 0;
|
||||
hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister;
|
||||
hw->gbpDriver.p = hw;
|
||||
hw->gbpNextEvent.context = &hw->gbpDriver;
|
||||
hw->gbpNextEvent.name = "GBA SIO Game Boy Player";
|
||||
hw->gbpNextEvent.callback = _gbpSioProcessEvents;
|
||||
hw->gbpNextEvent.priority = 0x80;
|
||||
}
|
||||
|
||||
void GBAHardwareClear(struct GBACartridgeHardware* hw) {
|
||||
|
@ -87,10 +70,6 @@ void GBAHardwareClear(struct GBACartridgeHardware* hw) {
|
|||
hw->eReaderCards[i].data = NULL;
|
||||
hw->eReaderCards[i].size = 0;
|
||||
}
|
||||
|
||||
if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) {
|
||||
GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32);
|
||||
}
|
||||
}
|
||||
|
||||
void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) {
|
||||
|
@ -504,124 +483,10 @@ uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) {
|
|||
return 0xFF;
|
||||
}
|
||||
|
||||
// == Game Boy Player
|
||||
|
||||
static const uint8_t _logoPalette[] = {
|
||||
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
|
||||
0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED,
|
||||
0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72,
|
||||
0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B,
|
||||
0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F,
|
||||
0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2,
|
||||
0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const uint32_t _logoHash = 0xEEDA6963;
|
||||
|
||||
static const uint32_t _gbpTxData[] = {
|
||||
0x0000494E, 0x0000494E,
|
||||
0xB6B1494E, 0xB6B1544E,
|
||||
0xABB1544E, 0xABB14E45,
|
||||
0xB1BA4E45, 0xB1BA4F44,
|
||||
0xB0BB4F44, 0xB0BB8002,
|
||||
0x10000010, 0x20000013,
|
||||
0x30000003
|
||||
};
|
||||
|
||||
bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) {
|
||||
if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
|
||||
return hash == _logoHash;
|
||||
}
|
||||
|
||||
void GBAHardwarePlayerUpdate(struct GBA* gba) {
|
||||
if (gba->memory.hw.devices & HW_GB_PLAYER) {
|
||||
if (GBAHardwarePlayerCheckScreen(&gba->video)) {
|
||||
++gba->memory.hw.gbpInputsPosted;
|
||||
gba->memory.hw.gbpInputsPosted %= 3;
|
||||
gba->keyCallback = &gba->memory.hw.gbpCallback.d;
|
||||
} else {
|
||||
// TODO: Save and restore
|
||||
gba->keyCallback = 0;
|
||||
}
|
||||
gba->memory.hw.gbpTxPosition = 0;
|
||||
return;
|
||||
}
|
||||
if (gba->keyCallback) {
|
||||
return;
|
||||
}
|
||||
if (GBAHardwarePlayerCheckScreen(&gba->video)) {
|
||||
gba->memory.hw.devices |= HW_GB_PLAYER;
|
||||
gba->memory.hw.gbpInputsPosted = 0;
|
||||
gba->keyCallback = &gba->memory.hw.gbpCallback.d;
|
||||
// TODO: Check if the SIO driver is actually used first
|
||||
GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t _gbpRead(struct mKeyCallback* callback) {
|
||||
struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback;
|
||||
if (gbpCallback->p->gbpInputsPosted == 2) {
|
||||
return 0xF0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
|
||||
struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver;
|
||||
if (address == REG_SIOCNT) {
|
||||
if (value & 0x0080) {
|
||||
uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
|
||||
if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) {
|
||||
// TODO: Check expected
|
||||
} else if (gbp->p->gbpTxPosition >= 12) {
|
||||
uint32_t mask = 0x33;
|
||||
// 0x00 = Stop
|
||||
// 0x11 = Hard Stop
|
||||
// 0x22 = Start
|
||||
if (gbp->p->p->rumble) {
|
||||
gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22);
|
||||
}
|
||||
}
|
||||
mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent);
|
||||
mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048);
|
||||
}
|
||||
value &= 0x78FB;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
UNUSED(timing);
|
||||
UNUSED(cyclesLate);
|
||||
struct GBAGBPSIODriver* gbp = user;
|
||||
uint32_t tx = 0;
|
||||
int txPosition = gbp->p->gbpTxPosition;
|
||||
if (txPosition > 16) {
|
||||
gbp->p->gbpTxPosition = 0;
|
||||
txPosition = 0;
|
||||
} else if (txPosition > 12) {
|
||||
txPosition = 12;
|
||||
}
|
||||
tx = _gbpTxData[txPosition];
|
||||
++gbp->p->gbpTxPosition;
|
||||
gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
|
||||
gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
|
||||
if (GBASIONormalIsIrq(gbp->d.p->siocnt)) {
|
||||
GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate);
|
||||
}
|
||||
gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt);
|
||||
gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
|
||||
}
|
||||
|
||||
// == Serialization
|
||||
|
||||
void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) {
|
||||
GBASerializedHWFlags1 flags1 = 0;
|
||||
GBASerializedHWFlags2 flags2 = 0;
|
||||
flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite);
|
||||
STORE_16(hw->pinState, 0, &state->hw.pinState);
|
||||
STORE_16(hw->direction, 0, &state->hw.pinDirection);
|
||||
|
@ -640,14 +505,19 @@ void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASeria
|
|||
flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge);
|
||||
STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX);
|
||||
STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY);
|
||||
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
|
||||
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
|
||||
state->hw.lightSample = hw->lightSample;
|
||||
flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge);
|
||||
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted);
|
||||
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition);
|
||||
STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
|
||||
STORE_16(flags1, 0, &state->hw.flags1);
|
||||
|
||||
GBASerializedHWFlags2 flags2 = 0;
|
||||
flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState);
|
||||
flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter);
|
||||
|
||||
// GBP stuff is only here for legacy reasons
|
||||
flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted);
|
||||
flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition);
|
||||
STORE_32(hw->p->sio.gbp.event.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent);
|
||||
|
||||
state->hw.flags2 = flags2;
|
||||
}
|
||||
|
||||
|
@ -676,15 +546,17 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer
|
|||
hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1);
|
||||
hw->lightSample = state->hw.lightSample;
|
||||
hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1);
|
||||
hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
|
||||
hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
|
||||
|
||||
// GBP stuff is only here for legacy reasons
|
||||
hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2);
|
||||
hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2);
|
||||
|
||||
uint32_t when;
|
||||
LOAD_32(when, 0, &state->hw.gbpNextEvent);
|
||||
if (hw->devices & HW_GB_PLAYER) {
|
||||
GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32);
|
||||
GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, SIO_NORMAL_32);
|
||||
if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) {
|
||||
mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when);
|
||||
mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/matrix.h>
|
||||
#include <mgba/internal/gba/cart/matrix.h>
|
||||
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/gba/gba.h>
|
|
@ -3,7 +3,7 @@
|
|||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/vfame.h>
|
||||
#include <mgba/internal/gba/cart/vfame.h>
|
||||
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#include <mgba/internal/gba/memory.h>
|
|
@ -219,7 +219,7 @@ void GBAReset(struct ARMCore* cpu) {
|
|||
|
||||
// GB Player SIO control should not be engaged before detection, even if we already know it's GBP
|
||||
gba->memory.hw.devices &= ~HW_GB_PLAYER;
|
||||
if (gba->sio.drivers.normal == &gba->memory.hw.gbpDriver.d) {
|
||||
if (gba->sio.drivers.normal == &gba->sio.gbp.d) {
|
||||
GBASIOSetDriver(&gba->sio, NULL, SIO_NORMAL_32);
|
||||
}
|
||||
|
||||
|
@ -855,7 +855,7 @@ void GBAFrameEnded(struct GBA* gba) {
|
|||
}
|
||||
|
||||
if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) {
|
||||
GBAHardwarePlayerUpdate(gba);
|
||||
GBASIOPlayerUpdate(gba);
|
||||
}
|
||||
|
||||
size_t c;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <mgba/internal/gba/overrides.h>
|
||||
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#include <mgba/internal/gba/hardware.h>
|
||||
#include <mgba/internal/gba/cart/gpio.h>
|
||||
|
||||
#include <mgba-util/configuration.h>
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <mgba/internal/gba/gba.h>
|
||||
#include <mgba/internal/gba/io.h>
|
||||
#include <mgba/internal/gba/sio/gbp.h>
|
||||
|
||||
mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O", "gba.sio");
|
||||
|
||||
|
@ -76,6 +77,10 @@ void GBASIOInit(struct GBASIO* sio) {
|
|||
sio->drivers.multiplayer = 0;
|
||||
sio->drivers.joybus = 0;
|
||||
sio->activeDriver = 0;
|
||||
|
||||
sio->gbp.p = sio->p;
|
||||
GBASIOPlayerInit(&sio->gbp);
|
||||
|
||||
GBASIOReset(sio);
|
||||
}
|
||||
|
||||
|
@ -103,6 +108,8 @@ void GBASIOReset(struct GBASIO* sio) {
|
|||
sio->mode = -1;
|
||||
sio->activeDriver = NULL;
|
||||
_switchMode(sio);
|
||||
|
||||
GBASIOPlayerReset(&sio->gbp);
|
||||
}
|
||||
|
||||
void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) {
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/* Copyright (c) 2013-2021 Jeffrey Pfau
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/sio.h>
|
||||
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/gba/io.h>
|
||||
#include <mgba/internal/gba/serialize.h>
|
||||
#include <mgba-util/formatting.h>
|
||||
#include <mgba-util/hash.h>
|
||||
#include <mgba-util/memory.h>
|
||||
|
||||
static uint16_t _gbpRead(struct mKeyCallback*);
|
||||
static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
|
||||
static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate);
|
||||
|
||||
static const uint8_t _logoPalette[] = {
|
||||
0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68,
|
||||
0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED,
|
||||
0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72,
|
||||
0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B,
|
||||
0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F,
|
||||
0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2,
|
||||
0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const uint32_t _logoHash = 0xEEDA6963;
|
||||
|
||||
static const uint32_t _gbpTxData[] = {
|
||||
0x0000494E, 0x0000494E,
|
||||
0xB6B1494E, 0xB6B1544E,
|
||||
0xABB1544E, 0xABB14E45,
|
||||
0xB1BA4E45, 0xB1BA4F44,
|
||||
0xB0BB4F44, 0xB0BB8002,
|
||||
0x10000010, 0x20000013,
|
||||
0x30000003
|
||||
};
|
||||
|
||||
void GBASIOPlayerInit(struct GBASIOPlayer* gbp) {
|
||||
gbp->callback.d.readKeys = _gbpRead;
|
||||
gbp->callback.p = gbp;
|
||||
gbp->d.init = 0;
|
||||
gbp->d.deinit = 0;
|
||||
gbp->d.load = 0;
|
||||
gbp->d.unload = 0;
|
||||
gbp->d.writeRegister = _gbpSioWriteRegister;
|
||||
gbp->event.context = gbp;
|
||||
gbp->event.name = "GBA SIO Game Boy Player";
|
||||
gbp->event.callback = _gbpSioProcessEvents;
|
||||
gbp->event.priority = 0x80;
|
||||
}
|
||||
|
||||
void GBASIOPlayerReset(struct GBASIOPlayer* gbp) {
|
||||
if (gbp->p->sio.drivers.normal == &gbp->d) {
|
||||
GBASIOSetDriver(&gbp->p->sio, NULL, SIO_NORMAL_32);
|
||||
}
|
||||
}
|
||||
|
||||
bool GBASIOPlayerCheckScreen(const struct GBAVideo* video) {
|
||||
if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0);
|
||||
return hash == _logoHash;
|
||||
}
|
||||
|
||||
void GBASIOPlayerUpdate(struct GBA* gba) {
|
||||
if (gba->memory.hw.devices & HW_GB_PLAYER) {
|
||||
if (GBASIOPlayerCheckScreen(&gba->video)) {
|
||||
++gba->sio.gbp.inputsPosted;
|
||||
gba->sio.gbp.inputsPosted %= 3;
|
||||
gba->keyCallback = &gba->sio.gbp.callback.d;
|
||||
} else {
|
||||
// TODO: Save and restore
|
||||
gba->keyCallback = 0;
|
||||
}
|
||||
gba->sio.gbp.txPosition = 0;
|
||||
return;
|
||||
}
|
||||
if (gba->keyCallback) {
|
||||
return;
|
||||
}
|
||||
if (GBASIOPlayerCheckScreen(&gba->video)) {
|
||||
gba->memory.hw.devices |= HW_GB_PLAYER;
|
||||
gba->sio.gbp.inputsPosted = 0;
|
||||
gba->keyCallback = &gba->sio.gbp.callback.d;
|
||||
// TODO: Check if the SIO driver is actually used first
|
||||
GBASIOSetDriver(&gba->sio, &gba->sio.gbp.d, SIO_NORMAL_32);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t _gbpRead(struct mKeyCallback* callback) {
|
||||
struct GBASIOPlayerKeyCallback* gbpCallback = (struct GBASIOPlayerKeyCallback*) callback;
|
||||
if (gbpCallback->p->inputsPosted == 2) {
|
||||
return 0xF0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
|
||||
struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver;
|
||||
if (address == REG_SIOCNT) {
|
||||
if (value & 0x0080) {
|
||||
uint32_t rx = gbp->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->memory.io[REG_SIODATA32_HI >> 1] << 16);
|
||||
if (gbp->txPosition < 12 && gbp->txPosition > 0) {
|
||||
// TODO: Check expected
|
||||
} else if (gbp->txPosition >= 12) {
|
||||
uint32_t mask = 0x33;
|
||||
// 0x00 = Stop
|
||||
// 0x11 = Hard Stop
|
||||
// 0x22 = Start
|
||||
if (gbp->p->rumble) {
|
||||
gbp->p->rumble->setRumble(gbp->p->rumble, (rx & mask) == 0x22);
|
||||
}
|
||||
}
|
||||
mTimingDeschedule(&gbp->p->timing, &gbp->event);
|
||||
mTimingSchedule(&gbp->p->timing, &gbp->event, 2048);
|
||||
}
|
||||
value &= 0x78FB;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
|
||||
UNUSED(timing);
|
||||
UNUSED(cyclesLate);
|
||||
struct GBASIOPlayer* gbp = user;
|
||||
uint32_t tx = 0;
|
||||
int txPosition = gbp->txPosition;
|
||||
if (txPosition > 16) {
|
||||
gbp->txPosition = 0;
|
||||
txPosition = 0;
|
||||
} else if (txPosition > 12) {
|
||||
txPosition = 12;
|
||||
}
|
||||
tx = _gbpTxData[txPosition];
|
||||
++gbp->txPosition;
|
||||
gbp->p->memory.io[REG_SIODATA32_LO >> 1] = tx;
|
||||
gbp->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16;
|
||||
if (GBASIONormalIsIrq(gbp->d.p->siocnt)) {
|
||||
GBARaiseIRQ(gbp->p, IRQ_SIO, cyclesLate);
|
||||
}
|
||||
gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt);
|
||||
gbp->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080;
|
||||
}
|
Loading…
Reference in New Issue