From 0051c82fcb58126e345f8009d0e9ee116b62fe29 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Tue, 29 Jun 2021 22:13:13 -0300 Subject: [PATCH 01/21] Add .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 20c19fc4154..9bc108b766b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ /build /build-* /.vs +/.vscode *.a *.dylib From cf6d9ef9842db1ff408d137a1c24e2e521e5c834 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Tue, 29 Jun 2021 22:15:51 -0300 Subject: [PATCH 02/21] Added a protoype protocol to use hardware extensions. Made an extension that allows a game to access a swap memory it can write to or read from. --- include/mgba/internal/gba/gba.h | 5 + .../mgba/internal/gba/hardware-extensions.h | 21 +++ include/mgba/internal/gba/io.h | 5 + src/gba/CMakeLists.txt | 1 + src/gba/hardware-extensions.c | 125 ++++++++++++++++++ src/gba/io.c | 11 ++ 6 files changed, 168 insertions(+) create mode 100644 include/mgba/internal/gba/hardware-extensions.h create mode 100644 src/gba/hardware-extensions.c diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index 6e8fe499056..923982999f8 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -18,6 +18,7 @@ CXX_GUARD_START #include #include #include +#include #define GBA_ARM7TDMI_FREQUENCY 0x1000000U @@ -123,6 +124,10 @@ struct GBA { bool debug; char debugString[0x100]; GBADebugFlags debugFlags; + + // Extensions + uint32_t extIORegisters[HWEX_EXTENSIONS_COUNT]; + uint32_t extMoreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; struct GBACartridge { diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h new file mode 100644 index 00000000000..32df2434fcf --- /dev/null +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -0,0 +1,21 @@ + +#ifndef HARDWARE_EXTENSIONS_H +#define HARDWARE_EXTENSIONS_H + +#include + +#include +#include + + +#define HWEX_EXTENSIONS_COUNT 1 + +#define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB + +struct GBA; +uint16_t GetRegMgbaHwExtensionsEnabled(void); +uint16_t GetRegMgbaHwExtensionsCnt(struct GBA* gba, uint32_t address); +uint16_t GetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address); +void SetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address, uint32_t value); + +#endif diff --git a/include/mgba/internal/gba/io.h b/include/mgba/internal/gba/io.h index 9875061f358..93c7a79f725 100644 --- a/include/mgba/internal/gba/io.h +++ b/include/mgba/internal/gba/io.h @@ -157,6 +157,11 @@ enum GBAIORegisters { REG_DEBUG_STRING = 0xFFF600, REG_DEBUG_FLAGS = 0xFFF700, REG_DEBUG_ENABLE = 0xFFF780, + + // Extensions + REG_MGBA_EXTENSIONS_ENABLED = 0xFFFA00, + REG_MGBA_EXTENSIONS_CNT = 0xFFFA02, + REG_MGBA_EXTENSION_0 = 0xFFFA08, }; mLOG_DECLARE_CATEGORY(GBA_IO); diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index 4bf354f3a37..f88f76d1e00 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCE_FILES core.c dma.c gba.c + hardware-extensions.c hle-bios.c input.c io.c diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c new file mode 100644 index 00000000000..807bad4a22f --- /dev/null +++ b/src/gba/hardware-extensions.c @@ -0,0 +1,125 @@ + +#include +#include +#include +#include + +static enum HWEX_RETURN_CODES { + HWEX_RET_OK = 0, + HWEX_RET_WAIT = 1, + + // Errors + HWEX_RET_ERR_UNKNOWN = 0x100, + HWEX_RET_ERR_BAD_ADDRESS = 0x101, + HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, + HWEX_RET_ERR_WRITE_TO_ROM = 0x103, +}; + +static bool GetMemoryDataFromAddress(struct GBA* gba, uint32_t address, uint32_t** memory, uint32_t* index, uint32_t* memoryLength, bool* isRom) { + uint addressPrefix = (address >> 24) & 0xF; + *memory = NULL; + *isRom = false; + + if (address & 0b11) { + return false; + } + *index = (address & 0xFFFFFF) >> 2; + if (addressPrefix == 2) { + *memory = gba->memory.wram; + *memoryLength = SIZE_WORKING_RAM; + } else if (addressPrefix == 3) { + *memory = gba->memory.iwram; + *memoryLength = SIZE_WORKING_IRAM; + } else if (addressPrefix == 8) { + *isRom = true; + *memory = gba->memory.rom; + *memoryLength = gba->memory.romSize; + } else if (addressPrefix == 9) { + *isRom = true; + *memory = gba->memory.rom; + *index += 0x1000000 >> 2; + *memoryLength = gba->memory.romSize; + } else { + return false; + } + + if (*isRom && *index > gba->memory.romSize) { + return false; + } + + + return true; +} + +static enum HwExtMoreRAMActions { + HwExtMoreRAMMemoryWrite = 0, + HwExtMoreRAMMemoryRead = 1, + HwExtMoreRAMMemorySwap = 2, +}; + +static uint16_t MGBAHwExtMoreRAM(struct GBA* gba, uint32_t* memory, uint32_t index, uint32_t memoryLength, bool isRom) { + + uint32_t action = memory[index] >> 28; + uint32_t dataLength = memory[index] & 0xFFFFFFF; + uint32_t moreRamIndex = memory[index + 1]; + mLOG(GBA_IO, GAME_ERROR, "Index: %03X", moreRamIndex); + mLOG(GBA_IO, GAME_ERROR, "Length: %03X", dataLength); + + if (action <= HwExtMoreRAMMemorySwap) { + if (action == HwExtMoreRAMMemoryWrite) { + memcpy(gba->extMoreRam + moreRamIndex, memory + 2 + index, sizeof(uint32_t) * dataLength); + } else if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } else if (action == HwExtMoreRAMMemoryRead) { + memcpy(memory + 2 + index, gba->extMoreRam + moreRamIndex, sizeof(uint32_t) * dataLength); + } else if (action == HwExtMoreRAMMemorySwap) { + uint32_t aux; + for (uint32_t i = 0; i < dataLength; i++) { + aux = memory[i + index + 2]; + memory[i + index + 2] = gba->extMoreRam[i + moreRamIndex]; + gba->extMoreRam[i + moreRamIndex] = aux; + } + } + return HWEX_RET_OK; + } + + return HWEX_RET_ERR_INVALID_PARAMETERS; +} + +typedef uint16_t (*HwExtensionHandler)(struct GBA* gba, uint32_t* memory, uint32_t index, uint32_t memoryLength, bool isRom); + +static const HwExtensionHandler HwExtensionHandlers[HWEX_EXTENSIONS_COUNT] = { + MGBAHwExtMoreRAM +}; + +uint16_t GetRegMgbaHwExtensionsEnabled(void) { + return 0xEC57; +} + +uint16_t GetRegMgbaHwExtensionsCnt(struct GBA* gba, uint32_t address) { + return 1; +} + +uint16_t GetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address) { + uint32_t index = (address - REG_MGBA_EXTENSION_0) >> 2; + uint32_t value = gba->extIORegisters[index]; + return (uint16_t) (address & 0b10 ? value >> 16 : value & 0xFFFF); +} + +void SetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address, uint32_t value) { + if (value & 0x80000000) { + uint32_t extension = (address - REG_MGBA_EXTENSION_0) >> 2; + if (extension < HWEX_EXTENSIONS_COUNT) { + uint32_t* memory; + uint32_t index, memoryLenght; + bool isRom; + + if (GetMemoryDataFromAddress(gba, value & 0x0FFFFFFF, &memory, &index, &memoryLenght, &isRom)) { + gba->extIORegisters[extension] = HwExtensionHandlers[extension](gba, memory, index, memoryLenght, isRom); + } else { + gba->extIORegisters[extension] = HWEX_RET_ERR_BAD_ADDRESS; + } + } + } +} + diff --git a/src/gba/io.c b/src/gba/io.c index 9dc66b94d67..72f1509acdb 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -9,6 +9,7 @@ #include #include #include +#include mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io"); @@ -666,6 +667,9 @@ void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { case REG_DMA3DAD_LO: value = GBADMAWriteDAD(gba, 3, value); break; + case REG_MGBA_EXTENSION_0: + SetRegMgbaHwExtensionValue(gba, address, value); + return; default: if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString); @@ -931,12 +935,19 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case 0x206: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return 0; + case REG_MGBA_EXTENSIONS_ENABLED: + return GetRegMgbaHwExtensionsEnabled(); + case REG_MGBA_EXTENSIONS_CNT: + return GetRegMgbaHwExtensionsCnt(gba, address); case REG_DEBUG_ENABLE: if (gba->debug) { return 0x1DEA; } // Fall through default: + if (address >= REG_MGBA_EXTENSION_0 && (address & 1) == 0 && ((address - REG_MGBA_EXTENSION_0) >> 2) < HWEX_EXTENSIONS_COUNT) { + return GetRegMgbaHwExtensionValue(gba, address); + } mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return GBALoadBad(gba->cpu); } From e563a3659c2e7b4404eeecb57b120989cde74f7b Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 4 Jul 2021 14:57:14 -0300 Subject: [PATCH 03/21] Rewrote most of the extensions code to reorganize the IO and change the way parameters are passed. --- include/mgba/internal/gba/gba.h | 4 +- .../mgba/internal/gba/hardware-extensions.h | 32 +- include/mgba/internal/gba/io.h | 26 +- src/gba/gba.c | 2 + src/gba/hardware-extensions.c | 349 ++++++++++++++---- src/gba/io.c | 23 +- 6 files changed, 335 insertions(+), 101 deletions(-) diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index 923982999f8..a915b8e284f 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -125,9 +125,7 @@ struct GBA { char debugString[0x100]; GBADebugFlags debugFlags; - // Extensions - uint32_t extIORegisters[HWEX_EXTENSIONS_COUNT]; - uint32_t extMoreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + struct GBAHardwareExtensions hwExtensions; }; struct GBACartridge { diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h index 32df2434fcf..be21e57c1d8 100644 --- a/include/mgba/internal/gba/hardware-extensions.h +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -1,4 +1,8 @@ - +/* Copyright (c) 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 HARDWARE_EXTENSIONS_H #define HARDWARE_EXTENSIONS_H @@ -7,15 +11,31 @@ #include #include +#include -#define HWEX_EXTENSIONS_COUNT 1 +#define HWEX_EXTENSIONS_COUNT 1 +#define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB +struct GBAHardwareExtensions { + bool enabled; + bool userEnabled; + uint16_t userEnabledFlags[5]; + + // IO: + uint32_t memory[(REG_HWEX_END - REG_HWEX_ENABLE) / sizeof(uint32_t)]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; +}; + struct GBA; -uint16_t GetRegMgbaHwExtensionsEnabled(void); -uint16_t GetRegMgbaHwExtensionsCnt(struct GBA* gba, uint32_t address); -uint16_t GetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address); -void SetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address, uint32_t value); +void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hw); +uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address); +uint32_t GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address); +void GBAHardwareExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); +void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value); +void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t value); #endif diff --git a/include/mgba/internal/gba/io.h b/include/mgba/internal/gba/io.h index 93c7a79f725..777d1cac697 100644 --- a/include/mgba/internal/gba/io.h +++ b/include/mgba/internal/gba/io.h @@ -159,9 +159,29 @@ enum GBAIORegisters { REG_DEBUG_ENABLE = 0xFFF780, // Extensions - REG_MGBA_EXTENSIONS_ENABLED = 0xFFFA00, - REG_MGBA_EXTENSIONS_CNT = 0xFFFA02, - REG_MGBA_EXTENSION_0 = 0xFFFA08, + REG_HWEX_ENABLE = 0x400A00, + REG_HWEX_VERSION = 0x400A02, + REG_HWEX_ENABLE_FLAGS_0 = 0x400A04, + REG_HWEX_ENABLE_FLAGS_1 = 0x400A06, + REG_HWEX_ENABLE_FLAGS_2 = 0x400A08, + REG_HWEX_ENABLE_FLAGS_3 = 0x400A0A, + REG_HWEX_ENABLE_FLAGS_4 = 0x400A0C, + REG_HWEX_ENABLE_FLAGS_5 = 0x400A0E, + + // More RAM + REG_HWEX0_CNT = 0x400A10, + REG_HWEX0_RET_CODE = 0x400A12, + REG_HWEX0_P0_LO = 0x400A14, // command + REG_HWEX0_P0_HI = 0x400A16, + REG_HWEX0_P1_LO = 0x400A18, // index + REG_HWEX0_P1_HI = 0x400A1A, + REG_HWEX0_P2_LO = 0x400A1C, // data pointer + REG_HWEX0_P2_HI = 0x400A1E, + REG_HWEX0_P3_LO = 0x400A20, // size + REG_HWEX0_P3_HI = 0x400A22, + + REG_HWEX_END = 0x400A24, + }; mLOG_DECLARE_CATEGORY(GBA_IO); diff --git a/src/gba/gba.c b/src/gba/gba.c index b73fe9d8668..a5f1b90cc7f 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -124,6 +124,8 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->irqEvent.callback = _triggerIRQ; gba->irqEvent.context = gba; gba->irqEvent.priority = 0; + + GBAHardwareExtensionsInit(&gba->hwExtensions); } void GBAUnloadROM(struct GBA* gba) { diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index 807bad4a22f..5fc304d600f 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -1,9 +1,16 @@ - +/* Copyright (c) 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 #include #include #include +static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address); +static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address); + static enum HWEX_RETURN_CODES { HWEX_RET_OK = 0, HWEX_RET_WAIT = 1, @@ -13,113 +20,295 @@ static enum HWEX_RETURN_CODES { HWEX_RET_ERR_BAD_ADDRESS = 0x101, HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, HWEX_RET_ERR_WRITE_TO_ROM = 0x103, + HWEX_RET_ERR_ABORTED = 0x104 }; -static bool GetMemoryDataFromAddress(struct GBA* gba, uint32_t address, uint32_t** memory, uint32_t* index, uint32_t* memoryLength, bool* isRom) { - uint addressPrefix = (address >> 24) & 0xF; - *memory = NULL; - *isRom = false; +static enum { + HWEX_ID_MORE_RAM = 0 +}; - if (address & 0b11) { - return false; - } - *index = (address & 0xFFFFFF) >> 2; - if (addressPrefix == 2) { - *memory = gba->memory.wram; - *memoryLength = SIZE_WORKING_RAM; - } else if (addressPrefix == 3) { - *memory = gba->memory.iwram; - *memoryLength = SIZE_WORKING_IRAM; - } else if (addressPrefix == 8) { - *isRom = true; - *memory = gba->memory.rom; - *memoryLength = gba->memory.romSize; - } else if (addressPrefix == 9) { - *isRom = true; - *memory = gba->memory.rom; - *index += 0x1000000 >> 2; - *memoryLength = gba->memory.romSize; - } else { - return false; +void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hwExtensions) { + hwExtensions->enabled = false; + + // TODO: read this from the config + hwExtensions->userEnabled = true; + memset(hwExtensions->userEnabledFlags, 0xFF, sizeof(hwExtensions->userEnabledFlags)); + + memset(hwExtensions->memory, 0, sizeof(hwExtensions->memory)); +} + +uint16_t _GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { + switch (address) { + case REG_HWEX_ENABLE: + return 0x1DEA; + case REG_HWEX_VERSION: + return REG_HWEX_VERSION_VALUE; + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + return *GetHwExIOPointer(gba, address) & gba->hwExtensions.userEnabledFlags[index]; + } + + default: + return *GetHwExIOPointer(gba, address); } +} - if (*isRom && *index > gba->memory.romSize) { - return false; +uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { + if (gba->hwExtensions.enabled && gba->hwExtensions.userEnabled) { + return _GBAHardwareExtensionsIORead(gba, address); } + mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); + return GBALoadBad(gba->cpu); +} + +uint32_t GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address) { + return gba->hwExtensions.memory[GetHwExMemoryIndex32FromAddress(address)]; +}; +static void* GBAHardwareExtensionsIOReadPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { + uint32_t addressPrefix = (address >> 24) & 0xF; + uint8_t* pointer = NULL; + *isRom = false; - return true; + if (addressPrefix == 2) { + if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { + pointer = (uint8_t*) gba->memory.wram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); + } + } else if (addressPrefix == 3) { + if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { + pointer = (uint8_t*) gba->memory.iwram; + mLOG(GBA_IO, GAME_ERROR, "addr: %03X", pointer); + pointer += address & 0xFFFFFF; + mLOG(GBA_IO, GAME_ERROR, "addr2: %03X", pointer); + *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); + } + } else if (addressPrefix & 8) { + if ((address & 0x1FFFFFF) < gba->memory.romSize) { + *isRom = true; + pointer = (uint8_t*) gba->memory.rom; + pointer += address & 0x1FFFFFF; + *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); + } + } + + return pointer; } -static enum HwExtMoreRAMActions { +static enum HwExMoreRAMCommands { HwExtMoreRAMMemoryWrite = 0, HwExtMoreRAMMemoryRead = 1, - HwExtMoreRAMMemorySwap = 2, + HwExtMoreRAMMemorySwap = 2 }; -static uint16_t MGBAHwExtMoreRAM(struct GBA* gba, uint32_t* memory, uint32_t index, uint32_t memoryLength, bool isRom) { - - uint32_t action = memory[index] >> 28; - uint32_t dataLength = memory[index] & 0xFFFFFFF; - uint32_t moreRamIndex = memory[index + 1]; - mLOG(GBA_IO, GAME_ERROR, "Index: %03X", moreRamIndex); - mLOG(GBA_IO, GAME_ERROR, "Length: %03X", dataLength); - - if (action <= HwExtMoreRAMMemorySwap) { - if (action == HwExtMoreRAMMemoryWrite) { - memcpy(gba->extMoreRam + moreRamIndex, memory + 2 + index, sizeof(uint32_t) * dataLength); - } else if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } else if (action == HwExtMoreRAMMemoryRead) { - memcpy(memory + 2 + index, gba->extMoreRam + moreRamIndex, sizeof(uint32_t) * dataLength); - } else if (action == HwExtMoreRAMMemorySwap) { - uint32_t aux; - for (uint32_t i = 0; i < dataLength; i++) { - aux = memory[i + index + 2]; - memory[i + index + 2] = gba->extMoreRam[i + moreRamIndex]; - gba->extMoreRam[i + moreRamIndex] = aux; + +static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { + uint32_t command = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); + uint32_t index = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); + uint32_t dataPointer = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); + uint32_t dataSize = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); + void* data; + // Check if the pointer is valid + bool isRom; + uint32_t memoryMaxSize; + data = GBAHardwareExtensionsIOReadPointer(gba, dataPointer, &memoryMaxSize, &isRom); + if (data == NULL) { + mLOG(GBA_IO, GAME_ERROR, "Bad address: %03X", dataPointer); + return HWEX_RET_ERR_BAD_ADDRESS; + } + + // Check if index and size are valid + if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + switch (command) { + case HwExtMoreRAMMemoryWrite: + mLOG(GBA_IO, GAME_ERROR, "write: %03X", dataPointer); + memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); + break; + case HwExtMoreRAMMemoryRead: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; } - } - return HWEX_RET_OK; - } + memcpy(data, ((uint8_t*)gba->hwExtensions.moreRam) + index, dataSize); + break; + case HwExtMoreRAMMemorySwap: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + // TODO: make this more efficient + uint8_t* data1 = data; + uint8_t* data2 = gba->hwExtensions.moreRam; + data2 += index; + for (uint32_t i = 0; i < dataSize; i++) { + uint8_t aux = data1[i]; + data1[i] = data2[i]; + data2[i] = aux; + } + break; + default: + // invalid command + return HWEX_RET_ERR_INVALID_PARAMETERS; + } - return HWEX_RET_ERR_INVALID_PARAMETERS; + return HWEX_RET_OK; } -typedef uint16_t (*HwExtensionHandler)(struct GBA* gba, uint32_t* memory, uint32_t index, uint32_t memoryLength, bool isRom); -static const HwExtensionHandler HwExtensionHandlers[HWEX_EXTENSIONS_COUNT] = { - MGBAHwExtMoreRAM -}; +static uint32_t GetHwExMemoryIndex16FromAddress(uint32_t address) { + uint32_t ret = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + return ret; +} +static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address) { + return (address - REG_HWEX_ENABLE_FLAGS_0) >> 2; +} -uint16_t GetRegMgbaHwExtensionsEnabled(void) { - return 0xEC57; +static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address) { + return ((uint16_t*) &gba->hwExtensions.memory) + GetHwExMemoryIndex16FromAddress(address); } -uint16_t GetRegMgbaHwExtensionsCnt(struct GBA* gba, uint32_t address) { - return 1; +static void _GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { + *GetHwExIOPointer(gba, address) = value; } -uint16_t GetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address) { - uint32_t index = (address - REG_MGBA_EXTENSION_0) >> 2; - uint32_t value = gba->extIORegisters[index]; - return (uint16_t) (address & 0b10 ? value >> 16 : value & 0xFFFF); +// CNT flags +// Writable +#define HWEX_CNT_FLAG_CALL 1 +#define HWEX_CNT_ALL_WRITABLE (HWEX_CNT_FLAG_CALL) +// Read only +#define HWEX_CNT_FLAG_PROCESSING (1 << 15) + +struct HardwareExtensionHandlers { + uint16_t (*onCall)(struct GBA* gba); + bool (*onAbort)(void); +}; + +static const struct HardwareExtensionHandlers extensionHandlers[] = { + [HWEX_ID_MORE_RAM] = { .onCall = MGBAHwExtMoreRAM, .onAbort = NULL } +}; + +#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) + +const uint16_t extensionIdByRegister[] = { + // More RAM + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, +}; + +static uint16_t GetExtensionIdFromAddress(uint32_t address) { + return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; } -void SetRegMgbaHwExtensionValue(struct GBA* gba, uint32_t address, uint32_t value) { - if (value & 0x80000000) { - uint32_t extension = (address - REG_MGBA_EXTENSION_0) >> 2; - if (extension < HWEX_EXTENSIONS_COUNT) { - uint32_t* memory; - uint32_t index, memoryLenght; - bool isRom; - - if (GetMemoryDataFromAddress(gba, value & 0x0FFFFFFF, &memory, &index, &memoryLenght, &isRom)) { - gba->extIORegisters[extension] = HwExtensionHandlers[extension](gba, memory, index, memoryLenght, isRom); - } else { - gba->extIORegisters[extension] = HWEX_RET_ERR_BAD_ADDRESS; +#undef SIMPLIFY_HWEX_REG_ADDRESS + + +static void GBAHardwareExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { + uint16_t* cnt = GetHwExIOPointer(gba, cntAddress); + uint16_t* returnCode = cnt + 1; + uint16_t currentValue = *cnt; + const struct HardwareExtensionHandlers* handlers = extensionHandlers + GetExtensionIdFromAddress(cntAddress); + value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags + + if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed + if (currentValue & HWEX_CNT_FLAG_PROCESSING) { // check if extension is running + if (!(currentValue & HWEX_CNT_FLAG_CALL)) { + // call flag set to 0 + // abort + if (handlers->onAbort) { + handlers->onAbort(); + *cnt = currentValue; + *returnCode = HWEX_RET_ERR_ABORTED; + } } + } else { + if (value & HWEX_CNT_FLAG_CALL) { // check call the extension + *returnCode = handlers->onCall(gba); + if (*returnCode == HWEX_RET_OK || *returnCode >= HWEX_RET_ERR_UNKNOWN) { // execution finished + *cnt = 0; + } else { // processing + *cnt = currentValue | HWEX_CNT_FLAG_CALL | HWEX_CNT_FLAG_PROCESSING; + } + } + } + } + + return; +} + + +void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { + switch (address) { + case REG_HWEX_ENABLE: + gba->hwExtensions.enabled = value == 0xC0DE; + break; + // Enable flags + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists + if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { + // delete the flags of the non-existant extensions + value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); + } + _GBAHardwareExtensionsIOWrite(gba, address, value); + } + break; } + // Return codes + case REG_HWEX0_RET_CODE: + mLOG(GBA_IO, GAME_ERROR, "Write to read-only hardware extensions I/O register: %06X", address); + break; + + // CNT + case REG_HWEX0_CNT: + GBAHardwareExtensionsHandleCntWrite(gba, address, value); + break; + + // Parameters + case REG_HWEX0_P0_LO: + case REG_HWEX0_P0_HI: + case REG_HWEX0_P1_LO: + case REG_HWEX0_P1_HI: + case REG_HWEX0_P2_LO: + case REG_HWEX0_P2_HI: + case REG_HWEX0_P3_LO: + case REG_HWEX0_P3_HI: + if (!(_GBAHardwareExtensionsIORead(gba, REG_HWEX0_CNT) & HWEX_CNT_FLAG_PROCESSING)) { + _GBAHardwareExtensionsIOWrite(gba, address, value); + } + break; + default: + mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); } } +void GBAHardwareExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { + uint32_t address16 = address & 0xFFFFFE; + uint16_t* reg = GetHwExIOPointer(gba, address16); + GBAHardwareExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); +} + +void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { + GBAHardwareExtensionsIOWrite(gba, address, value & 0xFFFF); + GBAHardwareExtensionsIOWrite(gba, address + 2, value >> 16); +} + diff --git a/src/gba/io.c b/src/gba/io.c index 887db5dfcb3..3859f6f2988 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -586,6 +586,10 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { STORE_16LE(value, address - REG_DEBUG_STRING, gba->debugString); return; } + if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { + GBAHardwareExtensionsIOWrite(gba, address, value); + return; + } mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address); if (address >= REG_MAX) { mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address); @@ -614,6 +618,10 @@ void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { gba->debugString[address - REG_DEBUG_STRING] = value; return; } + if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { + GBAHardwareExtensionsIOWrite8(gba, address, value); + return; + } if (address > SIZE_IO) { return; } @@ -667,14 +675,15 @@ void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { case REG_DMA3DAD_LO: value = GBADMAWriteDAD(gba, 3, value); break; - case REG_MGBA_EXTENSION_0: - SetRegMgbaHwExtensionValue(gba, address, value); - return; default: if (address >= REG_DEBUG_STRING && address - REG_DEBUG_STRING < sizeof(gba->debugString)) { STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString); return; } + if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { + GBAHardwareExtensionsIOWrite32(gba, address, value); + return; + } GBAIOWrite(gba, address, value & 0xFFFF); GBAIOWrite(gba, address | 2, value >> 16); return; @@ -935,18 +944,14 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { case 0x206: mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return 0; - case REG_MGBA_EXTENSIONS_ENABLED: - return GetRegMgbaHwExtensionsEnabled(); - case REG_MGBA_EXTENSIONS_CNT: - return GetRegMgbaHwExtensionsCnt(gba, address); case REG_DEBUG_ENABLE: if (gba->debug) { return 0x1DEA; } // Fall through default: - if (address >= REG_MGBA_EXTENSION_0 && (address & 1) == 0 && ((address - REG_MGBA_EXTENSION_0) >> 2) < HWEX_EXTENSIONS_COUNT) { - return GetRegMgbaHwExtensionValue(gba, address); + if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { + return GBAHardwareExtensionsIORead(gba, address); } mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return GBALoadBad(gba->cpu); From 7bba0eb52fc17b9d1850540953f6d87abfb5b422 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 4 Jul 2021 17:44:49 -0300 Subject: [PATCH 04/21] Hardware extensions code cleanup. --- src/gba/hardware-extensions.c | 64 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index 5fc304d600f..d7fa298c95c 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -8,10 +8,8 @@ #include #include -static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address); -static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address); -static enum HWEX_RETURN_CODES { +enum HWEX_RETURN_CODES { HWEX_RET_OK = 0, HWEX_RET_WAIT = 1, @@ -20,10 +18,12 @@ static enum HWEX_RETURN_CODES { HWEX_RET_ERR_BAD_ADDRESS = 0x101, HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, HWEX_RET_ERR_WRITE_TO_ROM = 0x103, - HWEX_RET_ERR_ABORTED = 0x104 + HWEX_RET_ERR_ABORTED = 0x104, + HWEX_RET_ERR_DISABLED = 0x105, + HWEX_RET_ERR_DISABLED_BY_USER = 0x106 }; -static enum { +enum { HWEX_ID_MORE_RAM = 0 }; @@ -37,7 +37,19 @@ void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hwExtensions) { memset(hwExtensions->memory, 0, sizeof(hwExtensions->memory)); } -uint16_t _GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { +static uint32_t GetHwExMemoryIndex16FromAddress(uint32_t address) { + return (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; +} + +static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address) { + return (address - REG_HWEX_ENABLE_FLAGS_0) >> 2; +} + +static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address) { + return ((uint16_t*) &gba->hwExtensions.memory) + GetHwExMemoryIndex16FromAddress(address); +} + +static uint16_t _GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { switch (address) { case REG_HWEX_ENABLE: return 0x1DEA; @@ -66,11 +78,11 @@ uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { return GBALoadBad(gba->cpu); } -uint32_t GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address) { +static uint32_t _GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address) { return gba->hwExtensions.memory[GetHwExMemoryIndex32FromAddress(address)]; }; -static void* GBAHardwareExtensionsIOReadPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { +static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { uint32_t addressPrefix = (address >> 24) & 0xF; uint8_t* pointer = NULL; *isRom = false; @@ -84,9 +96,7 @@ static void* GBAHardwareExtensionsIOReadPointer(struct GBA* gba, uint32_t addres } else if (addressPrefix == 3) { if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { pointer = (uint8_t*) gba->memory.iwram; - mLOG(GBA_IO, GAME_ERROR, "addr: %03X", pointer); pointer += address & 0xFFFFFF; - mLOG(GBA_IO, GAME_ERROR, "addr2: %03X", pointer); *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); } } else if (addressPrefix & 8) { @@ -101,25 +111,23 @@ static void* GBAHardwareExtensionsIOReadPointer(struct GBA* gba, uint32_t addres return pointer; } -static enum HwExMoreRAMCommands { +enum HwExMoreRAMCommands { HwExtMoreRAMMemoryWrite = 0, HwExtMoreRAMMemoryRead = 1, HwExtMoreRAMMemorySwap = 2 }; - static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { - uint32_t command = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); - uint32_t index = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); - uint32_t dataPointer = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); - uint32_t dataSize = GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); + uint32_t command = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); + uint32_t index = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); + uint32_t dataPointer = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); + uint32_t dataSize = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); void* data; // Check if the pointer is valid bool isRom; uint32_t memoryMaxSize; - data = GBAHardwareExtensionsIOReadPointer(gba, dataPointer, &memoryMaxSize, &isRom); + data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); if (data == NULL) { - mLOG(GBA_IO, GAME_ERROR, "Bad address: %03X", dataPointer); return HWEX_RET_ERR_BAD_ADDRESS; } @@ -130,7 +138,6 @@ static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { switch (command) { case HwExtMoreRAMMemoryWrite: - mLOG(GBA_IO, GAME_ERROR, "write: %03X", dataPointer); memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); break; case HwExtMoreRAMMemoryRead: @@ -145,7 +152,7 @@ static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { } // TODO: make this more efficient uint8_t* data1 = data; - uint8_t* data2 = gba->hwExtensions.moreRam; + uint8_t* data2 = (uint8_t*) gba->hwExtensions.moreRam; data2 += index; for (uint32_t i = 0; i < dataSize; i++) { uint8_t aux = data1[i]; @@ -161,19 +168,6 @@ static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { return HWEX_RET_OK; } - -static uint32_t GetHwExMemoryIndex16FromAddress(uint32_t address) { - uint32_t ret = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - return ret; -} -static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address) { - return (address - REG_HWEX_ENABLE_FLAGS_0) >> 2; -} - -static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address) { - return ((uint16_t*) &gba->hwExtensions.memory) + GetHwExMemoryIndex16FromAddress(address); -} - static void _GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { *GetHwExIOPointer(gba, address) = value; } @@ -216,7 +210,6 @@ static uint16_t GetExtensionIdFromAddress(uint32_t address) { #undef SIMPLIFY_HWEX_REG_ADDRESS - static void GBAHardwareExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { uint16_t* cnt = GetHwExIOPointer(gba, cntAddress); uint16_t* returnCode = cnt + 1; @@ -246,11 +239,8 @@ static void GBAHardwareExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAdd } } } - - return; } - void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { switch (address) { case REG_HWEX_ENABLE: From acc10c3cfda7a496ff726aac0d5f690a353ee7e3 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sat, 10 Jul 2021 16:44:49 -0300 Subject: [PATCH 05/21] Fixed bug that allowed to call disabled extensions. --- src/gba/hardware-extensions.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index d7fa298c95c..869f0831e6c 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -30,9 +30,8 @@ enum { void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hwExtensions) { hwExtensions->enabled = false; - // TODO: read this from the config - hwExtensions->userEnabled = true; - memset(hwExtensions->userEnabledFlags, 0xFF, sizeof(hwExtensions->userEnabledFlags)); + hwExtensions->userEnabled = false; + memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); memset(hwExtensions->memory, 0, sizeof(hwExtensions->memory)); } @@ -210,11 +209,24 @@ static uint16_t GetExtensionIdFromAddress(uint32_t address) { #undef SIMPLIFY_HWEX_REG_ADDRESS +static bool GBAHardwareExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { + uint32_t index = extensionId / 16; + uint32_t bit = extensionId % 16; + return (_GBAHardwareExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; +} + static void GBAHardwareExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { uint16_t* cnt = GetHwExIOPointer(gba, cntAddress); uint16_t* returnCode = cnt + 1; uint16_t currentValue = *cnt; - const struct HardwareExtensionHandlers* handlers = extensionHandlers + GetExtensionIdFromAddress(cntAddress); + uint32_t extensionId = GetExtensionIdFromAddress(cntAddress); + + if (!GBAHardwareExtensionsIsExtensionEnabled(gba, extensionId)) { + *returnCode = HWEX_RET_ERR_DISABLED; + return; + } + + const struct HardwareExtensionHandlers* handlers = extensionHandlers + extensionId; value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed From 7a12e6acdaaab0b7445c2ab3aa0293f8ef2ee7aa Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sat, 10 Jul 2021 16:45:25 -0300 Subject: [PATCH 06/21] Added command line arguments to enable extensions. --- include/mgba/core/config.h | 4 ++++ include/mgba/feature/commandline.h | 3 +++ src/core/config.c | 18 ++++++++++++++++++ src/feature/commandline.c | 30 ++++++++++++++++++++++++++++++ src/gba/core.c | 23 +++++++++++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 063b14e02f1..421cce09223 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -58,6 +58,10 @@ struct mCoreOptions { bool videoSync; bool audioSync; + + // Extensions + bool hwExtensions; + uint16_t hwExtensionsFlags[5]; }; void mCoreConfigInit(struct mCoreConfig*, const char* port); diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index c543652e983..9cf3b91ac89 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -29,6 +29,9 @@ struct mArguments { bool debugAtStart; bool showHelp; bool showVersion; + + bool hwExtensions; + uint16_t hwExtensionsFlags[5]; }; struct mCoreConfig; diff --git a/src/core/config.c b/src/core/config.c index 9f54aca265c..bfaea024927 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -440,6 +440,17 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupCharValue(config, "screenshotPath", &opts->screenshotPath); _lookupCharValue(config, "patchPath", &opts->patchPath); _lookupCharValue(config, "cheatsPath", &opts->cheatsPath); + + _lookupIntValue(config, "hwExtensions", &fakeBool); + opts->hwExtensions = fakeBool; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; + uint32_t value32; + for (size_t i = 0; i < (sizeof(opts->hwExtensionsFlags) / sizeof(opts->hwExtensionsFlags[0])); i++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; + if (_lookupUIntValue(config, hwExtensionsFlagsKey, &value32)) { + opts->hwExtensionsFlags[i] = (uint16_t)value32; + } + } } void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts) { @@ -465,6 +476,13 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "lockIntegerScaling", opts->lockIntegerScaling); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver); + + ConfigurationSetIntValue(&config->defaultsTable, 0, "hwExtensions", opts->hwExtensions); + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; + for (size_t i = 0; i < (sizeof(opts->hwExtensionsFlags) / sizeof(opts->hwExtensionsFlags[0])); i++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; + ConfigurationSetIntValue(&config->defaultsTable, 0, hwExtensionsFlagsKey, opts->hwExtensionsFlags[i]); + } } static void _configEnum(const char* key, const char* value, void* user) { diff --git a/src/feature/commandline.c b/src/feature/commandline.c index 2d3f3e357f3..311cc1e2eaa 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -42,6 +42,10 @@ static const struct option _options[] = { { "savestate", required_argument, 0, 't' }, { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' }, + // Extensions + { "hw-extensions", no_argument, 0, 0x1000 }, + { "hwex-all", no_argument, 0, 0x1001 }, + { "hwex-more-ram", no_argument, 0, 0x1002 }, { 0, 0, 0, 0 } }; @@ -135,6 +139,24 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct case 't': args->savestate = strdup(optarg); break; + + // Extensions + case 0x1000: + // enable extensions + args->hwExtensions = true; + break; + case 0x1001: + // enable all extensions + memset(args->hwExtensionsFlags, 0xFF, sizeof(args->hwExtensionsFlags)); + break; + case 0x1002: { + // enable 1 extension + size_t extensionId = ch - 0x1002; + size_t index = extensionId / (8 * sizeof(args->hwExtensionsFlags[0])); + size_t offset = extensionId % (8 * sizeof(args->hwExtensionsFlags[0])); + args->hwExtensionsFlags[index] |= 1 << offset; + break; + } default: if (subparser) { if (!subparser->parse(subparser, ch, optarg)) { @@ -166,6 +188,14 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser, if (args->bios) { mCoreConfigSetOverrideValue(config, "bios", args->bios); } + if (args->hwExtensions) { + mCoreConfigSetOverrideIntValue(config, "hwExtensions", args->hwExtensions); + } + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; + for (size_t i = 0; i < (sizeof(args->hwExtensionsFlags) / sizeof(args->hwExtensionsFlags[0])); i++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; + mCoreConfigSetOverrideUIntValue(config, hwExtensionsFlagsKey, args->hwExtensionsFlags[i]); + } HashTableEnumerate(&args->configOverrides, _tableApply, config); if (subparser) { subparser->apply(subparser, config); diff --git a/src/gba/core.c b/src/gba/core.c index 88171fbeb89..c7c347be1eb 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -272,6 +272,9 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con } gba->video.frameskip = core->opts.frameskip; + gba->hwExtensions.userEnabled = core->opts.hwExtensions; + memcpy(gba->hwExtensions.userEnabledFlags, core->opts.hwExtensionsFlags, sizeof(gba->hwExtensions.userEnabledFlags)); + #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 struct GBACore* gbacore = (struct GBACore*) core; gbacore->overrides = mCoreConfigGetOverridesConst(config); @@ -361,6 +364,26 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c return; } + if (strcmp("hwExtensions", option) == 0) { + if (mCoreConfigGetIntValue(config, "hwExtensions", &fakeBool)) { + core->opts.hwExtensions = fakeBool; + gba->hwExtensions.userEnabled = core->opts.hwExtensions; + } + return; + } + + if (strcmp("hwExtensionsFlags", option) == 0) { + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; + uint32_t value32; + for (size_t i = 0; i < (sizeof(core->opts.hwExtensionsFlags) / sizeof(core->opts.hwExtensionsFlags[0])); i++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; + if (mCoreConfigGetUIntValue(config, hwExtensionsFlagsKey, &value32)) { + core->opts.hwExtensionsFlags[i] = (uint16_t)value32; + gba->hwExtensions.userEnabledFlags[i] = core->opts.hwExtensionsFlags[i]; + } + } + } + struct GBACore* gbacore = (struct GBACore*) core; #if defined(BUILD_GLES2) || defined(BUILD_GLES3) if (strcmp("videoScale", option) == 0) { From 36f5879e4d9ec06b09f9bd8368e2096c0a689a36 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sat, 10 Jul 2021 21:54:17 -0300 Subject: [PATCH 07/21] Added initial hardware extensions serialization support. --- include/mgba/core/core.h | 3 +++ include/mgba/core/serialize.h | 2 ++ include/mgba/internal/gba/hardware-extensions.h | 13 +++++++++++++ src/core/serialize.c | 16 ++++++++++++++++ src/gba/core.c | 17 +++++++++++++++++ src/gba/hardware-extensions.c | 17 +++++++++++++++++ 6 files changed, 68 insertions(+) diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 3475c393dfa..506c656638f 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -160,6 +160,9 @@ struct mCore { void (*startVideoLog)(struct mCore*, struct mVideoLogContext*); void (*endVideoLog)(struct mCore*); #endif + + size_t (*hwExtensionsSerialize)(struct mCore*, void** sram); + bool (*hwExtensionsDeserialize)(struct mCore*, const void* sram, size_t size); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/include/mgba/core/serialize.h b/include/mgba/core/serialize.h index 968f3f16f05..7c2d58686cc 100644 --- a/include/mgba/core/serialize.h +++ b/include/mgba/core/serialize.h @@ -16,6 +16,7 @@ enum mStateExtdataTag { EXTDATA_SAVEDATA = 2, EXTDATA_CHEATS = 3, EXTDATA_RTC = 4, + EXTDATA_HW_EXTENSIONS = 5, EXTDATA_META_TIME = 0x101, EXTDATA_MAX }; @@ -25,6 +26,7 @@ enum mStateExtdataTag { #define SAVESTATE_CHEATS 4 #define SAVESTATE_RTC 8 #define SAVESTATE_METADATA 16 +#define SAVESTATE_HW_EXTENSIONS 32 struct mStateExtdataItem { int32_t size; diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h index be21e57c1d8..04e2c7ba467 100644 --- a/include/mgba/internal/gba/hardware-extensions.h +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -30,6 +30,17 @@ struct GBAHardwareExtensions { uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; + +struct GBAHardwareExtensionsState { + uint32_t enabled; // boolean + // IO: + uint32_t memory[128]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; +}; + + struct GBA; void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hw); uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address); @@ -37,5 +48,7 @@ uint32_t GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address); void GBAHardwareExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value); void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t value); +bool GBAHardwareExtensionsSerialize(struct GBA* gba, struct GBAHardwareExtensionsState* state); +bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareExtensionsState* state, size_t size); #endif diff --git a/src/core/serialize.c b/src/core/serialize.c index 446152e0414..3a9fa4b4e7a 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -421,6 +421,18 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { mStateExtdataPut(&extdata, EXTDATA_RTC, &item); } } + if ((true || flags & SAVESTATE_HW_EXTENSIONS) && core->hwExtensionsSerialize) { + void* sram = NULL; + size_t size = core->hwExtensionsSerialize(core, &sram); + if (size) { + struct mStateExtdataItem item = { + .size = size, + .data = sram, + .clean = free + }; + mStateExtdataPut(&extdata, EXTDATA_HW_EXTENSIONS, &item); + } + } #ifdef USE_PNG if (!(flags & SAVESTATE_SCREENSHOT)) { #else @@ -537,6 +549,10 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { core->rtc.d.deserialize(&core->rtc.d, &item); } } + if ((true || flags & SAVESTATE_HW_EXTENSIONS) && core->hwExtensionsDeserialize && mStateExtdataGet(&extdata, EXTDATA_HW_EXTENSIONS, &item)) { + mLOG(SAVESTATE, INFO, "Loading hardware extensions"); + core->hwExtensionsDeserialize(core, item.data, item.size); + } mStateExtdataDeinit(&extdata); return success; } diff --git a/src/gba/core.c b/src/gba/core.c index c7c347be1eb..b690cc209c9 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -1175,6 +1175,21 @@ static void _GBACoreEndVideoLog(struct mCore* core) { } #endif +static size_t _GBAHardwareExtensionsSerialize(struct mCore* core, void** sram) { + size_t size = sizeof(struct GBAHardwareExtensionsState); + *sram = malloc(size); + if (!GBAHardwareExtensionsSerialize(core->board, sram)) { + free(*sram); + size = 0; + *sram = NULL; + } + return size; +} + +static bool _GBAHardwareExtensionsDeserialize(struct mCore* core, const void* sram, size_t size) { + return GBAHardwareExtensionsDeserialize(core->board, sram, size); +} + struct mCore* GBACoreCreate(void) { struct GBACore* gbacore = malloc(sizeof(*gbacore)); struct mCore* core = &gbacore->d; @@ -1259,6 +1274,8 @@ struct mCore* GBACoreCreate(void) { core->startVideoLog = _GBACoreStartVideoLog; core->endVideoLog = _GBACoreEndVideoLog; #endif + core->hwExtensionsSerialize = NULL; + core->hwExtensionsDeserialize = NULL; return core; } diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index 869f0831e6c..bbe034d2ff0 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -314,3 +314,20 @@ void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t GBAHardwareExtensionsIOWrite(gba, address + 2, value >> 16); } +bool GBAHardwareExtensionsSerialize(struct GBA* gba, struct GBAHardwareExtensionsState* state) { + state->enabled = gba->hwExtensions.enabled; + memcpy(state->memory, gba->hwExtensions.memory, sizeof(gba->hwExtensions.memory)); + memcpy(state->moreRam, gba->hwExtensions.moreRam, sizeof(gba->hwExtensions.moreRam)); + return true; +} + +bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareExtensionsState* state, size_t size) { + if (size < sizeof(*state)) { + return false; + } + gba->hwExtensions.enabled = state->enabled; + memcpy(gba->hwExtensions.memory, state->memory, sizeof(gba->hwExtensions.memory)); + memcpy(gba->hwExtensions.moreRam, state->moreRam, sizeof(gba->hwExtensions.moreRam)); + + return true; +} From 71e4e6ce3ac5b0a5b59e849f3c5d4979ebe5623b Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 11 Jul 2021 13:37:01 -0300 Subject: [PATCH 08/21] Organized hardware extensions code a bit. --- .../mgba/internal/gba/hardware-extensions.h | 6 +- src/gba/hardware-extensions.c | 80 ++++++++++--------- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h index 04e2c7ba467..b484a959d2e 100644 --- a/include/mgba/internal/gba/hardware-extensions.h +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -14,7 +14,7 @@ #include -#define HWEX_EXTENSIONS_COUNT 1 +#define HWEX_EXTENSIONS_COUNT ((REG_HWEX_END - REG_HWEX_ENABLE) / 2) #define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB @@ -24,7 +24,7 @@ struct GBAHardwareExtensions { uint16_t userEnabledFlags[5]; // IO: - uint32_t memory[(REG_HWEX_END - REG_HWEX_ENABLE) / sizeof(uint32_t)]; + uint32_t memory[HWEX_EXTENSIONS_COUNT / 2]; // Other data uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; @@ -33,6 +33,8 @@ struct GBAHardwareExtensions { struct GBAHardwareExtensionsState { uint32_t enabled; // boolean + uint32_t version; + // IO: uint32_t memory[128]; diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index bbe034d2ff0..88bd04ac33c 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -27,6 +27,42 @@ enum { HWEX_ID_MORE_RAM = 0 }; +#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) + +const uint16_t extensionIdByRegister[] = { + // More RAM + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, +}; + +static uint16_t GetExtensionIdFromAddress(uint32_t address) { + return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; +} + +#undef SIMPLIFY_HWEX_REG_ADDRESS + +// CNT flags +// Writable +#define HWEX_CNT_FLAG_CALL 1 +#define HWEX_CNT_ALL_WRITABLE (HWEX_CNT_FLAG_CALL) +// Read only +#define HWEX_CNT_FLAG_PROCESSING (1 << 15) + +struct HardwareExtensionHandlers { + uint16_t (*onCall)(struct GBA* gba); + bool (*onAbort)(void); +}; + +static const struct HardwareExtensionHandlers extensionHandlers[]; + void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hwExtensions) { hwExtensions->enabled = false; @@ -171,44 +207,6 @@ static void _GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uin *GetHwExIOPointer(gba, address) = value; } -// CNT flags -// Writable -#define HWEX_CNT_FLAG_CALL 1 -#define HWEX_CNT_ALL_WRITABLE (HWEX_CNT_FLAG_CALL) -// Read only -#define HWEX_CNT_FLAG_PROCESSING (1 << 15) - -struct HardwareExtensionHandlers { - uint16_t (*onCall)(struct GBA* gba); - bool (*onAbort)(void); -}; - -static const struct HardwareExtensionHandlers extensionHandlers[] = { - [HWEX_ID_MORE_RAM] = { .onCall = MGBAHwExtMoreRAM, .onAbort = NULL } -}; - -#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) - -const uint16_t extensionIdByRegister[] = { - // More RAM - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, -}; - -static uint16_t GetExtensionIdFromAddress(uint32_t address) { - return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; -} - -#undef SIMPLIFY_HWEX_REG_ADDRESS - static bool GBAHardwareExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { uint32_t index = extensionId / 16; uint32_t bit = extensionId % 16; @@ -316,6 +314,7 @@ void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t bool GBAHardwareExtensionsSerialize(struct GBA* gba, struct GBAHardwareExtensionsState* state) { state->enabled = gba->hwExtensions.enabled; + state->version = REG_HWEX_VERSION_VALUE; memcpy(state->memory, gba->hwExtensions.memory, sizeof(gba->hwExtensions.memory)); memcpy(state->moreRam, gba->hwExtensions.moreRam, sizeof(gba->hwExtensions.moreRam)); return true; @@ -331,3 +330,8 @@ bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareE return true; } + + +static const struct HardwareExtensionHandlers extensionHandlers[] = { + [HWEX_ID_MORE_RAM] = { .onCall = MGBAHwExtMoreRAM, .onAbort = NULL } +}; From 58450e680c756ad5a916a29eaceb1ec0f63302ff Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 11 Jul 2021 13:38:38 -0300 Subject: [PATCH 09/21] Organized hardware extensions code a bit more... --- src/gba/hardware-extensions.c | 175 +++++++++++++++++----------------- 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index 88bd04ac33c..85e106f5759 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -117,92 +117,6 @@ static uint32_t _GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address return gba->hwExtensions.memory[GetHwExMemoryIndex32FromAddress(address)]; }; -static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { - uint32_t addressPrefix = (address >> 24) & 0xF; - uint8_t* pointer = NULL; - *isRom = false; - - if (addressPrefix == 2) { - if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { - pointer = (uint8_t*) gba->memory.wram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); - } - } else if (addressPrefix == 3) { - if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { - pointer = (uint8_t*) gba->memory.iwram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); - } - } else if (addressPrefix & 8) { - if ((address & 0x1FFFFFF) < gba->memory.romSize) { - *isRom = true; - pointer = (uint8_t*) gba->memory.rom; - pointer += address & 0x1FFFFFF; - *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); - } - } - - return pointer; -} - -enum HwExMoreRAMCommands { - HwExtMoreRAMMemoryWrite = 0, - HwExtMoreRAMMemoryRead = 1, - HwExtMoreRAMMemorySwap = 2 -}; - -static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { - uint32_t command = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); - uint32_t index = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); - uint32_t dataPointer = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); - uint32_t dataSize = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); - void* data; - // Check if the pointer is valid - bool isRom; - uint32_t memoryMaxSize; - data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); - if (data == NULL) { - return HWEX_RET_ERR_BAD_ADDRESS; - } - - // Check if index and size are valid - if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - switch (command) { - case HwExtMoreRAMMemoryWrite: - memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); - break; - case HwExtMoreRAMMemoryRead: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - memcpy(data, ((uint8_t*)gba->hwExtensions.moreRam) + index, dataSize); - break; - case HwExtMoreRAMMemorySwap: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - // TODO: make this more efficient - uint8_t* data1 = data; - uint8_t* data2 = (uint8_t*) gba->hwExtensions.moreRam; - data2 += index; - for (uint32_t i = 0; i < dataSize; i++) { - uint8_t aux = data1[i]; - data1[i] = data2[i]; - data2[i] = aux; - } - break; - default: - // invalid command - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - return HWEX_RET_OK; -} - static void _GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { *GetHwExIOPointer(gba, address) = value; } @@ -332,6 +246,95 @@ bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareE } + +// Extension handlers + +static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { + uint32_t addressPrefix = (address >> 24) & 0xF; + uint8_t* pointer = NULL; + *isRom = false; + + if (addressPrefix == 2) { + if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { + pointer = (uint8_t*) gba->memory.wram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); + } + } else if (addressPrefix == 3) { + if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { + pointer = (uint8_t*) gba->memory.iwram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); + } + } else if (addressPrefix & 8) { + if ((address & 0x1FFFFFF) < gba->memory.romSize) { + *isRom = true; + pointer = (uint8_t*) gba->memory.rom; + pointer += address & 0x1FFFFFF; + *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); + } + } + + return pointer; +} + +enum HwExMoreRAMCommands { + HwExtMoreRAMMemoryWrite = 0, + HwExtMoreRAMMemoryRead = 1, + HwExtMoreRAMMemorySwap = 2 +}; + +static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { + uint32_t command = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); + uint32_t index = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); + uint32_t dataPointer = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); + uint32_t dataSize = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); + void* data; + // Check if the pointer is valid + bool isRom; + uint32_t memoryMaxSize; + data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); + if (data == NULL) { + return HWEX_RET_ERR_BAD_ADDRESS; + } + + // Check if index and size are valid + if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + switch (command) { + case HwExtMoreRAMMemoryWrite: + memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); + break; + case HwExtMoreRAMMemoryRead: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + memcpy(data, ((uint8_t*)gba->hwExtensions.moreRam) + index, dataSize); + break; + case HwExtMoreRAMMemorySwap: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + // TODO: make this more efficient + uint8_t* data1 = data; + uint8_t* data2 = (uint8_t*) gba->hwExtensions.moreRam; + data2 += index; + for (uint32_t i = 0; i < dataSize; i++) { + uint8_t aux = data1[i]; + data1[i] = data2[i]; + data2[i] = aux; + } + break; + default: + // invalid command + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + return HWEX_RET_OK; +} + static const struct HardwareExtensionHandlers extensionHandlers[] = { [HWEX_ID_MORE_RAM] = { .onCall = MGBAHwExtMoreRAM, .onAbort = NULL } }; From e3d7cad3d9686b71119f6f78f0757e691a46ea8a Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 11 Jul 2021 14:41:31 -0300 Subject: [PATCH 10/21] Moved some hardcoded stuff to a hardware extensions header file. --- include/mgba/core/config.h | 4 +++- include/mgba/feature/commandline.h | 4 +++- .../internal/gba/hardware-extensions-ids.h | 16 +++++++++++++++ .../mgba/internal/gba/hardware-extensions.h | 6 +++--- src/feature/commandline.c | 20 ++++++++++--------- src/gba/hardware-extensions.c | 4 ---- 6 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 include/mgba/internal/gba/hardware-extensions-ids.h diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 421cce09223..56b11c5c3b8 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -12,6 +12,8 @@ CXX_GUARD_START #include +#include + struct mCoreConfig { struct Configuration configTable; struct Configuration defaultsTable; @@ -61,7 +63,7 @@ struct mCoreOptions { // Extensions bool hwExtensions; - uint16_t hwExtensionsFlags[5]; + uint16_t hwExtensionsFlags[HWEX_FLAGS_REGISTERS_COUNT]; }; void mCoreConfigInit(struct mCoreConfig*, const char* port); diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index 9cf3b91ac89..5d5f6817f18 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -14,6 +14,8 @@ CXX_GUARD_START #include +#include + struct mArguments { char* fname; char* patch; @@ -31,7 +33,7 @@ struct mArguments { bool showVersion; bool hwExtensions; - uint16_t hwExtensionsFlags[5]; + uint16_t hwExtensionsFlags[HWEX_FLAGS_REGISTERS_COUNT]; }; struct mCoreConfig; diff --git a/include/mgba/internal/gba/hardware-extensions-ids.h b/include/mgba/internal/gba/hardware-extensions-ids.h new file mode 100644 index 00000000000..eb77425d543 --- /dev/null +++ b/include/mgba/internal/gba/hardware-extensions-ids.h @@ -0,0 +1,16 @@ +/* Copyright (c) 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 HARDWARE_EXTENSIONS_IDS_H +#define HARDWARE_EXTENSIONS_IDS_H + +enum HARDWARE_EXTENSIONS_IDS { + HWEX_ID_MORE_RAM = 0, + HWEX_EXTENSIONS_COUNT +}; + +#define HWEX_FLAGS_REGISTERS_COUNT ((HWEX_EXTENSIONS_COUNT / 16) + (HWEX_EXTENSIONS_COUNT % 16 ? 1 : 0)) + +#endif diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h index b484a959d2e..8efac1ace0a 100644 --- a/include/mgba/internal/gba/hardware-extensions.h +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -12,16 +12,16 @@ #include #include +#include -#define HWEX_EXTENSIONS_COUNT ((REG_HWEX_END - REG_HWEX_ENABLE) / 2) #define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB struct GBAHardwareExtensions { bool enabled; bool userEnabled; - uint16_t userEnabledFlags[5]; + uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; // IO: uint32_t memory[HWEX_EXTENSIONS_COUNT / 2]; @@ -34,7 +34,7 @@ struct GBAHardwareExtensions { struct GBAHardwareExtensionsState { uint32_t enabled; // boolean uint32_t version; - + // IO: uint32_t memory[128]; diff --git a/src/feature/commandline.c b/src/feature/commandline.c index 311cc1e2eaa..f601af65b23 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -27,6 +27,8 @@ " -6 6x viewport\n" \ " -f Start full-screen" +#define HWEX_ARGS_OFFSET 0x1002 + static const struct option _options[] = { { "bios", required_argument, 0, 'b' }, { "cheats", required_argument, 0, 'c' }, @@ -43,9 +45,9 @@ static const struct option _options[] = { { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' }, // Extensions - { "hw-extensions", no_argument, 0, 0x1000 }, - { "hwex-all", no_argument, 0, 0x1001 }, - { "hwex-more-ram", no_argument, 0, 0x1002 }, + { "hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 2 }, + { "hwex-all", no_argument, 0, HWEX_ARGS_OFFSET - 1 }, + { "hwex-more-ram", no_argument, 0, HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM }, { 0, 0, 0, 0 } }; @@ -141,19 +143,19 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct break; // Extensions - case 0x1000: + case HWEX_ARGS_OFFSET - 2: // enable extensions args->hwExtensions = true; break; - case 0x1001: + case HWEX_ARGS_OFFSET - 1: // enable all extensions memset(args->hwExtensionsFlags, 0xFF, sizeof(args->hwExtensionsFlags)); break; - case 0x1002: { + case HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM: { // enable 1 extension - size_t extensionId = ch - 0x1002; - size_t index = extensionId / (8 * sizeof(args->hwExtensionsFlags[0])); - size_t offset = extensionId % (8 * sizeof(args->hwExtensionsFlags[0])); + size_t extensionId = ch - HWEX_ARGS_OFFSET; + size_t index = extensionId / 16; + size_t offset = extensionId % 16; args->hwExtensionsFlags[index] |= 1 << offset; break; } diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index 85e106f5759..dba365398de 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -23,10 +23,6 @@ enum HWEX_RETURN_CODES { HWEX_RET_ERR_DISABLED_BY_USER = 0x106 }; -enum { - HWEX_ID_MORE_RAM = 0 -}; - #define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) const uint16_t extensionIdByRegister[] = { From 6223cd7e392ef9627c25593388c84e5b24ae257d Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 18 Jul 2021 21:09:26 -0300 Subject: [PATCH 11/21] Designed hardware extensions Qt UI. Functionality missing. --- src/platform/qt/CMakeLists.txt | 2 + src/platform/qt/HardwareExtensionsView.cpp | 83 ++++++++++++++++++++++ src/platform/qt/HardwareExtensionsView.h | 32 +++++++++ src/platform/qt/HardwareExtensionsView.ui | 59 +++++++++++++++ src/platform/qt/SettingsView.cpp | 4 ++ src/platform/qt/SettingsView.h | 1 + 6 files changed, 181 insertions(+) create mode 100644 src/platform/qt/HardwareExtensionsView.cpp create mode 100644 src/platform/qt/HardwareExtensionsView.h create mode 100644 src/platform/qt/HardwareExtensionsView.ui diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 9ae96e964a8..a474f093ba7 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -80,6 +80,7 @@ set(SOURCE_FILES GamepadAxisEvent.cpp GamepadButtonEvent.cpp GamepadHatEvent.cpp + HardwareExtensionsView.cpp IOViewer.cpp InputController.cpp InputProfile.cpp @@ -130,6 +131,7 @@ set(UI_FILES DolphinConnector.ui FrameView.ui GIFView.ui + HardwareExtensionsView.ui IOViewer.ui LoadSaveState.ui LogView.ui diff --git a/src/platform/qt/HardwareExtensionsView.cpp b/src/platform/qt/HardwareExtensionsView.cpp new file mode 100644 index 00000000000..fa7a9efb18d --- /dev/null +++ b/src/platform/qt/HardwareExtensionsView.cpp @@ -0,0 +1,83 @@ +/* Copyright (c) 2013-2015 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 "HardwareExtensionsView.h" + +#include + +#include + +#include "ConfigController.h" + + +struct HwExtensionDescription { + int id; + const char* description; +}; + +const struct HwExtensionDescription hwExtensionsDescriptions[] = { + { .id = HWEX_ID_MORE_RAM +6, .description = "More RAM" }, +}; + +#define EXTENSIONS_ROWS (sizeof(hwExtensionsDescriptions) / sizeof(hwExtensionsDescriptions[0])) + + +using namespace QGBA; + + + +HardwareExtensionsView::HardwareExtensionsView(ConfigController* controller, QWidget* parent) + : QWidget(parent) + , m_controller(controller) +{ + enabledCounter = 0; + m_ui.setupUi(this); + + // Add "All" checkbox + QCheckBox* cb = new QCheckBox(this); + m_ui.individualEnableTable->setCellWidget(0, 0, cb); + connect(cb, &QCheckBox::stateChanged, this, [this](int state) { + QCheckBox* cb; + for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { + cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(1 + i, 0); + if (state != cb->checkState()) { + cb->setCheckState((Qt::CheckState) state); + } + } + }); + + // Add the rest of checkboxes + m_ui.individualEnableTable->setRowCount(1 + EXTENSIONS_ROWS); + for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { + cb = new QCheckBox(this); + m_ui.individualEnableTable->setVerticalHeaderItem(i + 1, new QTableWidgetItem(tr(hwExtensionsDescriptions[i].description))); + m_ui.individualEnableTable->setCellWidget(i + 1, 0, cb); + connect(cb, &QCheckBox::stateChanged, this, [this, i](int state) { + bool enabled = state == Qt::Checked; + QCheckBox* cbAll = (QCheckBox*) m_ui.individualEnableTable->cellWidget(0, 0); + + // Update "All" checkbox + enabledCounter += enabled ? 1 : -1; + switch (cbAll->checkState()) { + case Qt::Checked: + if (enabledCounter < EXTENSIONS_ROWS) { + cbAll->blockSignals(true); + cbAll->setCheckState(Qt::Unchecked); + cbAll->blockSignals(false); + } + break; + default: + if (enabledCounter == EXTENSIONS_ROWS) { + cbAll->blockSignals(true); + cbAll->setCheckState(Qt::Checked); + cbAll->blockSignals(false); + } + } + }); + } +} + +HardwareExtensionsView::~HardwareExtensionsView() { +} diff --git a/src/platform/qt/HardwareExtensionsView.h b/src/platform/qt/HardwareExtensionsView.h new file mode 100644 index 00000000000..f736f1e16c3 --- /dev/null +++ b/src/platform/qt/HardwareExtensionsView.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2013-2015 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/. */ +#pragma once + + + +#include + +#include "ui_HardwareExtensionsView.h" + +namespace QGBA { + +class ConfigController; + +class HardwareExtensionsView : public QWidget { +Q_OBJECT + +public: + HardwareExtensionsView(ConfigController* controller, QWidget* parent = nullptr); + ~HardwareExtensionsView(); + +private: + Ui::HardwareExtensionsView m_ui; + ConfigController* m_controller; + unsigned int enabledCounter; + +}; + +} \ No newline at end of file diff --git a/src/platform/qt/HardwareExtensionsView.ui b/src/platform/qt/HardwareExtensionsView.ui new file mode 100644 index 00000000000..982a840bd01 --- /dev/null +++ b/src/platform/qt/HardwareExtensionsView.ui @@ -0,0 +1,59 @@ + + + HardwareExtensionsView + + + + 0 + 0 + 432 + 443 + + + + Edit Shortcuts + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable hardware extensions + + + + + + + + + + All + + + + + Enable + + + + + + + + + diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 5de04fa9d3c..62de1c19f41 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -14,6 +14,7 @@ #include "RotatedHeaderView.h" #include "ShaderSelector.h" #include "ShortcutView.h" +#include "HardwareExtensionsView.h" #ifdef M_CORE_GB #include "GameBoy.h" @@ -336,6 +337,9 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC shortcutView->setController(shortcutController); shortcutView->setInputController(inputController); addPage(tr("Shortcuts"), shortcutView, Page::SHORTCUTS); + + HardwareExtensionsView* hwExtensionsView = new HardwareExtensionsView(m_controller); + addPage(tr("Hardware extensions"), hwExtensionsView, Page::HARDWARE_EXTENSIONS); } SettingsView::~SettingsView() { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 880db5f14c9..0a087f1b007 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -43,6 +43,7 @@ Q_OBJECT CONTROLLERS, SHORTCUTS, SHADERS, + HARDWARE_EXTENSIONS, }; SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent = nullptr); From 3b0b9c3155197aa7b07faa13a244d8a6dfd8ba68 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Mon, 19 Jul 2021 16:21:24 -0300 Subject: [PATCH 12/21] Fixed some bugs that happened after refactoring. --- .../mgba/internal/gba/hardware-extensions.h | 2 +- src/gba/core.c | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h index 8efac1ace0a..d9fd8180d49 100644 --- a/include/mgba/internal/gba/hardware-extensions.h +++ b/include/mgba/internal/gba/hardware-extensions.h @@ -24,7 +24,7 @@ struct GBAHardwareExtensions { uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; // IO: - uint32_t memory[HWEX_EXTENSIONS_COUNT / 2]; + uint32_t memory[(REG_HWEX_END - REG_HWEX_ENABLE) / 2]; // Other data uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; diff --git a/src/gba/core.c b/src/gba/core.c index b690cc209c9..d2cd9b3ab1d 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -373,14 +373,24 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c } if (strcmp("hwExtensionsFlags", option) == 0) { - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; - uint32_t value32; - for (size_t i = 0; i < (sizeof(core->opts.hwExtensionsFlags) / sizeof(core->opts.hwExtensionsFlags[0])); i++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; - if (mCoreConfigGetUIntValue(config, hwExtensionsFlagsKey, &value32)) { - core->opts.hwExtensionsFlags[i] = (uint16_t)value32; - gba->hwExtensions.userEnabledFlags[i] = core->opts.hwExtensionsFlags[i]; + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; + for (size_t index = 0; index <= (HWEX_EXTENSIONS_COUNT >> 4); index++) { + for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { + uint16_t bitFlag = (1 << offset); + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; + if (mCoreConfigGetIntValue(config, hwExtensionsFlagsKey, &fakeBool)) { + if (fakeBool) { + core->opts.hwExtensionsFlags[index] |= bitFlag; + } else { + core->opts.hwExtensionsFlags[index] &= 0xFFFF ^ bitFlag; + } + } } + gba->hwExtensions.userEnabledFlags[index] = core->opts.hwExtensionsFlags[index]; } } @@ -1178,7 +1188,7 @@ static void _GBACoreEndVideoLog(struct mCore* core) { static size_t _GBAHardwareExtensionsSerialize(struct mCore* core, void** sram) { size_t size = sizeof(struct GBAHardwareExtensionsState); *sram = malloc(size); - if (!GBAHardwareExtensionsSerialize(core->board, sram)) { + if (!GBAHardwareExtensionsSerialize(core->board, *sram)) { free(*sram); size = 0; *sram = NULL; @@ -1274,8 +1284,8 @@ struct mCore* GBACoreCreate(void) { core->startVideoLog = _GBACoreStartVideoLog; core->endVideoLog = _GBACoreEndVideoLog; #endif - core->hwExtensionsSerialize = NULL; - core->hwExtensionsDeserialize = NULL; + core->hwExtensionsSerialize = _GBAHardwareExtensionsSerialize; + core->hwExtensionsDeserialize = _GBAHardwareExtensionsDeserialize; return core; } From 77a0db97876e3b8aabaa07b16b6286a7c5cf4036 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Mon, 19 Jul 2021 16:33:15 -0300 Subject: [PATCH 13/21] Made each extension have its own config key. Made command line args to disable extensions. Merged HardwareExtensionsView into SettingsView, and finished it in the process. --- include/mgba/feature/commandline.h | 10 ++- src/core/config.c | 40 +++++++--- src/feature/commandline.c | 59 ++++++++++---- src/platform/qt/CMakeLists.txt | 2 - src/platform/qt/HardwareExtensionsView.cpp | 83 -------------------- src/platform/qt/HardwareExtensionsView.h | 32 -------- src/platform/qt/HardwareExtensionsView.ui | 59 -------------- src/platform/qt/SettingsView.cpp | 89 +++++++++++++++++++++- src/platform/qt/SettingsView.h | 2 + src/platform/qt/SettingsView.ui | 47 ++++++++++++ 10 files changed, 215 insertions(+), 208 deletions(-) delete mode 100644 src/platform/qt/HardwareExtensionsView.cpp delete mode 100644 src/platform/qt/HardwareExtensionsView.h delete mode 100644 src/platform/qt/HardwareExtensionsView.ui diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index 5d5f6817f18..1814778fb1e 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -16,6 +16,12 @@ CXX_GUARD_START #include +enum HwExSettingsOverrides { + HWEX_DONT_OVERRIDE = 0, + HWEX_ENABLE = 1, + HWEX_DISABLE = 2, +}; + struct mArguments { char* fname; char* patch; @@ -32,8 +38,8 @@ struct mArguments { bool showHelp; bool showVersion; - bool hwExtensions; - uint16_t hwExtensionsFlags[HWEX_FLAGS_REGISTERS_COUNT]; + char hwExtensions; + char hwExtensionsFlags[HWEX_EXTENSIONS_COUNT]; }; struct mCoreConfig; diff --git a/src/core/config.c b/src/core/config.c index bfaea024927..44c03d4ba60 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -443,12 +443,24 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupIntValue(config, "hwExtensions", &fakeBool); opts->hwExtensions = fakeBool; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; - uint32_t value32; - for (size_t i = 0; i < (sizeof(opts->hwExtensionsFlags) / sizeof(opts->hwExtensionsFlags[0])); i++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; - if (_lookupUIntValue(config, hwExtensionsFlagsKey, &value32)) { - opts->hwExtensionsFlags[i] = (uint16_t)value32; + + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; + for (size_t index = 0; index <= (HWEX_EXTENSIONS_COUNT >> 4); index++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; + + for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { + uint16_t bitFlag = (1 << offset); + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; + if (_lookupIntValue(config, hwExtensionsFlagsKey, &fakeBool)) { + if (fakeBool) { + opts->hwExtensionsFlags[index] |= bitFlag; + } else { + opts->hwExtensionsFlags[index] &= 0xFFFF ^ bitFlag; + } + } } } } @@ -478,10 +490,18 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver); ConfigurationSetIntValue(&config->defaultsTable, 0, "hwExtensions", opts->hwExtensions); - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; - for (size_t i = 0; i < (sizeof(opts->hwExtensionsFlags) / sizeof(opts->hwExtensionsFlags[0])); i++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; - ConfigurationSetIntValue(&config->defaultsTable, 0, hwExtensionsFlagsKey, opts->hwExtensionsFlags[i]); + + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; + for (size_t index = 0; index <= HWEX_EXTENSIONS_COUNT; index++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; + + for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; + ConfigurationSetIntValue(&config->defaultsTable, 0, hwExtensionsFlagsKey, (opts->hwExtensionsFlags[index] & (1 << offset)) != 0); + } } } diff --git a/src/feature/commandline.c b/src/feature/commandline.c index f601af65b23..cd8729884ae 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -28,6 +28,7 @@ " -f Start full-screen" #define HWEX_ARGS_OFFSET 0x1002 +#define HWEX_ARGS_NO_OFFSET (HWEX_ARGS_OFFSET + HWEX_EXTENSIONS_COUNT) static const struct option _options[] = { { "bios", required_argument, 0, 'b' }, @@ -45,9 +46,12 @@ static const struct option _options[] = { { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' }, // Extensions - { "hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 2 }, - { "hwex-all", no_argument, 0, HWEX_ARGS_OFFSET - 1 }, + { "hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 4 }, + { "no-hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 3 }, + { "hwex-all", no_argument, 0, HWEX_ARGS_OFFSET - 2 }, + { "hwex-none", no_argument, 0, HWEX_ARGS_OFFSET - 1 }, { "hwex-more-ram", no_argument, 0, HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM }, + { "no-hwex-more-ram", no_argument, 0, HWEX_ARGS_NO_OFFSET + HWEX_ID_MORE_RAM }, { 0, 0, 0, 0 } }; @@ -143,22 +147,30 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct break; // Extensions - case HWEX_ARGS_OFFSET - 2: + case HWEX_ARGS_OFFSET - 4: // enable extensions - args->hwExtensions = true; + args->hwExtensions = HWEX_ENABLE; break; - case HWEX_ARGS_OFFSET - 1: + case HWEX_ARGS_OFFSET - 3: + // enable extensions + args->hwExtensions = HWEX_DISABLE; + break; + case HWEX_ARGS_OFFSET - 2: // enable all extensions - memset(args->hwExtensionsFlags, 0xFF, sizeof(args->hwExtensionsFlags)); + memset(args->hwExtensionsFlags, HWEX_ENABLE, sizeof(args->hwExtensionsFlags)); + break; + case HWEX_ARGS_OFFSET - 1: + // disable all extensions + memset(args->hwExtensionsFlags, HWEX_DISABLE, sizeof(args->hwExtensionsFlags)); break; - case HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM: { + case HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM: // enable 1 extension - size_t extensionId = ch - HWEX_ARGS_OFFSET; - size_t index = extensionId / 16; - size_t offset = extensionId % 16; - args->hwExtensionsFlags[index] |= 1 << offset; + args->hwExtensionsFlags[ch - HWEX_ARGS_OFFSET] = HWEX_ENABLE; + break; + case HWEX_ARGS_NO_OFFSET + HWEX_ID_MORE_RAM: + // disable 1 extension + args->hwExtensionsFlags[ch - HWEX_ARGS_OFFSET] = HWEX_ENABLE; break; - } default: if (subparser) { if (!subparser->parse(subparser, ch, optarg)) { @@ -191,12 +203,18 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser, mCoreConfigSetOverrideValue(config, "bios", args->bios); } if (args->hwExtensions) { - mCoreConfigSetOverrideIntValue(config, "hwExtensions", args->hwExtensions); + mCoreConfigSetOverrideIntValue(config, "hwExtensions", args->hwExtensions == HWEX_ENABLE); } - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_X"; + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; for (size_t i = 0; i < (sizeof(args->hwExtensionsFlags) / sizeof(args->hwExtensionsFlags[0])); i++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = 'A' + i; - mCoreConfigSetOverrideUIntValue(config, hwExtensionsFlagsKey, args->hwExtensionsFlags[i]); + if (args->hwExtensionsFlags[i]) { + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[i & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(i >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(i >> 8) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(i >> 12) & 0xF]; + mCoreConfigSetOverrideIntValue(config, hwExtensionsFlagsKey, args->hwExtensionsFlags[i] == HWEX_ENABLE); + } } HashTableEnumerate(&args->configOverrides, _tableApply, config); if (subparser) { @@ -280,6 +298,15 @@ void usage(const char* arg0, const char* extraOptions) { puts(" -p, --patch FILE Apply a specified patch file when running"); puts(" -s, --frameskip N Skip every N frames"); puts(" --version Print version and exit"); + + puts("\nHardware extensions options:"); + puts(" --hw-extensions Enable hardware extensions"); + puts(" --no-hw-extensions Disable hardware extensions"); + puts(" --hwex-all Enable all hardware extensions"); + puts(" --hwex-none Disable all hardware extensions"); + puts(" --hwex-more-ram Enable hardware extension \"More RAM\""); + puts(" --no-hwex-more-ram Disable hardware extension \"More RAM\""); + if (extraOptions) { puts(extraOptions); } diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index a474f093ba7..9ae96e964a8 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -80,7 +80,6 @@ set(SOURCE_FILES GamepadAxisEvent.cpp GamepadButtonEvent.cpp GamepadHatEvent.cpp - HardwareExtensionsView.cpp IOViewer.cpp InputController.cpp InputProfile.cpp @@ -131,7 +130,6 @@ set(UI_FILES DolphinConnector.ui FrameView.ui GIFView.ui - HardwareExtensionsView.ui IOViewer.ui LoadSaveState.ui LogView.ui diff --git a/src/platform/qt/HardwareExtensionsView.cpp b/src/platform/qt/HardwareExtensionsView.cpp deleted file mode 100644 index fa7a9efb18d..00000000000 --- a/src/platform/qt/HardwareExtensionsView.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (c) 2013-2015 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 "HardwareExtensionsView.h" - -#include - -#include - -#include "ConfigController.h" - - -struct HwExtensionDescription { - int id; - const char* description; -}; - -const struct HwExtensionDescription hwExtensionsDescriptions[] = { - { .id = HWEX_ID_MORE_RAM +6, .description = "More RAM" }, -}; - -#define EXTENSIONS_ROWS (sizeof(hwExtensionsDescriptions) / sizeof(hwExtensionsDescriptions[0])) - - -using namespace QGBA; - - - -HardwareExtensionsView::HardwareExtensionsView(ConfigController* controller, QWidget* parent) - : QWidget(parent) - , m_controller(controller) -{ - enabledCounter = 0; - m_ui.setupUi(this); - - // Add "All" checkbox - QCheckBox* cb = new QCheckBox(this); - m_ui.individualEnableTable->setCellWidget(0, 0, cb); - connect(cb, &QCheckBox::stateChanged, this, [this](int state) { - QCheckBox* cb; - for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { - cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(1 + i, 0); - if (state != cb->checkState()) { - cb->setCheckState((Qt::CheckState) state); - } - } - }); - - // Add the rest of checkboxes - m_ui.individualEnableTable->setRowCount(1 + EXTENSIONS_ROWS); - for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { - cb = new QCheckBox(this); - m_ui.individualEnableTable->setVerticalHeaderItem(i + 1, new QTableWidgetItem(tr(hwExtensionsDescriptions[i].description))); - m_ui.individualEnableTable->setCellWidget(i + 1, 0, cb); - connect(cb, &QCheckBox::stateChanged, this, [this, i](int state) { - bool enabled = state == Qt::Checked; - QCheckBox* cbAll = (QCheckBox*) m_ui.individualEnableTable->cellWidget(0, 0); - - // Update "All" checkbox - enabledCounter += enabled ? 1 : -1; - switch (cbAll->checkState()) { - case Qt::Checked: - if (enabledCounter < EXTENSIONS_ROWS) { - cbAll->blockSignals(true); - cbAll->setCheckState(Qt::Unchecked); - cbAll->blockSignals(false); - } - break; - default: - if (enabledCounter == EXTENSIONS_ROWS) { - cbAll->blockSignals(true); - cbAll->setCheckState(Qt::Checked); - cbAll->blockSignals(false); - } - } - }); - } -} - -HardwareExtensionsView::~HardwareExtensionsView() { -} diff --git a/src/platform/qt/HardwareExtensionsView.h b/src/platform/qt/HardwareExtensionsView.h deleted file mode 100644 index f736f1e16c3..00000000000 --- a/src/platform/qt/HardwareExtensionsView.h +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (c) 2013-2015 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/. */ -#pragma once - - - -#include - -#include "ui_HardwareExtensionsView.h" - -namespace QGBA { - -class ConfigController; - -class HardwareExtensionsView : public QWidget { -Q_OBJECT - -public: - HardwareExtensionsView(ConfigController* controller, QWidget* parent = nullptr); - ~HardwareExtensionsView(); - -private: - Ui::HardwareExtensionsView m_ui; - ConfigController* m_controller; - unsigned int enabledCounter; - -}; - -} \ No newline at end of file diff --git a/src/platform/qt/HardwareExtensionsView.ui b/src/platform/qt/HardwareExtensionsView.ui deleted file mode 100644 index 982a840bd01..00000000000 --- a/src/platform/qt/HardwareExtensionsView.ui +++ /dev/null @@ -1,59 +0,0 @@ - - - HardwareExtensionsView - - - - 0 - 0 - 432 - 443 - - - - Edit Shortcuts - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Enable hardware extensions - - - - - - - - - - All - - - - - Enable - - - - - - - - - diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 62de1c19f41..55e2bfda13f 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -14,7 +14,6 @@ #include "RotatedHeaderView.h" #include "ShaderSelector.h" #include "ShortcutView.h" -#include "HardwareExtensionsView.h" #ifdef M_CORE_GB #include "GameBoy.h" @@ -25,6 +24,17 @@ #include #include +struct HwExtensionDescription { + int id; + const char* description; +}; + +const struct HwExtensionDescription hwExtensionsDescriptions[] = { + { .id = HWEX_ID_MORE_RAM, .description = "More RAM" }, +}; + +#define EXTENSIONS_ROWS (sizeof(hwExtensionsDescriptions) / sizeof(hwExtensionsDescriptions[0])) + using namespace QGBA; SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent) @@ -60,6 +70,52 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC m_ui.cgbSgbModel->setCurrentIndex(m_ui.gbModel->findData(GB_MODEL_CGB)); #endif + // Hardware extensions + m_enabledExtensionsCounter = 0; + + // Add "All" checkbox + QCheckBox* cb = new QCheckBox(this); + m_ui.individualEnableTable->setCellWidget(0, 0, cb); + connect(cb, &QCheckBox::stateChanged, this, [this](int state) { + QCheckBox* cb; + for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { + cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(1 + i, 0); + if (state != cb->checkState()) { + cb->setCheckState((Qt::CheckState) state); + } + } + }); + + // Add the rest of checkboxes + m_ui.individualEnableTable->setRowCount(1 + EXTENSIONS_ROWS); + for (unsigned int i = 0; i < EXTENSIONS_ROWS; i++) { + cb = new QCheckBox(this); + m_ui.individualEnableTable->setVerticalHeaderItem(i + 1, new QTableWidgetItem(tr(hwExtensionsDescriptions[i].description))); + m_ui.individualEnableTable->setCellWidget(i + 1, 0, cb); + connect(cb, &QCheckBox::stateChanged, this, [this, i](int state) { + bool enabled = state == Qt::Checked; + QCheckBox* cbAll = (QCheckBox*) m_ui.individualEnableTable->cellWidget(0, 0); + + // Update "All" checkbox + m_enabledExtensionsCounter += enabled ? 1 : -1; + switch (cbAll->checkState()) { + case Qt::Checked: + if (m_enabledExtensionsCounter < EXTENSIONS_ROWS) { + cbAll->blockSignals(true); + cbAll->setCheckState(Qt::Unchecked); + cbAll->blockSignals(false); + } + break; + default: + if (m_enabledExtensionsCounter == EXTENSIONS_ROWS) { + cbAll->blockSignals(true); + cbAll->setCheckState(Qt::Checked); + cbAll->blockSignals(false); + } + } + }); + } + reloadConfig(); connect(m_ui.volume, static_cast(&QSlider::valueChanged), [this](int v) { @@ -337,9 +393,6 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC shortcutView->setController(shortcutController); shortcutView->setInputController(inputController); addPage(tr("Shortcuts"), shortcutView, Page::SHORTCUTS); - - HardwareExtensionsView* hwExtensionsView = new HardwareExtensionsView(m_controller); - addPage(tr("Hardware extensions"), hwExtensionsView, Page::HARDWARE_EXTENSIONS); } SettingsView::~SettingsView() { @@ -605,6 +658,21 @@ void SettingsView::updateConfig() { saveSetting("gb.colors", gbColors); #endif + saveSetting("hwExtensions", m_ui.globalEnableCheckBox); + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; + for (size_t i = 0; i < EXTENSIONS_ROWS; i++) { + QCheckBox* cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(i + 1, 0); + unsigned int extensionId = hwExtensionsDescriptions[i].id; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[extensionId & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(extensionId >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(extensionId >> 8) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(extensionId >> 12) & 0xF]; + + saveSetting(hwExtensionsFlagsKey, cb); + } + + m_controller->write(); emit pathsChanged(); @@ -783,6 +851,19 @@ void SettingsView::reloadConfig() { } else { m_ui.multiplayerAudioAll->setChecked(true); } + + loadSetting("hwExtensions", m_ui.globalEnableCheckBox, false); + const char hexDigits[] = "0123456789ABCDEF"; + char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; + for (size_t i = 0; i < EXTENSIONS_ROWS; i++) { + unsigned int extensionId = hwExtensionsDescriptions[i].id; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[extensionId & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(extensionId >> 4) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(extensionId >> 8) & 0xF]; + hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(extensionId >> 12) & 0xF]; + + loadSetting(hwExtensionsFlagsKey, (QCheckBox*) m_ui.individualEnableTable->cellWidget(i + 1, 0), false); + } } void SettingsView::addPage(const QString& name, QWidget* view, Page index) { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 0a087f1b007..31f7f8be144 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -79,6 +79,8 @@ private slots: ShaderSelector* m_shader = nullptr; LogConfigModel m_logModel; + unsigned int m_enabledExtensionsCounter; + #ifdef M_CORE_GB uint32_t m_gbColors[12]{}; ColorPicker m_colorPickers[12]; diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index 7589e06f3a3..af74de83c8c 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -80,6 +80,11 @@ Game Boy + + + Hardware extensions + + @@ -2013,6 +2018,48 @@ + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Enable hardware extensions + + + + + + + + + + All + + + + + Enable + + + + + + From cedf69fe2ab6f4dc95c43cad3060684b3aa4de1a Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Mon, 19 Jul 2021 23:07:23 -0300 Subject: [PATCH 14/21] Moved hardware extensions settings into enhancements and redesigned UI. --- src/platform/qt/SettingsView.cpp | 136 ++++++++++++------------------- src/platform/qt/SettingsView.h | 1 + src/platform/qt/SettingsView.ui | 114 +++++++++++++++----------- 3 files changed, 121 insertions(+), 130 deletions(-) diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index 55e2bfda13f..abbfdf37eae 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -24,17 +24,6 @@ #include #include -struct HwExtensionDescription { - int id; - const char* description; -}; - -const struct HwExtensionDescription hwExtensionsDescriptions[] = { - { .id = HWEX_ID_MORE_RAM, .description = "More RAM" }, -}; - -#define EXTENSIONS_ROWS (sizeof(hwExtensionsDescriptions) / sizeof(hwExtensionsDescriptions[0])) - using namespace QGBA; SettingsView::SettingsView(ConfigController* controller, InputController* inputController, ShortcutController* shortcutController, LogController* logController, QWidget* parent) @@ -70,52 +59,6 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC m_ui.cgbSgbModel->setCurrentIndex(m_ui.gbModel->findData(GB_MODEL_CGB)); #endif - // Hardware extensions - m_enabledExtensionsCounter = 0; - - // Add "All" checkbox - QCheckBox* cb = new QCheckBox(this); - m_ui.individualEnableTable->setCellWidget(0, 0, cb); - connect(cb, &QCheckBox::stateChanged, this, [this](int state) { - QCheckBox* cb; - for (unsigned i = 0; i < EXTENSIONS_ROWS; i++) { - cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(1 + i, 0); - if (state != cb->checkState()) { - cb->setCheckState((Qt::CheckState) state); - } - } - }); - - // Add the rest of checkboxes - m_ui.individualEnableTable->setRowCount(1 + EXTENSIONS_ROWS); - for (unsigned int i = 0; i < EXTENSIONS_ROWS; i++) { - cb = new QCheckBox(this); - m_ui.individualEnableTable->setVerticalHeaderItem(i + 1, new QTableWidgetItem(tr(hwExtensionsDescriptions[i].description))); - m_ui.individualEnableTable->setCellWidget(i + 1, 0, cb); - connect(cb, &QCheckBox::stateChanged, this, [this, i](int state) { - bool enabled = state == Qt::Checked; - QCheckBox* cbAll = (QCheckBox*) m_ui.individualEnableTable->cellWidget(0, 0); - - // Update "All" checkbox - m_enabledExtensionsCounter += enabled ? 1 : -1; - switch (cbAll->checkState()) { - case Qt::Checked: - if (m_enabledExtensionsCounter < EXTENSIONS_ROWS) { - cbAll->blockSignals(true); - cbAll->setCheckState(Qt::Unchecked); - cbAll->blockSignals(false); - } - break; - default: - if (m_enabledExtensionsCounter == EXTENSIONS_ROWS) { - cbAll->blockSignals(true); - cbAll->setCheckState(Qt::Checked); - cbAll->blockSignals(false); - } - } - }); - } - reloadConfig(); connect(m_ui.volume, static_cast(&QSlider::valueChanged), [this](int v) { @@ -393,6 +336,55 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC shortcutView->setController(shortcutController); shortcutView->setInputController(inputController); addPage(tr("Shortcuts"), shortcutView, Page::SHORTCUTS); + + // Hardware extensions + memset(m_hwExtensionsCheckboxes, 0, sizeof(m_hwExtensionsCheckboxes)); + m_hwExtensionsCheckboxes[0] = m_ui.hwEx0CheckBox; + m_enabledExtensionsCounter = 0; + for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { + if (m_hwExtensionsCheckboxes[i] && Qt::Checked == m_hwExtensionsCheckboxes[i]->checkState()) { + m_enabledExtensionsCounter++; + } + } + if (m_enabledExtensionsCounter == HWEX_EXTENSIONS_COUNT) { + m_ui.hwExAllCheckBox->setCheckState(Qt::Checked); + } + + // connect "All" checkbox + connect(m_ui.hwExAllCheckBox, &QCheckBox::stateChanged, this, [this](int state) { + for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { + m_enabledExtensionsCounter = 0; + if (m_hwExtensionsCheckboxes[i] && state != m_hwExtensionsCheckboxes[i]->checkState()) { + m_hwExtensionsCheckboxes[i]->blockSignals(true); + m_hwExtensionsCheckboxes[i]->setCheckState((Qt::CheckState) state); + m_hwExtensionsCheckboxes[i]->blockSignals(false); + m_enabledExtensionsCounter++; + } + } + }); + for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { + if (m_hwExtensionsCheckboxes[i]) { + connect(m_hwExtensionsCheckboxes[i], &QCheckBox::stateChanged, this, [this](int state) { + // update "All" checkbox + m_enabledExtensionsCounter += (state == Qt::Checked) ? 1 : -1; + switch (m_ui.hwExAllCheckBox->checkState()) { + case Qt::Checked: + if (m_enabledExtensionsCounter < HWEX_EXTENSIONS_COUNT) { + m_ui.hwExAllCheckBox->blockSignals(true); + m_ui.hwExAllCheckBox->setCheckState(Qt::Unchecked); + m_ui.hwExAllCheckBox->blockSignals(false); + } + break; + default: + if (m_enabledExtensionsCounter == HWEX_EXTENSIONS_COUNT) { + m_ui.hwExAllCheckBox->blockSignals(true); + m_ui.hwExAllCheckBox->setCheckState(Qt::Checked); + m_ui.hwExAllCheckBox->blockSignals(false); + } + } + }); + } + } } SettingsView::~SettingsView() { @@ -658,20 +650,8 @@ void SettingsView::updateConfig() { saveSetting("gb.colors", gbColors); #endif - saveSetting("hwExtensions", m_ui.globalEnableCheckBox); - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t i = 0; i < EXTENSIONS_ROWS; i++) { - QCheckBox* cb = (QCheckBox*) m_ui.individualEnableTable->cellWidget(i + 1, 0); - unsigned int extensionId = hwExtensionsDescriptions[i].id; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[extensionId & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(extensionId >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(extensionId >> 8) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(extensionId >> 12) & 0xF]; - - saveSetting(hwExtensionsFlagsKey, cb); - } - + saveSetting("hwExtensions", m_ui.hwExtensionsCheckBox); + saveSetting("hwExtensionsFlags_0000", m_ui.hwEx0CheckBox); m_controller->write(); @@ -852,18 +832,8 @@ void SettingsView::reloadConfig() { m_ui.multiplayerAudioAll->setChecked(true); } - loadSetting("hwExtensions", m_ui.globalEnableCheckBox, false); - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t i = 0; i < EXTENSIONS_ROWS; i++) { - unsigned int extensionId = hwExtensionsDescriptions[i].id; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[extensionId & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(extensionId >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(extensionId >> 8) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(extensionId >> 12) & 0xF]; - - loadSetting(hwExtensionsFlagsKey, (QCheckBox*) m_ui.individualEnableTable->cellWidget(i + 1, 0), false); - } + loadSetting("hwExtensions", m_ui.hwExtensionsCheckBox, false); + loadSetting("hwExtensionsFlags_0000", m_ui.hwEx0CheckBox, false); } void SettingsView::addPage(const QString& name, QWidget* view, Page index) { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 31f7f8be144..034cd7c0206 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -80,6 +80,7 @@ private slots: LogConfigModel m_logModel; unsigned int m_enabledExtensionsCounter; + QCheckBox* m_hwExtensionsCheckboxes[HWEX_EXTENSIONS_COUNT]; #ifdef M_CORE_GB uint32_t m_gbColors[12]{}; diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index af74de83c8c..88287b2f1b7 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -80,11 +80,6 @@ Game Boy - - - Hardware extensions - - @@ -1154,6 +1149,73 @@ + + + + Hardware extensions + + + + QFormLayout::ExpandingFieldsGrow + + + + + General: + + + + + + + Enable + + + + + + + Qt::Horizontal + + + + + + + Individual: + + + + + + + All + + + + + + + More RAM + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -2018,48 +2080,6 @@ - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Enable hardware extensions - - - - - - - - - - All - - - - - Enable - - - - - - From b65493b94321879cd74239c972c986547a52f7b3 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Wed, 21 Jul 2021 14:35:33 -0300 Subject: [PATCH 15/21] De-hardcoded some memory regions. And changed an enum to comply with coding styles. --- src/gba/hardware-extensions.c | 55 ++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c index dba365398de..2b223395092 100644 --- a/src/gba/hardware-extensions.c +++ b/src/gba/hardware-extensions.c @@ -246,38 +246,41 @@ bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareE // Extension handlers static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { - uint32_t addressPrefix = (address >> 24) & 0xF; uint8_t* pointer = NULL; *isRom = false; - if (addressPrefix == 2) { - if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { - pointer = (uint8_t*) gba->memory.wram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); - } - } else if (addressPrefix == 3) { - if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { - pointer = (uint8_t*) gba->memory.iwram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); - } - } else if (addressPrefix & 8) { - if ((address & 0x1FFFFFF) < gba->memory.romSize) { - *isRom = true; - pointer = (uint8_t*) gba->memory.rom; - pointer += address & 0x1FFFFFF; - *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); - } + switch (address >> 24) { + case REGION_WORKING_RAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { + pointer = (uint8_t*) gba->memory.wram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); + } + break; + case REGION_WORKING_IRAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { + pointer = (uint8_t*) gba->memory.iwram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); + } + break; + case REGION_CART0: + case REGION_CART0_EX: + if ((address & 0x1FFFFFF) < gba->memory.romSize) { + *isRom = true; + pointer = (uint8_t*) gba->memory.rom; + pointer += address & 0x1FFFFFF; + *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); + } } return pointer; } enum HwExMoreRAMCommands { - HwExtMoreRAMMemoryWrite = 0, - HwExtMoreRAMMemoryRead = 1, - HwExtMoreRAMMemorySwap = 2 + HWEX_MORE_RAM_CMD_WRITE = 0, + HWEX_MORE_RAM_CMD_READ = 1, + HWEX_MORE_RAM_CMD_SWAP = 2 }; static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { @@ -300,16 +303,16 @@ static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { } switch (command) { - case HwExtMoreRAMMemoryWrite: + case HWEX_MORE_RAM_CMD_WRITE: memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); break; - case HwExtMoreRAMMemoryRead: + case HWEX_MORE_RAM_CMD_READ: if (isRom) { return HWEX_RET_ERR_WRITE_TO_ROM; } memcpy(data, ((uint8_t*)gba->hwExtensions.moreRam) + index, dataSize); break; - case HwExtMoreRAMMemorySwap: + case HWEX_MORE_RAM_CMD_SWAP: if (isRom) { return HWEX_RET_ERR_WRITE_TO_ROM; } From ece8c5aeaff8f427f41b9a350e9335353ba42420 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Thu, 22 Jul 2021 02:21:10 -0300 Subject: [PATCH 16/21] Multiple name changes, moved files and other small changes related to gba extensions. --- include/mgba/core/config.h | 2 +- include/mgba/feature/commandline.h | 2 +- .../extensions-ids.h} | 8 +- include/mgba/internal/gba/extra/extensions.h | 56 +++ include/mgba/internal/gba/gba.h | 5 +- .../mgba/internal/gba/hardware-extensions.h | 56 --- src/gba/CMakeLists.txt | 2 +- src/gba/core.c | 22 +- src/gba/extra/extensions.c | 323 +++++++++++++++++ src/gba/gba.c | 2 +- src/gba/hardware-extensions.c | 339 ------------------ src/gba/io.c | 12 +- 12 files changed, 404 insertions(+), 425 deletions(-) rename include/mgba/internal/gba/{hardware-extensions-ids.h => extra/extensions-ids.h} (73%) create mode 100644 include/mgba/internal/gba/extra/extensions.h delete mode 100644 include/mgba/internal/gba/hardware-extensions.h create mode 100644 src/gba/extra/extensions.c delete mode 100644 src/gba/hardware-extensions.c diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 56b11c5c3b8..0c578efbea6 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -12,7 +12,7 @@ CXX_GUARD_START #include -#include +#include struct mCoreConfig { struct Configuration configTable; diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index 1814778fb1e..bb7d1d1755f 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -14,7 +14,7 @@ CXX_GUARD_START #include -#include +#include enum HwExSettingsOverrides { HWEX_DONT_OVERRIDE = 0, diff --git a/include/mgba/internal/gba/hardware-extensions-ids.h b/include/mgba/internal/gba/extra/extensions-ids.h similarity index 73% rename from include/mgba/internal/gba/hardware-extensions-ids.h rename to include/mgba/internal/gba/extra/extensions-ids.h index eb77425d543..e0c2a24abc8 100644 --- a/include/mgba/internal/gba/hardware-extensions-ids.h +++ b/include/mgba/internal/gba/extra/extensions-ids.h @@ -1,12 +1,12 @@ -/* Copyright (c) 2021 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/. */ -#ifndef HARDWARE_EXTENSIONS_IDS_H -#define HARDWARE_EXTENSIONS_IDS_H +#ifndef GBA_EXTENSIONS_IDS_H +#define GBA_EXTENSIONS_IDS_H -enum HARDWARE_EXTENSIONS_IDS { +enum GBA_EXTENSIONS_IDS { HWEX_ID_MORE_RAM = 0, HWEX_EXTENSIONS_COUNT }; diff --git a/include/mgba/internal/gba/extra/extensions.h b/include/mgba/internal/gba/extra/extensions.h new file mode 100644 index 00000000000..046254c1a19 --- /dev/null +++ b/include/mgba/internal/gba/extra/extensions.h @@ -0,0 +1,56 @@ +/* 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_EXTENSIONS_H +#define GBA_EXTENSIONS_H + +#include + +CXX_GUARD_START + +#include +#include + +#include +#include + +#define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT +#define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB + +struct GBAExtensions { + bool enabled; + bool userEnabled; + uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; + + // IO: + uint16_t io[REG_HWEX_END - REG_HWEX_ENABLE]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; +}; + +struct GBAExtensionsState { + uint32_t enabled; // boolean + uint32_t version; + + // IO: + uint32_t memory[128]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; +}; + +struct GBA; +void GBAExtensionsInit(struct GBAExtensions* hw); +uint16_t GBAExtensionsIORead(struct GBA* gba, uint32_t address); +uint32_t GBAExtensionsIORead32(struct GBA* gba, uint32_t address); +void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); +void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value); +bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state); +bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* state, size_t size); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index a915b8e284f..2ae5fedc4ef 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -18,7 +18,7 @@ CXX_GUARD_START #include #include #include -#include +#include #define GBA_ARM7TDMI_FREQUENCY 0x1000000U @@ -71,6 +71,7 @@ struct GBA { struct GBAVideo video; struct GBAAudio audio; struct GBASIO sio; + struct GBAExtensions extensions; struct mCoreSync* sync; struct mTiming timing; @@ -124,8 +125,6 @@ struct GBA { bool debug; char debugString[0x100]; GBADebugFlags debugFlags; - - struct GBAHardwareExtensions hwExtensions; }; struct GBACartridge { diff --git a/include/mgba/internal/gba/hardware-extensions.h b/include/mgba/internal/gba/hardware-extensions.h deleted file mode 100644 index d9fd8180d49..00000000000 --- a/include/mgba/internal/gba/hardware-extensions.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Copyright (c) 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 HARDWARE_EXTENSIONS_H -#define HARDWARE_EXTENSIONS_H - -#include - -#include -#include - -#include -#include - - -#define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT -#define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB - -struct GBAHardwareExtensions { - bool enabled; - bool userEnabled; - uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; - - // IO: - uint32_t memory[(REG_HWEX_END - REG_HWEX_ENABLE) / 2]; - - // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; -}; - - -struct GBAHardwareExtensionsState { - uint32_t enabled; // boolean - uint32_t version; - - // IO: - uint32_t memory[128]; - - // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; -}; - - -struct GBA; -void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hw); -uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address); -uint32_t GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address); -void GBAHardwareExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); -void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value); -void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t value); -bool GBAHardwareExtensionsSerialize(struct GBA* gba, struct GBAHardwareExtensionsState* state); -bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareExtensionsState* state, size_t size); - -#endif diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index f88f76d1e00..9331244766a 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -13,8 +13,8 @@ set(SOURCE_FILES cheats/parv3.c core.c dma.c + extra/extensions.c gba.c - hardware-extensions.c hle-bios.c input.c io.c diff --git a/src/gba/core.c b/src/gba/core.c index d2cd9b3ab1d..776c7a397b6 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -272,8 +272,8 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con } gba->video.frameskip = core->opts.frameskip; - gba->hwExtensions.userEnabled = core->opts.hwExtensions; - memcpy(gba->hwExtensions.userEnabledFlags, core->opts.hwExtensionsFlags, sizeof(gba->hwExtensions.userEnabledFlags)); + gba->extensions.userEnabled = core->opts.hwExtensions; + memcpy(gba->extensions.userEnabledFlags, core->opts.hwExtensionsFlags, sizeof(gba->extensions.userEnabledFlags)); #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 struct GBACore* gbacore = (struct GBACore*) core; @@ -367,7 +367,7 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c if (strcmp("hwExtensions", option) == 0) { if (mCoreConfigGetIntValue(config, "hwExtensions", &fakeBool)) { core->opts.hwExtensions = fakeBool; - gba->hwExtensions.userEnabled = core->opts.hwExtensions; + gba->extensions.userEnabled = core->opts.hwExtensions; } return; } @@ -390,7 +390,7 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c } } } - gba->hwExtensions.userEnabledFlags[index] = core->opts.hwExtensionsFlags[index]; + gba->extensions.userEnabledFlags[index] = core->opts.hwExtensionsFlags[index]; } } @@ -1185,10 +1185,10 @@ static void _GBACoreEndVideoLog(struct mCore* core) { } #endif -static size_t _GBAHardwareExtensionsSerialize(struct mCore* core, void** sram) { - size_t size = sizeof(struct GBAHardwareExtensionsState); +static size_t _GBAExtensionsSerialize(struct mCore* core, void** sram) { + size_t size = sizeof(struct GBAExtensionsState); *sram = malloc(size); - if (!GBAHardwareExtensionsSerialize(core->board, *sram)) { + if (!GBAExtensionsSerialize(core->board, *sram)) { free(*sram); size = 0; *sram = NULL; @@ -1196,8 +1196,8 @@ static size_t _GBAHardwareExtensionsSerialize(struct mCore* core, void** sram) { return size; } -static bool _GBAHardwareExtensionsDeserialize(struct mCore* core, const void* sram, size_t size) { - return GBAHardwareExtensionsDeserialize(core->board, sram, size); +static bool _GBAExtensionsDeserialize(struct mCore* core, const void* sram, size_t size) { + return GBAExtensionsDeserialize(core->board, sram, size); } struct mCore* GBACoreCreate(void) { @@ -1284,8 +1284,8 @@ struct mCore* GBACoreCreate(void) { core->startVideoLog = _GBACoreStartVideoLog; core->endVideoLog = _GBACoreEndVideoLog; #endif - core->hwExtensionsSerialize = _GBAHardwareExtensionsSerialize; - core->hwExtensionsDeserialize = _GBAHardwareExtensionsDeserialize; + core->hwExtensionsSerialize = _GBAExtensionsSerialize; + core->hwExtensionsDeserialize = _GBAExtensionsDeserialize; return core; } diff --git a/src/gba/extra/extensions.c b/src/gba/extra/extensions.c new file mode 100644 index 00000000000..0fab8779db8 --- /dev/null +++ b/src/gba/extra/extensions.c @@ -0,0 +1,323 @@ +/* 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 +#include +#include +#include + + +enum HWEX_RETURN_CODES { + HWEX_RET_OK = 0, + HWEX_RET_WAIT = 1, + + // Errors + HWEX_RET_ERR_UNKNOWN = 0x100, + HWEX_RET_ERR_BAD_ADDRESS = 0x101, + HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, + HWEX_RET_ERR_WRITE_TO_ROM = 0x103, + HWEX_RET_ERR_ABORTED = 0x104, + HWEX_RET_ERR_DISABLED = 0x105, + HWEX_RET_ERR_DISABLED_BY_USER = 0x106 +}; + +#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) + +const uint16_t extensionIdByRegister[] = { + // More RAM + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, +}; + +static uint16_t _getExtensionIdFromAddress(uint32_t address) { + return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; +} + +#undef SIMPLIFY_HWEX_REG_ADDRESS + +// CNT flags +// Writable +#define HWEX_CNT_FLAG_CALL 1 +#define HWEX_CNT_ALL_WRITABLE (HWEX_CNT_FLAG_CALL) +// Read only +#define HWEX_CNT_FLAG_PROCESSING (1 << 15) + +struct GBAExtensionHandlers { + uint16_t (*onCall)(struct GBA* gba); + bool (*onAbort)(void); +}; + +static uint16_t _GBAExtensionMoreRAM(struct GBA* gba); + +static const struct GBAExtensionHandlers extensionHandlers[] = { + [HWEX_ID_MORE_RAM] = { .onCall = _GBAExtensionMoreRAM, .onAbort = NULL } +}; + +void GBAExtensionsInit(struct GBAExtensions* hwExtensions) { + hwExtensions->enabled = false; + + hwExtensions->userEnabled = false; + memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); + + memset(hwExtensions->io, 0, sizeof(hwExtensions->io)); +} + +static uint16_t* _getHwExIOPointer(struct GBA* gba, uint32_t address) { + return gba->extensions.io + ((address - REG_HWEX_ENABLE_FLAGS_0) >> 1); +} + +static uint16_t _GBAExtensionsIORead(struct GBA* gba, uint32_t address) { + switch (address) { + case REG_HWEX_ENABLE: + return 0x1DEA; + case REG_HWEX_VERSION: + return REG_HWEX_VERSION_VALUE; + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + return *_getHwExIOPointer(gba, address) & gba->extensions.userEnabledFlags[index]; + } + + default: + return *_getHwExIOPointer(gba, address); + } +} + +uint16_t GBAExtensionsIORead(struct GBA* gba, uint32_t address) { + if (gba->extensions.enabled && gba->extensions.userEnabled) { + return _GBAExtensionsIORead(gba, address); + } + mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); + return GBALoadBad(gba->cpu); +} + +static uint32_t _GBAExtensionsIORead32(struct GBA* gba, uint32_t address) { + return (_GBAExtensionsIORead(gba, address + 2) << 16) | _GBAExtensionsIORead(gba, address); +}; + +static void _GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { + *_getHwExIOPointer(gba, address) = value; +} + +static bool GBAExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { + uint32_t index = extensionId / 16; + uint32_t bit = extensionId % 16; + return (_GBAExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; +} + +static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { + uint16_t* cnt = _getHwExIOPointer(gba, cntAddress); + uint16_t* returnCode = cnt + 1; + uint16_t currentValue = *cnt; + uint32_t extensionId = _getExtensionIdFromAddress(cntAddress); + + if (!GBAExtensionsIsExtensionEnabled(gba, extensionId)) { + *returnCode = HWEX_RET_ERR_DISABLED; + return; + } + + const struct GBAExtensionHandlers* handlers = extensionHandlers + extensionId; + value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags + + if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed + if (currentValue & HWEX_CNT_FLAG_PROCESSING) { // check if extension is running + if (!(currentValue & HWEX_CNT_FLAG_CALL)) { + // call flag set to 0 + // abort + if (handlers->onAbort) { + handlers->onAbort(); + *cnt = currentValue; + *returnCode = HWEX_RET_ERR_ABORTED; + } + } + } else { + if (value & HWEX_CNT_FLAG_CALL) { // check call the extension + *returnCode = handlers->onCall(gba); + if (*returnCode == HWEX_RET_OK || *returnCode >= HWEX_RET_ERR_UNKNOWN) { // execution finished + *cnt = 0; + } else { // processing + *cnt = currentValue | HWEX_CNT_FLAG_CALL | HWEX_CNT_FLAG_PROCESSING; + } + } + } + } +} + +void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { + switch (address) { + case REG_HWEX_ENABLE: + gba->extensions.enabled = value == 0xC0DE; + break; + // Enable flags + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists + if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { + // delete the flags of the non-existant extensions + value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); + } + _GBAExtensionsIOWrite(gba, address, value); + } + break; + } + // Return codes + case REG_HWEX0_RET_CODE: + mLOG(GBA_IO, GAME_ERROR, "Write to read-only hardware extensions I/O register: %06X", address); + break; + + // CNT + case REG_HWEX0_CNT: + GBAExtensionsHandleCntWrite(gba, address, value); + break; + + // Parameters + case REG_HWEX0_P0_LO: + case REG_HWEX0_P0_HI: + case REG_HWEX0_P1_LO: + case REG_HWEX0_P1_HI: + case REG_HWEX0_P2_LO: + case REG_HWEX0_P2_HI: + case REG_HWEX0_P3_LO: + case REG_HWEX0_P3_HI: + if (!(_GBAExtensionsIORead(gba, REG_HWEX0_CNT) & HWEX_CNT_FLAG_PROCESSING)) { + _GBAExtensionsIOWrite(gba, address, value); + } + break; + default: + mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); + } +} + +void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { + uint32_t address16 = address & 0xFFFFFE; + uint16_t* reg = _getHwExIOPointer(gba, address16); + GBAExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); +} + +bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state) { + state->enabled = gba->extensions.enabled; + state->version = REG_HWEX_VERSION_VALUE; + memcpy(state->memory, gba->extensions.io, sizeof(gba->extensions.io)); + memcpy(state->moreRam, gba->extensions.moreRam, sizeof(gba->extensions.moreRam)); + return true; +} + +bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* state, size_t size) { + if (size < sizeof(*state)) { + return false; + } + gba->extensions.enabled = state->enabled; + memcpy(gba->extensions.io, state->memory, sizeof(gba->extensions.io)); + memcpy(gba->extensions.moreRam, state->moreRam, sizeof(gba->extensions.moreRam)); + + return true; +} + +// Extension handlers +static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { + uint8_t* pointer = NULL; + *isRom = false; + + switch (address >> 24) { + case REGION_WORKING_RAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { + pointer = (uint8_t*) gba->memory.wram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); + } + break; + case REGION_WORKING_IRAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { + pointer = (uint8_t*) gba->memory.iwram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); + } + break; + case REGION_CART0: + case REGION_CART0_EX: + if ((address & 0x1FFFFFF) < gba->memory.romSize) { + *isRom = true; + pointer = (uint8_t*) gba->memory.rom; + pointer += address & 0x1FFFFFF; + *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); + } + } + + return pointer; +} + +enum GBAEX_MORE_RAM_COMMANDS { + GBAEX_MORE_RAM_CMD_WRITE = 0, + GBAEX_MORE_RAM_CMD_READ = 1, + GBAEX_MORE_RAM_CMD_SWAP = 2 +}; + +static uint16_t _GBAExtensionMoreRAM(struct GBA* gba) { + uint32_t command = _GBAExtensionsIORead32(gba, REG_HWEX0_P0_LO); + uint32_t index = _GBAExtensionsIORead32(gba, REG_HWEX0_P1_LO); + uint32_t dataPointer = _GBAExtensionsIORead32(gba, REG_HWEX0_P2_LO); + uint32_t dataSize = _GBAExtensionsIORead32(gba, REG_HWEX0_P3_LO); + void* data; + // Check if the pointer is valid + bool isRom; + uint32_t memoryMaxSize; + data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); + if (data == NULL) { + return HWEX_RET_ERR_BAD_ADDRESS; + } + + // Check if index and size are valid + if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + switch (command) { + case GBAEX_MORE_RAM_CMD_WRITE: + memcpy(((uint8_t*)gba->extensions.moreRam) + index, data, dataSize); + break; + case GBAEX_MORE_RAM_CMD_READ: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + memcpy(data, ((uint8_t*)gba->extensions.moreRam) + index, dataSize); + break; + case GBAEX_MORE_RAM_CMD_SWAP: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + // TODO: make this more efficient + uint8_t* data1 = data; + uint8_t* data2 = (uint8_t*) gba->extensions.moreRam; + data2 += index; + for (uint32_t i = 0; i < dataSize; i++) { + uint8_t aux = data1[i]; + data1[i] = data2[i]; + data2[i] = aux; + } + break; + default: + // invalid command + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + return HWEX_RET_OK; +} diff --git a/src/gba/gba.c b/src/gba/gba.c index a5f1b90cc7f..b59329f4c1d 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -125,7 +125,7 @@ static void GBAInit(void* cpu, struct mCPUComponent* component) { gba->irqEvent.context = gba; gba->irqEvent.priority = 0; - GBAHardwareExtensionsInit(&gba->hwExtensions); + GBAExtensionsInit(&gba->extensions); } void GBAUnloadROM(struct GBA* gba) { diff --git a/src/gba/hardware-extensions.c b/src/gba/hardware-extensions.c deleted file mode 100644 index 2b223395092..00000000000 --- a/src/gba/hardware-extensions.c +++ /dev/null @@ -1,339 +0,0 @@ -/* Copyright (c) 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 -#include -#include -#include - - -enum HWEX_RETURN_CODES { - HWEX_RET_OK = 0, - HWEX_RET_WAIT = 1, - - // Errors - HWEX_RET_ERR_UNKNOWN = 0x100, - HWEX_RET_ERR_BAD_ADDRESS = 0x101, - HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, - HWEX_RET_ERR_WRITE_TO_ROM = 0x103, - HWEX_RET_ERR_ABORTED = 0x104, - HWEX_RET_ERR_DISABLED = 0x105, - HWEX_RET_ERR_DISABLED_BY_USER = 0x106 -}; - -#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) - -const uint16_t extensionIdByRegister[] = { - // More RAM - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, -}; - -static uint16_t GetExtensionIdFromAddress(uint32_t address) { - return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; -} - -#undef SIMPLIFY_HWEX_REG_ADDRESS - -// CNT flags -// Writable -#define HWEX_CNT_FLAG_CALL 1 -#define HWEX_CNT_ALL_WRITABLE (HWEX_CNT_FLAG_CALL) -// Read only -#define HWEX_CNT_FLAG_PROCESSING (1 << 15) - -struct HardwareExtensionHandlers { - uint16_t (*onCall)(struct GBA* gba); - bool (*onAbort)(void); -}; - -static const struct HardwareExtensionHandlers extensionHandlers[]; - -void GBAHardwareExtensionsInit(struct GBAHardwareExtensions* hwExtensions) { - hwExtensions->enabled = false; - - hwExtensions->userEnabled = false; - memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); - - memset(hwExtensions->memory, 0, sizeof(hwExtensions->memory)); -} - -static uint32_t GetHwExMemoryIndex16FromAddress(uint32_t address) { - return (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; -} - -static uint32_t GetHwExMemoryIndex32FromAddress(uint32_t address) { - return (address - REG_HWEX_ENABLE_FLAGS_0) >> 2; -} - -static uint16_t* GetHwExIOPointer(struct GBA* gba, uint32_t address) { - return ((uint16_t*) &gba->hwExtensions.memory) + GetHwExMemoryIndex16FromAddress(address); -} - -static uint16_t _GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { - switch (address) { - case REG_HWEX_ENABLE: - return 0x1DEA; - case REG_HWEX_VERSION: - return REG_HWEX_VERSION_VALUE; - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - return *GetHwExIOPointer(gba, address) & gba->hwExtensions.userEnabledFlags[index]; - } - - default: - return *GetHwExIOPointer(gba, address); - } -} - -uint16_t GBAHardwareExtensionsIORead(struct GBA* gba, uint32_t address) { - if (gba->hwExtensions.enabled && gba->hwExtensions.userEnabled) { - return _GBAHardwareExtensionsIORead(gba, address); - } - mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); - return GBALoadBad(gba->cpu); -} - -static uint32_t _GBAHardwareExtensionsIORead32(struct GBA* gba, uint32_t address) { - return gba->hwExtensions.memory[GetHwExMemoryIndex32FromAddress(address)]; -}; - -static void _GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - *GetHwExIOPointer(gba, address) = value; -} - -static bool GBAHardwareExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { - uint32_t index = extensionId / 16; - uint32_t bit = extensionId % 16; - return (_GBAHardwareExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; -} - -static void GBAHardwareExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { - uint16_t* cnt = GetHwExIOPointer(gba, cntAddress); - uint16_t* returnCode = cnt + 1; - uint16_t currentValue = *cnt; - uint32_t extensionId = GetExtensionIdFromAddress(cntAddress); - - if (!GBAHardwareExtensionsIsExtensionEnabled(gba, extensionId)) { - *returnCode = HWEX_RET_ERR_DISABLED; - return; - } - - const struct HardwareExtensionHandlers* handlers = extensionHandlers + extensionId; - value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags - - if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed - if (currentValue & HWEX_CNT_FLAG_PROCESSING) { // check if extension is running - if (!(currentValue & HWEX_CNT_FLAG_CALL)) { - // call flag set to 0 - // abort - if (handlers->onAbort) { - handlers->onAbort(); - *cnt = currentValue; - *returnCode = HWEX_RET_ERR_ABORTED; - } - } - } else { - if (value & HWEX_CNT_FLAG_CALL) { // check call the extension - *returnCode = handlers->onCall(gba); - if (*returnCode == HWEX_RET_OK || *returnCode >= HWEX_RET_ERR_UNKNOWN) { // execution finished - *cnt = 0; - } else { // processing - *cnt = currentValue | HWEX_CNT_FLAG_CALL | HWEX_CNT_FLAG_PROCESSING; - } - } - } - } -} - -void GBAHardwareExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - switch (address) { - case REG_HWEX_ENABLE: - gba->hwExtensions.enabled = value == 0xC0DE; - break; - // Enable flags - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists - if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { - // delete the flags of the non-existant extensions - value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); - } - _GBAHardwareExtensionsIOWrite(gba, address, value); - } - break; - } - // Return codes - case REG_HWEX0_RET_CODE: - mLOG(GBA_IO, GAME_ERROR, "Write to read-only hardware extensions I/O register: %06X", address); - break; - - // CNT - case REG_HWEX0_CNT: - GBAHardwareExtensionsHandleCntWrite(gba, address, value); - break; - - // Parameters - case REG_HWEX0_P0_LO: - case REG_HWEX0_P0_HI: - case REG_HWEX0_P1_LO: - case REG_HWEX0_P1_HI: - case REG_HWEX0_P2_LO: - case REG_HWEX0_P2_HI: - case REG_HWEX0_P3_LO: - case REG_HWEX0_P3_HI: - if (!(_GBAHardwareExtensionsIORead(gba, REG_HWEX0_CNT) & HWEX_CNT_FLAG_PROCESSING)) { - _GBAHardwareExtensionsIOWrite(gba, address, value); - } - break; - default: - mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); - } -} - -void GBAHardwareExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { - uint32_t address16 = address & 0xFFFFFE; - uint16_t* reg = GetHwExIOPointer(gba, address16); - GBAHardwareExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); -} - -void GBAHardwareExtensionsIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { - GBAHardwareExtensionsIOWrite(gba, address, value & 0xFFFF); - GBAHardwareExtensionsIOWrite(gba, address + 2, value >> 16); -} - -bool GBAHardwareExtensionsSerialize(struct GBA* gba, struct GBAHardwareExtensionsState* state) { - state->enabled = gba->hwExtensions.enabled; - state->version = REG_HWEX_VERSION_VALUE; - memcpy(state->memory, gba->hwExtensions.memory, sizeof(gba->hwExtensions.memory)); - memcpy(state->moreRam, gba->hwExtensions.moreRam, sizeof(gba->hwExtensions.moreRam)); - return true; -} - -bool GBAHardwareExtensionsDeserialize(struct GBA* gba, const struct GBAHardwareExtensionsState* state, size_t size) { - if (size < sizeof(*state)) { - return false; - } - gba->hwExtensions.enabled = state->enabled; - memcpy(gba->hwExtensions.memory, state->memory, sizeof(gba->hwExtensions.memory)); - memcpy(gba->hwExtensions.moreRam, state->moreRam, sizeof(gba->hwExtensions.moreRam)); - - return true; -} - - - -// Extension handlers - -static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { - uint8_t* pointer = NULL; - *isRom = false; - - switch (address >> 24) { - case REGION_WORKING_RAM: - if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { - pointer = (uint8_t*) gba->memory.wram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); - } - break; - case REGION_WORKING_IRAM: - if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { - pointer = (uint8_t*) gba->memory.iwram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); - } - break; - case REGION_CART0: - case REGION_CART0_EX: - if ((address & 0x1FFFFFF) < gba->memory.romSize) { - *isRom = true; - pointer = (uint8_t*) gba->memory.rom; - pointer += address & 0x1FFFFFF; - *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); - } - } - - return pointer; -} - -enum HwExMoreRAMCommands { - HWEX_MORE_RAM_CMD_WRITE = 0, - HWEX_MORE_RAM_CMD_READ = 1, - HWEX_MORE_RAM_CMD_SWAP = 2 -}; - -static uint16_t MGBAHwExtMoreRAM(struct GBA* gba) { - uint32_t command = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P0_LO); - uint32_t index = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P1_LO); - uint32_t dataPointer = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P2_LO); - uint32_t dataSize = _GBAHardwareExtensionsIORead32(gba, REG_HWEX0_P3_LO); - void* data; - // Check if the pointer is valid - bool isRom; - uint32_t memoryMaxSize; - data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); - if (data == NULL) { - return HWEX_RET_ERR_BAD_ADDRESS; - } - - // Check if index and size are valid - if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - switch (command) { - case HWEX_MORE_RAM_CMD_WRITE: - memcpy(((uint8_t*)gba->hwExtensions.moreRam) + index, data, dataSize); - break; - case HWEX_MORE_RAM_CMD_READ: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - memcpy(data, ((uint8_t*)gba->hwExtensions.moreRam) + index, dataSize); - break; - case HWEX_MORE_RAM_CMD_SWAP: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - // TODO: make this more efficient - uint8_t* data1 = data; - uint8_t* data2 = (uint8_t*) gba->hwExtensions.moreRam; - data2 += index; - for (uint32_t i = 0; i < dataSize; i++) { - uint8_t aux = data1[i]; - data1[i] = data2[i]; - data2[i] = aux; - } - break; - default: - // invalid command - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - return HWEX_RET_OK; -} - -static const struct HardwareExtensionHandlers extensionHandlers[] = { - [HWEX_ID_MORE_RAM] = { .onCall = MGBAHwExtMoreRAM, .onAbort = NULL } -}; diff --git a/src/gba/io.c b/src/gba/io.c index 71fd2332eba..a669eb261a8 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include mLOG_DEFINE_CATEGORY(GBA_IO, "GBA I/O", "gba.io"); @@ -587,7 +587,7 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { return; } if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { - GBAHardwareExtensionsIOWrite(gba, address, value); + GBAExtensionsIOWrite(gba, address, value); return; } mLOG(GBA_IO, STUB, "Stub I/O register write: %03X", address); @@ -619,7 +619,7 @@ void GBAIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { return; } if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { - GBAHardwareExtensionsIOWrite8(gba, address, value); + GBAExtensionsIOWrite8(gba, address, value); return; } if (address > SIZE_IO) { @@ -680,10 +680,6 @@ void GBAIOWrite32(struct GBA* gba, uint32_t address, uint32_t value) { STORE_32LE(value, address - REG_DEBUG_STRING, gba->debugString); return; } - if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { - GBAHardwareExtensionsIOWrite32(gba, address, value); - return; - } GBAIOWrite(gba, address, value & 0xFFFF); GBAIOWrite(gba, address | 2, value >> 16); return; @@ -951,7 +947,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) { // Fall through default: if (address >= REG_HWEX_ENABLE && address < REG_HWEX_END) { - return GBAHardwareExtensionsIORead(gba, address); + return GBAExtensionsIORead(gba, address); } mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); return GBALoadBad(gba->cpu); From 97dac47dfaa83f783bce88903ff331fde0345990 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Thu, 22 Jul 2021 02:26:11 -0300 Subject: [PATCH 17/21] Convert spaces indentation to tabs in gab extensions files. --- .../mgba/internal/gba/extra/extensions-ids.h | 4 +- include/mgba/internal/gba/extra/extensions.h | 34 +- src/gba/extra/extensions.c | 456 +++++++++--------- 3 files changed, 247 insertions(+), 247 deletions(-) diff --git a/include/mgba/internal/gba/extra/extensions-ids.h b/include/mgba/internal/gba/extra/extensions-ids.h index e0c2a24abc8..f876ed3585c 100644 --- a/include/mgba/internal/gba/extra/extensions-ids.h +++ b/include/mgba/internal/gba/extra/extensions-ids.h @@ -7,8 +7,8 @@ #define GBA_EXTENSIONS_IDS_H enum GBA_EXTENSIONS_IDS { - HWEX_ID_MORE_RAM = 0, - HWEX_EXTENSIONS_COUNT + HWEX_ID_MORE_RAM = 0, + HWEX_EXTENSIONS_COUNT }; #define HWEX_FLAGS_REGISTERS_COUNT ((HWEX_EXTENSIONS_COUNT / 16) + (HWEX_EXTENSIONS_COUNT % 16 ? 1 : 0)) diff --git a/include/mgba/internal/gba/extra/extensions.h b/include/mgba/internal/gba/extra/extensions.h index 046254c1a19..73a3549232e 100644 --- a/include/mgba/internal/gba/extra/extensions.h +++ b/include/mgba/internal/gba/extra/extensions.h @@ -20,26 +20,26 @@ CXX_GUARD_START #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB struct GBAExtensions { - bool enabled; - bool userEnabled; - uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; - - // IO: - uint16_t io[REG_HWEX_END - REG_HWEX_ENABLE]; - - // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + bool enabled; + bool userEnabled; + uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; + + // IO: + uint16_t io[REG_HWEX_END - REG_HWEX_ENABLE]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; struct GBAExtensionsState { - uint32_t enabled; // boolean - uint32_t version; - - // IO: - uint32_t memory[128]; - - // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + uint32_t enabled; // boolean + uint32_t version; + + // IO: + uint32_t memory[128]; + + // Other data + uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; struct GBA; diff --git a/src/gba/extra/extensions.c b/src/gba/extra/extensions.c index 0fab8779db8..2afbd83f23a 100644 --- a/src/gba/extra/extensions.c +++ b/src/gba/extra/extensions.c @@ -10,25 +10,25 @@ enum HWEX_RETURN_CODES { - HWEX_RET_OK = 0, - HWEX_RET_WAIT = 1, - - // Errors - HWEX_RET_ERR_UNKNOWN = 0x100, - HWEX_RET_ERR_BAD_ADDRESS = 0x101, - HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, - HWEX_RET_ERR_WRITE_TO_ROM = 0x103, - HWEX_RET_ERR_ABORTED = 0x104, - HWEX_RET_ERR_DISABLED = 0x105, - HWEX_RET_ERR_DISABLED_BY_USER = 0x106 + HWEX_RET_OK = 0, + HWEX_RET_WAIT = 1, + + // Errors + HWEX_RET_ERR_UNKNOWN = 0x100, + HWEX_RET_ERR_BAD_ADDRESS = 0x101, + HWEX_RET_ERR_INVALID_PARAMETERS = 0x102, + HWEX_RET_ERR_WRITE_TO_ROM = 0x103, + HWEX_RET_ERR_ABORTED = 0x104, + HWEX_RET_ERR_DISABLED = 0x105, + HWEX_RET_ERR_DISABLED_BY_USER = 0x106 }; #define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) const uint16_t extensionIdByRegister[] = { - // More RAM - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, + // More RAM + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, @@ -40,7 +40,7 @@ const uint16_t extensionIdByRegister[] = { }; static uint16_t _getExtensionIdFromAddress(uint32_t address) { - return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; + return extensionIdByRegister[SIMPLIFY_HWEX_REG_ADDRESS(address)]; } #undef SIMPLIFY_HWEX_REG_ADDRESS @@ -53,271 +53,271 @@ static uint16_t _getExtensionIdFromAddress(uint32_t address) { #define HWEX_CNT_FLAG_PROCESSING (1 << 15) struct GBAExtensionHandlers { - uint16_t (*onCall)(struct GBA* gba); - bool (*onAbort)(void); + uint16_t (*onCall)(struct GBA* gba); + bool (*onAbort)(void); }; static uint16_t _GBAExtensionMoreRAM(struct GBA* gba); static const struct GBAExtensionHandlers extensionHandlers[] = { - [HWEX_ID_MORE_RAM] = { .onCall = _GBAExtensionMoreRAM, .onAbort = NULL } + [HWEX_ID_MORE_RAM] = { .onCall = _GBAExtensionMoreRAM, .onAbort = NULL } }; void GBAExtensionsInit(struct GBAExtensions* hwExtensions) { hwExtensions->enabled = false; - hwExtensions->userEnabled = false; - memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); + hwExtensions->userEnabled = false; + memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); - memset(hwExtensions->io, 0, sizeof(hwExtensions->io)); + memset(hwExtensions->io, 0, sizeof(hwExtensions->io)); } static uint16_t* _getHwExIOPointer(struct GBA* gba, uint32_t address) { - return gba->extensions.io + ((address - REG_HWEX_ENABLE_FLAGS_0) >> 1); + return gba->extensions.io + ((address - REG_HWEX_ENABLE_FLAGS_0) >> 1); } static uint16_t _GBAExtensionsIORead(struct GBA* gba, uint32_t address) { - switch (address) { - case REG_HWEX_ENABLE: - return 0x1DEA; - case REG_HWEX_VERSION: - return REG_HWEX_VERSION_VALUE; - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - return *_getHwExIOPointer(gba, address) & gba->extensions.userEnabledFlags[index]; - } - - default: - return *_getHwExIOPointer(gba, address); - } + switch (address) { + case REG_HWEX_ENABLE: + return 0x1DEA; + case REG_HWEX_VERSION: + return REG_HWEX_VERSION_VALUE; + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + return *_getHwExIOPointer(gba, address) & gba->extensions.userEnabledFlags[index]; + } + + default: + return *_getHwExIOPointer(gba, address); + } } uint16_t GBAExtensionsIORead(struct GBA* gba, uint32_t address) { - if (gba->extensions.enabled && gba->extensions.userEnabled) { - return _GBAExtensionsIORead(gba, address); - } - mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); - return GBALoadBad(gba->cpu); + if (gba->extensions.enabled && gba->extensions.userEnabled) { + return _GBAExtensionsIORead(gba, address); + } + mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); + return GBALoadBad(gba->cpu); } static uint32_t _GBAExtensionsIORead32(struct GBA* gba, uint32_t address) { - return (_GBAExtensionsIORead(gba, address + 2) << 16) | _GBAExtensionsIORead(gba, address); + return (_GBAExtensionsIORead(gba, address + 2) << 16) | _GBAExtensionsIORead(gba, address); }; static void _GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - *_getHwExIOPointer(gba, address) = value; + *_getHwExIOPointer(gba, address) = value; } static bool GBAExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { - uint32_t index = extensionId / 16; - uint32_t bit = extensionId % 16; - return (_GBAExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; + uint32_t index = extensionId / 16; + uint32_t bit = extensionId % 16; + return (_GBAExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; } static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { - uint16_t* cnt = _getHwExIOPointer(gba, cntAddress); - uint16_t* returnCode = cnt + 1; - uint16_t currentValue = *cnt; - uint32_t extensionId = _getExtensionIdFromAddress(cntAddress); - - if (!GBAExtensionsIsExtensionEnabled(gba, extensionId)) { - *returnCode = HWEX_RET_ERR_DISABLED; - return; - } - - const struct GBAExtensionHandlers* handlers = extensionHandlers + extensionId; - value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags - - if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed - if (currentValue & HWEX_CNT_FLAG_PROCESSING) { // check if extension is running - if (!(currentValue & HWEX_CNT_FLAG_CALL)) { - // call flag set to 0 - // abort - if (handlers->onAbort) { - handlers->onAbort(); - *cnt = currentValue; - *returnCode = HWEX_RET_ERR_ABORTED; - } - } - } else { - if (value & HWEX_CNT_FLAG_CALL) { // check call the extension - *returnCode = handlers->onCall(gba); - if (*returnCode == HWEX_RET_OK || *returnCode >= HWEX_RET_ERR_UNKNOWN) { // execution finished - *cnt = 0; - } else { // processing - *cnt = currentValue | HWEX_CNT_FLAG_CALL | HWEX_CNT_FLAG_PROCESSING; - } - } - } - } + uint16_t* cnt = _getHwExIOPointer(gba, cntAddress); + uint16_t* returnCode = cnt + 1; + uint16_t currentValue = *cnt; + uint32_t extensionId = _getExtensionIdFromAddress(cntAddress); + + if (!GBAExtensionsIsExtensionEnabled(gba, extensionId)) { + *returnCode = HWEX_RET_ERR_DISABLED; + return; + } + + const struct GBAExtensionHandlers* handlers = extensionHandlers + extensionId; + value &= HWEX_CNT_ALL_WRITABLE; // delete non-writable flags + + if (value != (currentValue & HWEX_CNT_ALL_WRITABLE)) { // check if value changed + if (currentValue & HWEX_CNT_FLAG_PROCESSING) { // check if extension is running + if (!(currentValue & HWEX_CNT_FLAG_CALL)) { + // call flag set to 0 + // abort + if (handlers->onAbort) { + handlers->onAbort(); + *cnt = currentValue; + *returnCode = HWEX_RET_ERR_ABORTED; + } + } + } else { + if (value & HWEX_CNT_FLAG_CALL) { // check call the extension + *returnCode = handlers->onCall(gba); + if (*returnCode == HWEX_RET_OK || *returnCode >= HWEX_RET_ERR_UNKNOWN) { // execution finished + *cnt = 0; + } else { // processing + *cnt = currentValue | HWEX_CNT_FLAG_CALL | HWEX_CNT_FLAG_PROCESSING; + } + } + } + } } void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { - switch (address) { - case REG_HWEX_ENABLE: - gba->extensions.enabled = value == 0xC0DE; - break; - // Enable flags - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists - if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { - // delete the flags of the non-existant extensions - value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); - } - _GBAExtensionsIOWrite(gba, address, value); - } - break; - } - // Return codes - case REG_HWEX0_RET_CODE: - mLOG(GBA_IO, GAME_ERROR, "Write to read-only hardware extensions I/O register: %06X", address); - break; - - // CNT - case REG_HWEX0_CNT: - GBAExtensionsHandleCntWrite(gba, address, value); - break; - - // Parameters - case REG_HWEX0_P0_LO: - case REG_HWEX0_P0_HI: - case REG_HWEX0_P1_LO: - case REG_HWEX0_P1_HI: - case REG_HWEX0_P2_LO: - case REG_HWEX0_P2_HI: - case REG_HWEX0_P3_LO: - case REG_HWEX0_P3_HI: - if (!(_GBAExtensionsIORead(gba, REG_HWEX0_CNT) & HWEX_CNT_FLAG_PROCESSING)) { - _GBAExtensionsIOWrite(gba, address, value); - } - break; - default: - mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); - } + switch (address) { + case REG_HWEX_ENABLE: + gba->extensions.enabled = value == 0xC0DE; + break; + // Enable flags + case REG_HWEX_ENABLE_FLAGS_0: + case REG_HWEX_ENABLE_FLAGS_1: + case REG_HWEX_ENABLE_FLAGS_2: + case REG_HWEX_ENABLE_FLAGS_3: + case REG_HWEX_ENABLE_FLAGS_4: + case REG_HWEX_ENABLE_FLAGS_5: { + uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; + if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists + if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { + // delete the flags of the non-existant extensions + value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); + } + _GBAExtensionsIOWrite(gba, address, value); + } + break; + } + // Return codes + case REG_HWEX0_RET_CODE: + mLOG(GBA_IO, GAME_ERROR, "Write to read-only hardware extensions I/O register: %06X", address); + break; + + // CNT + case REG_HWEX0_CNT: + GBAExtensionsHandleCntWrite(gba, address, value); + break; + + // Parameters + case REG_HWEX0_P0_LO: + case REG_HWEX0_P0_HI: + case REG_HWEX0_P1_LO: + case REG_HWEX0_P1_HI: + case REG_HWEX0_P2_LO: + case REG_HWEX0_P2_HI: + case REG_HWEX0_P3_LO: + case REG_HWEX0_P3_HI: + if (!(_GBAExtensionsIORead(gba, REG_HWEX0_CNT) & HWEX_CNT_FLAG_PROCESSING)) { + _GBAExtensionsIOWrite(gba, address, value); + } + break; + default: + mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); + } } void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { - uint32_t address16 = address & 0xFFFFFE; - uint16_t* reg = _getHwExIOPointer(gba, address16); - GBAExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); + uint32_t address16 = address & 0xFFFFFE; + uint16_t* reg = _getHwExIOPointer(gba, address16); + GBAExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); } bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state) { - state->enabled = gba->extensions.enabled; - state->version = REG_HWEX_VERSION_VALUE; - memcpy(state->memory, gba->extensions.io, sizeof(gba->extensions.io)); - memcpy(state->moreRam, gba->extensions.moreRam, sizeof(gba->extensions.moreRam)); - return true; + state->enabled = gba->extensions.enabled; + state->version = REG_HWEX_VERSION_VALUE; + memcpy(state->memory, gba->extensions.io, sizeof(gba->extensions.io)); + memcpy(state->moreRam, gba->extensions.moreRam, sizeof(gba->extensions.moreRam)); + return true; } bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* state, size_t size) { - if (size < sizeof(*state)) { - return false; - } - gba->extensions.enabled = state->enabled; - memcpy(gba->extensions.io, state->memory, sizeof(gba->extensions.io)); - memcpy(gba->extensions.moreRam, state->moreRam, sizeof(gba->extensions.moreRam)); - - return true; + if (size < sizeof(*state)) { + return false; + } + gba->extensions.enabled = state->enabled; + memcpy(gba->extensions.io, state->memory, sizeof(gba->extensions.io)); + memcpy(gba->extensions.moreRam, state->moreRam, sizeof(gba->extensions.moreRam)); + + return true; } // Extension handlers static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* memoryMaxSize, bool* isRom) { - uint8_t* pointer = NULL; - *isRom = false; - - switch (address >> 24) { - case REGION_WORKING_RAM: - if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { - pointer = (uint8_t*) gba->memory.wram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); - } - break; - case REGION_WORKING_IRAM: - if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { - pointer = (uint8_t*) gba->memory.iwram; - pointer += address & 0xFFFFFF; - *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); - } - break; - case REGION_CART0: - case REGION_CART0_EX: - if ((address & 0x1FFFFFF) < gba->memory.romSize) { - *isRom = true; - pointer = (uint8_t*) gba->memory.rom; - pointer += address & 0x1FFFFFF; - *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); - } - } - - return pointer; + uint8_t* pointer = NULL; + *isRom = false; + + switch (address >> 24) { + case REGION_WORKING_RAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_RAM) { + pointer = (uint8_t*) gba->memory.wram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_RAM - (address & 0xFFFFFF); + } + break; + case REGION_WORKING_IRAM: + if ((address & 0xFFFFFF) < SIZE_WORKING_IRAM) { + pointer = (uint8_t*) gba->memory.iwram; + pointer += address & 0xFFFFFF; + *memoryMaxSize = SIZE_WORKING_IRAM - (address & 0xFFFFFF); + } + break; + case REGION_CART0: + case REGION_CART0_EX: + if ((address & 0x1FFFFFF) < gba->memory.romSize) { + *isRom = true; + pointer = (uint8_t*) gba->memory.rom; + pointer += address & 0x1FFFFFF; + *memoryMaxSize = gba->memory.romSize - (address & 0x1FFFFFF); + } + } + + return pointer; } enum GBAEX_MORE_RAM_COMMANDS { - GBAEX_MORE_RAM_CMD_WRITE = 0, - GBAEX_MORE_RAM_CMD_READ = 1, - GBAEX_MORE_RAM_CMD_SWAP = 2 + GBAEX_MORE_RAM_CMD_WRITE = 0, + GBAEX_MORE_RAM_CMD_READ = 1, + GBAEX_MORE_RAM_CMD_SWAP = 2 }; static uint16_t _GBAExtensionMoreRAM(struct GBA* gba) { - uint32_t command = _GBAExtensionsIORead32(gba, REG_HWEX0_P0_LO); - uint32_t index = _GBAExtensionsIORead32(gba, REG_HWEX0_P1_LO); - uint32_t dataPointer = _GBAExtensionsIORead32(gba, REG_HWEX0_P2_LO); - uint32_t dataSize = _GBAExtensionsIORead32(gba, REG_HWEX0_P3_LO); - void* data; - // Check if the pointer is valid - bool isRom; - uint32_t memoryMaxSize; - data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); - if (data == NULL) { - return HWEX_RET_ERR_BAD_ADDRESS; - } - - // Check if index and size are valid - if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - switch (command) { - case GBAEX_MORE_RAM_CMD_WRITE: - memcpy(((uint8_t*)gba->extensions.moreRam) + index, data, dataSize); - break; - case GBAEX_MORE_RAM_CMD_READ: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - memcpy(data, ((uint8_t*)gba->extensions.moreRam) + index, dataSize); - break; - case GBAEX_MORE_RAM_CMD_SWAP: - if (isRom) { - return HWEX_RET_ERR_WRITE_TO_ROM; - } - // TODO: make this more efficient - uint8_t* data1 = data; - uint8_t* data2 = (uint8_t*) gba->extensions.moreRam; - data2 += index; - for (uint32_t i = 0; i < dataSize; i++) { - uint8_t aux = data1[i]; - data1[i] = data2[i]; - data2[i] = aux; - } - break; - default: - // invalid command - return HWEX_RET_ERR_INVALID_PARAMETERS; - } - - return HWEX_RET_OK; + uint32_t command = _GBAExtensionsIORead32(gba, REG_HWEX0_P0_LO); + uint32_t index = _GBAExtensionsIORead32(gba, REG_HWEX0_P1_LO); + uint32_t dataPointer = _GBAExtensionsIORead32(gba, REG_HWEX0_P2_LO); + uint32_t dataSize = _GBAExtensionsIORead32(gba, REG_HWEX0_P3_LO); + void* data; + // Check if the pointer is valid + bool isRom; + uint32_t memoryMaxSize; + data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); + if (data == NULL) { + return HWEX_RET_ERR_BAD_ADDRESS; + } + + // Check if index and size are valid + if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + switch (command) { + case GBAEX_MORE_RAM_CMD_WRITE: + memcpy(((uint8_t*)gba->extensions.moreRam) + index, data, dataSize); + break; + case GBAEX_MORE_RAM_CMD_READ: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + memcpy(data, ((uint8_t*)gba->extensions.moreRam) + index, dataSize); + break; + case GBAEX_MORE_RAM_CMD_SWAP: + if (isRom) { + return HWEX_RET_ERR_WRITE_TO_ROM; + } + // TODO: make this more efficient + uint8_t* data1 = data; + uint8_t* data2 = (uint8_t*) gba->extensions.moreRam; + data2 += index; + for (uint32_t i = 0; i < dataSize; i++) { + uint8_t aux = data1[i]; + data1[i] = data2[i]; + data2[i] = aux; + } + break; + default: + // invalid command + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + + return HWEX_RET_OK; } From 274183e167abfeb76b8b88fc84414dcac27af81e Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Thu, 22 Jul 2021 22:49:02 -0300 Subject: [PATCH 18/21] Removed gba extensions command line args. Also removed their optiond from core options. Renamed said options in the gba core. Renamed "More RAM" to "Extra RAM". Removed flags registers and added one register to specifically enable the extra RAM extension. --- include/mgba/core/config.h | 4 - include/mgba/feature/commandline.h | 11 -- .../mgba/internal/gba/extra/extensions-ids.h | 6 +- include/mgba/internal/gba/extra/extensions.h | 17 +-- include/mgba/internal/gba/io.h | 34 +++-- src/core/config.c | 38 ------ src/feature/commandline.c | 50 -------- src/gba/core.c | 53 +++----- src/gba/extra/extensions.c | 118 ++++++++---------- src/platform/qt/SettingsView.cpp | 59 ++++----- src/platform/qt/SettingsView.h | 3 +- src/platform/qt/SettingsView.ui | 10 +- 12 files changed, 136 insertions(+), 267 deletions(-) diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 0c578efbea6..3676accafdf 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -60,10 +60,6 @@ struct mCoreOptions { bool videoSync; bool audioSync; - - // Extensions - bool hwExtensions; - uint16_t hwExtensionsFlags[HWEX_FLAGS_REGISTERS_COUNT]; }; void mCoreConfigInit(struct mCoreConfig*, const char* port); diff --git a/include/mgba/feature/commandline.h b/include/mgba/feature/commandline.h index bb7d1d1755f..c543652e983 100644 --- a/include/mgba/feature/commandline.h +++ b/include/mgba/feature/commandline.h @@ -14,14 +14,6 @@ CXX_GUARD_START #include -#include - -enum HwExSettingsOverrides { - HWEX_DONT_OVERRIDE = 0, - HWEX_ENABLE = 1, - HWEX_DISABLE = 2, -}; - struct mArguments { char* fname; char* patch; @@ -37,9 +29,6 @@ struct mArguments { bool debugAtStart; bool showHelp; bool showVersion; - - char hwExtensions; - char hwExtensionsFlags[HWEX_EXTENSIONS_COUNT]; }; struct mCoreConfig; diff --git a/include/mgba/internal/gba/extra/extensions-ids.h b/include/mgba/internal/gba/extra/extensions-ids.h index f876ed3585c..0a6fc2d701f 100644 --- a/include/mgba/internal/gba/extra/extensions-ids.h +++ b/include/mgba/internal/gba/extra/extensions-ids.h @@ -7,10 +7,8 @@ #define GBA_EXTENSIONS_IDS_H enum GBA_EXTENSIONS_IDS { - HWEX_ID_MORE_RAM = 0, - HWEX_EXTENSIONS_COUNT + GBAEX_ID_EXTRA_RAM = 0, + GBAEX_EXTENSIONS_COUNT }; -#define HWEX_FLAGS_REGISTERS_COUNT ((HWEX_EXTENSIONS_COUNT / 16) + (HWEX_EXTENSIONS_COUNT % 16 ? 1 : 0)) - #endif diff --git a/include/mgba/internal/gba/extra/extensions.h b/include/mgba/internal/gba/extra/extensions.h index 73a3549232e..118f223146c 100644 --- a/include/mgba/internal/gba/extra/extensions.h +++ b/include/mgba/internal/gba/extra/extensions.h @@ -16,30 +16,31 @@ CXX_GUARD_START #include #include -#define REG_HWEX_VERSION_VALUE HWEX_EXTENSIONS_COUNT +#define REG_HWEX_VERSION_VALUE GBAEX_EXTENSIONS_COUNT #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB struct GBAExtensions { - bool enabled; - bool userEnabled; - uint16_t userEnabledFlags[HWEX_FLAGS_REGISTERS_COUNT]; + bool globalEnabled; + bool extensionsEnabled[GBAEX_EXTENSIONS_COUNT]; + bool userGlobalEnabled; + bool userExtensionsEnabled[GBAEX_EXTENSIONS_COUNT]; // IO: - uint16_t io[REG_HWEX_END - REG_HWEX_ENABLE]; + uint16_t io[(REG_HWEX_END - REG_HWEX0_ENABLE) / 2]; // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + uint32_t extraRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; struct GBAExtensionsState { - uint32_t enabled; // boolean + uint32_t globalEnabled; // boolean uint32_t version; // IO: uint32_t memory[128]; // Other data - uint32_t moreRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + uint32_t extraRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; }; struct GBA; diff --git a/include/mgba/internal/gba/io.h b/include/mgba/internal/gba/io.h index 777d1cac697..dce60108143 100644 --- a/include/mgba/internal/gba/io.h +++ b/include/mgba/internal/gba/io.h @@ -161,26 +161,22 @@ enum GBAIORegisters { // Extensions REG_HWEX_ENABLE = 0x400A00, REG_HWEX_VERSION = 0x400A02, - REG_HWEX_ENABLE_FLAGS_0 = 0x400A04, - REG_HWEX_ENABLE_FLAGS_1 = 0x400A06, - REG_HWEX_ENABLE_FLAGS_2 = 0x400A08, - REG_HWEX_ENABLE_FLAGS_3 = 0x400A0A, - REG_HWEX_ENABLE_FLAGS_4 = 0x400A0C, - REG_HWEX_ENABLE_FLAGS_5 = 0x400A0E, - // More RAM - REG_HWEX0_CNT = 0x400A10, - REG_HWEX0_RET_CODE = 0x400A12, - REG_HWEX0_P0_LO = 0x400A14, // command - REG_HWEX0_P0_HI = 0x400A16, - REG_HWEX0_P1_LO = 0x400A18, // index - REG_HWEX0_P1_HI = 0x400A1A, - REG_HWEX0_P2_LO = 0x400A1C, // data pointer - REG_HWEX0_P2_HI = 0x400A1E, - REG_HWEX0_P3_LO = 0x400A20, // size - REG_HWEX0_P3_HI = 0x400A22, - - REG_HWEX_END = 0x400A24, + // Extra RAM + REG_HWEX0_ENABLE = 0x400A04, + REG_HWEX0_CNT = 0x400A06, + REG_HWEX0_RET_CODE = 0x400A08, + REG_HWEX0_UNUSED = 0x400A0A, + REG_HWEX0_P0_LO = 0x400A0C, // command + REG_HWEX0_P0_HI = 0x400A0E, + REG_HWEX0_P1_LO = 0x400A10, // index + REG_HWEX0_P1_HI = 0x400A12, + REG_HWEX0_P2_LO = 0x400A14, // data pointer + REG_HWEX0_P2_HI = 0x400A16, + REG_HWEX0_P3_LO = 0x400A18, // size + REG_HWEX0_P3_HI = 0x400A1A, + + REG_HWEX_END = 0x400A1C, }; diff --git a/src/core/config.c b/src/core/config.c index 44c03d4ba60..9f54aca265c 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -440,29 +440,6 @@ void mCoreConfigMap(const struct mCoreConfig* config, struct mCoreOptions* opts) _lookupCharValue(config, "screenshotPath", &opts->screenshotPath); _lookupCharValue(config, "patchPath", &opts->patchPath); _lookupCharValue(config, "cheatsPath", &opts->cheatsPath); - - _lookupIntValue(config, "hwExtensions", &fakeBool); - opts->hwExtensions = fakeBool; - - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t index = 0; index <= (HWEX_EXTENSIONS_COUNT >> 4); index++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; - - for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { - uint16_t bitFlag = (1 << offset); - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; - if (_lookupIntValue(config, hwExtensionsFlagsKey, &fakeBool)) { - if (fakeBool) { - opts->hwExtensionsFlags[index] |= bitFlag; - } else { - opts->hwExtensionsFlags[index] &= 0xFFFF ^ bitFlag; - } - } - } - } } void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptions* opts) { @@ -488,21 +465,6 @@ void mCoreConfigLoadDefaults(struct mCoreConfig* config, const struct mCoreOptio ConfigurationSetIntValue(&config->defaultsTable, 0, "lockIntegerScaling", opts->lockIntegerScaling); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); ConfigurationSetIntValue(&config->defaultsTable, 0, "suspendScreensaver", opts->suspendScreensaver); - - ConfigurationSetIntValue(&config->defaultsTable, 0, "hwExtensions", opts->hwExtensions); - - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t index = 0; index <= HWEX_EXTENSIONS_COUNT; index++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; - - for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; - ConfigurationSetIntValue(&config->defaultsTable, 0, hwExtensionsFlagsKey, (opts->hwExtensionsFlags[index] & (1 << offset)) != 0); - } - } } static void _configEnum(const char* key, const char* value, void* user) { diff --git a/src/feature/commandline.c b/src/feature/commandline.c index cd8729884ae..0e3a7182cbe 100644 --- a/src/feature/commandline.c +++ b/src/feature/commandline.c @@ -27,9 +27,6 @@ " -6 6x viewport\n" \ " -f Start full-screen" -#define HWEX_ARGS_OFFSET 0x1002 -#define HWEX_ARGS_NO_OFFSET (HWEX_ARGS_OFFSET + HWEX_EXTENSIONS_COUNT) - static const struct option _options[] = { { "bios", required_argument, 0, 'b' }, { "cheats", required_argument, 0, 'c' }, @@ -45,13 +42,6 @@ static const struct option _options[] = { { "savestate", required_argument, 0, 't' }, { "patch", required_argument, 0, 'p' }, { "version", no_argument, 0, '\0' }, - // Extensions - { "hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 4 }, - { "no-hw-extensions", no_argument, 0, HWEX_ARGS_OFFSET - 3 }, - { "hwex-all", no_argument, 0, HWEX_ARGS_OFFSET - 2 }, - { "hwex-none", no_argument, 0, HWEX_ARGS_OFFSET - 1 }, - { "hwex-more-ram", no_argument, 0, HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM }, - { "no-hwex-more-ram", no_argument, 0, HWEX_ARGS_NO_OFFSET + HWEX_ID_MORE_RAM }, { 0, 0, 0, 0 } }; @@ -145,32 +135,6 @@ bool parseArguments(struct mArguments* args, int argc, char* const* argv, struct case 't': args->savestate = strdup(optarg); break; - - // Extensions - case HWEX_ARGS_OFFSET - 4: - // enable extensions - args->hwExtensions = HWEX_ENABLE; - break; - case HWEX_ARGS_OFFSET - 3: - // enable extensions - args->hwExtensions = HWEX_DISABLE; - break; - case HWEX_ARGS_OFFSET - 2: - // enable all extensions - memset(args->hwExtensionsFlags, HWEX_ENABLE, sizeof(args->hwExtensionsFlags)); - break; - case HWEX_ARGS_OFFSET - 1: - // disable all extensions - memset(args->hwExtensionsFlags, HWEX_DISABLE, sizeof(args->hwExtensionsFlags)); - break; - case HWEX_ARGS_OFFSET + HWEX_ID_MORE_RAM: - // enable 1 extension - args->hwExtensionsFlags[ch - HWEX_ARGS_OFFSET] = HWEX_ENABLE; - break; - case HWEX_ARGS_NO_OFFSET + HWEX_ID_MORE_RAM: - // disable 1 extension - args->hwExtensionsFlags[ch - HWEX_ARGS_OFFSET] = HWEX_ENABLE; - break; default: if (subparser) { if (!subparser->parse(subparser, ch, optarg)) { @@ -202,20 +166,6 @@ void applyArguments(const struct mArguments* args, struct mSubParser* subparser, if (args->bios) { mCoreConfigSetOverrideValue(config, "bios", args->bios); } - if (args->hwExtensions) { - mCoreConfigSetOverrideIntValue(config, "hwExtensions", args->hwExtensions == HWEX_ENABLE); - } - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t i = 0; i < (sizeof(args->hwExtensionsFlags) / sizeof(args->hwExtensionsFlags[0])); i++) { - if (args->hwExtensionsFlags[i]) { - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[i & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[(i >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(i >> 8) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(i >> 12) & 0xF]; - mCoreConfigSetOverrideIntValue(config, hwExtensionsFlagsKey, args->hwExtensionsFlags[i] == HWEX_ENABLE); - } - } HashTableEnumerate(&args->configOverrides, _tableApply, config); if (subparser) { subparser->apply(subparser, config); diff --git a/src/gba/core.c b/src/gba/core.c index 776c7a397b6..5e6c065453b 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -272,9 +272,6 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con } gba->video.frameskip = core->opts.frameskip; - gba->extensions.userEnabled = core->opts.hwExtensions; - memcpy(gba->extensions.userEnabledFlags, core->opts.hwExtensionsFlags, sizeof(gba->extensions.userEnabledFlags)); - #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 struct GBACore* gbacore = (struct GBACore*) core; gbacore->overrides = mCoreConfigGetOverridesConst(config); @@ -310,6 +307,13 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con #endif mCoreConfigCopyValue(&core->config, config, "hwaccelVideo"); mCoreConfigCopyValue(&core->config, config, "videoScale"); + + if (mCoreConfigGetIntValue(config, "gba.extensions", &fakeBool)) { + gba->extensions.userGlobalEnabled = fakeBool; + } + if (mCoreConfigGetIntValue(config, "gba.ext.extraRam", &fakeBool)) { + gba->extensions.userExtensionsEnabled[GBAEX_ID_EXTRA_RAM] = fakeBool; + } } static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, const struct mCoreConfig* config) { @@ -364,36 +368,6 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c return; } - if (strcmp("hwExtensions", option) == 0) { - if (mCoreConfigGetIntValue(config, "hwExtensions", &fakeBool)) { - core->opts.hwExtensions = fakeBool; - gba->extensions.userEnabled = core->opts.hwExtensions; - } - return; - } - - if (strcmp("hwExtensionsFlags", option) == 0) { - const char hexDigits[] = "0123456789ABCDEF"; - char hwExtensionsFlagsKey[] = "hwExtensionsFlags_XXXX"; - for (size_t index = 0; index <= (HWEX_EXTENSIONS_COUNT >> 4); index++) { - for (size_t offset = 0; offset < 0x10 && ((index << 4) + offset) < HWEX_EXTENSIONS_COUNT; offset++) { - uint16_t bitFlag = (1 << offset); - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 2] = hexDigits[offset]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 3] = hexDigits[index & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 4] = hexDigits[(index >> 4) & 0xF]; - hwExtensionsFlagsKey[sizeof(hwExtensionsFlagsKey) - 5] = hexDigits[(index >> 8) & 0xF]; - if (mCoreConfigGetIntValue(config, hwExtensionsFlagsKey, &fakeBool)) { - if (fakeBool) { - core->opts.hwExtensionsFlags[index] |= bitFlag; - } else { - core->opts.hwExtensionsFlags[index] &= 0xFFFF ^ bitFlag; - } - } - } - gba->extensions.userEnabledFlags[index] = core->opts.hwExtensionsFlags[index]; - } - } - struct GBACore* gbacore = (struct GBACore*) core; #if defined(BUILD_GLES2) || defined(BUILD_GLES3) if (strcmp("videoScale", option) == 0) { @@ -432,6 +406,19 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c GBAVideoAssociateRenderer(&gba->video, renderer); } } + + if (strcmp("gba.extensions", option) == 0) { + if (mCoreConfigGetIntValue(config, "gba.extensions", &fakeBool)) { + gba->extensions.userGlobalEnabled = fakeBool; + } + return; + } + if (strcmp("gba.ext.extraRam", option) == 0) { + if (mCoreConfigGetIntValue(config, "gba.ext.extraRam", &fakeBool)) { + gba->extensions.userExtensionsEnabled[GBAEX_ID_EXTRA_RAM] = fakeBool; + } + return; + } } static void _GBACoreDesiredVideoDimensions(const struct mCore* core, unsigned* width, unsigned* height) { diff --git a/src/gba/extra/extensions.c b/src/gba/extra/extensions.c index 2afbd83f23a..81f4a9bc920 100644 --- a/src/gba/extra/extensions.c +++ b/src/gba/extra/extensions.c @@ -8,6 +8,8 @@ #include #include +#define ENABLE_CODE 0xC0DE +#define ENABLED_VALUE 0x1DEA enum HWEX_RETURN_CODES { HWEX_RET_OK = 0, @@ -23,20 +25,22 @@ enum HWEX_RETURN_CODES { HWEX_RET_ERR_DISABLED_BY_USER = 0x106 }; -#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_CNT) >> 1) +#define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_ENABLE) >> 1) const uint16_t extensionIdByRegister[] = { - // More RAM - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = HWEX_ID_MORE_RAM, - [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = HWEX_ID_MORE_RAM, + // Extra RAM + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_ENABLE)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_CNT)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_RET_CODE)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_UNUSED)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_LO)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P0_HI)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_LO)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P1_HI)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_LO)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P2_HI)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_LO)] = GBAEX_ID_EXTRA_RAM, + [SIMPLIFY_HWEX_REG_ADDRESS(REG_HWEX0_P3_HI)] = GBAEX_ID_EXTRA_RAM, }; static uint16_t _getExtensionIdFromAddress(uint32_t address) { @@ -57,40 +61,36 @@ struct GBAExtensionHandlers { bool (*onAbort)(void); }; -static uint16_t _GBAExtensionMoreRAM(struct GBA* gba); +static uint16_t _GBAExtensionExtraRAM(struct GBA* gba); static const struct GBAExtensionHandlers extensionHandlers[] = { - [HWEX_ID_MORE_RAM] = { .onCall = _GBAExtensionMoreRAM, .onAbort = NULL } + [GBAEX_ID_EXTRA_RAM] = { .onCall = _GBAExtensionExtraRAM, .onAbort = NULL } }; void GBAExtensionsInit(struct GBAExtensions* hwExtensions) { - hwExtensions->enabled = false; + hwExtensions->globalEnabled = false; + memset(hwExtensions->extensionsEnabled, 0, sizeof(hwExtensions->extensionsEnabled)); - hwExtensions->userEnabled = false; - memset(hwExtensions->userEnabledFlags, 0, sizeof(hwExtensions->userEnabledFlags)); + hwExtensions->userGlobalEnabled = false; + memset(hwExtensions->userExtensionsEnabled, 0, sizeof(hwExtensions->userExtensionsEnabled)); memset(hwExtensions->io, 0, sizeof(hwExtensions->io)); } static uint16_t* _getHwExIOPointer(struct GBA* gba, uint32_t address) { - return gba->extensions.io + ((address - REG_HWEX_ENABLE_FLAGS_0) >> 1); + return gba->extensions.io + (address - REG_HWEX0_ENABLE) / 2; +} + +static bool GBAExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { + return gba->extensions.extensionsEnabled[extensionId] && gba->extensions.userExtensionsEnabled[extensionId]; } static uint16_t _GBAExtensionsIORead(struct GBA* gba, uint32_t address) { switch (address) { case REG_HWEX_ENABLE: - return 0x1DEA; + return ENABLED_VALUE; case REG_HWEX_VERSION: return REG_HWEX_VERSION_VALUE; - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - return *_getHwExIOPointer(gba, address) & gba->extensions.userEnabledFlags[index]; - } default: return *_getHwExIOPointer(gba, address); @@ -98,7 +98,7 @@ static uint16_t _GBAExtensionsIORead(struct GBA* gba, uint32_t address) { } uint16_t GBAExtensionsIORead(struct GBA* gba, uint32_t address) { - if (gba->extensions.enabled && gba->extensions.userEnabled) { + if (gba->extensions.userGlobalEnabled && gba->extensions.globalEnabled) { return _GBAExtensionsIORead(gba, address); } mLOG(GBA_IO, GAME_ERROR, "Read from unused I/O register: %03X", address); @@ -113,12 +113,6 @@ static void _GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t va *_getHwExIOPointer(gba, address) = value; } -static bool GBAExtensionsIsExtensionEnabled(struct GBA* gba, uint32_t extensionId) { - uint32_t index = extensionId / 16; - uint32_t bit = extensionId % 16; - return (_GBAExtensionsIORead(gba, REG_HWEX_ENABLE_FLAGS_0 + index * 2) & (1 << bit)) != 0; -} - static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, uint32_t value) { uint16_t* cnt = _getHwExIOPointer(gba, cntAddress); uint16_t* returnCode = cnt + 1; @@ -160,23 +154,14 @@ static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, ui void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { switch (address) { case REG_HWEX_ENABLE: - gba->extensions.enabled = value == 0xC0DE; + gba->extensions.globalEnabled = value == ENABLE_CODE; break; // Enable flags - case REG_HWEX_ENABLE_FLAGS_0: - case REG_HWEX_ENABLE_FLAGS_1: - case REG_HWEX_ENABLE_FLAGS_2: - case REG_HWEX_ENABLE_FLAGS_3: - case REG_HWEX_ENABLE_FLAGS_4: - case REG_HWEX_ENABLE_FLAGS_5: { - uint32_t index = (address - REG_HWEX_ENABLE_FLAGS_0) >> 1; - if (index <= (HWEX_EXTENSIONS_COUNT >> 4)) { // check if the extension exists - if (index == (HWEX_EXTENSIONS_COUNT >> 4)) { - // delete the flags of the non-existant extensions - value = value & (0xFFFF >> (16 - (HWEX_EXTENSIONS_COUNT & 0xF))); - } - _GBAExtensionsIOWrite(gba, address, value); - } + case REG_HWEX0_ENABLE: { + uint32_t extensionId = _getExtensionIdFromAddress(address); + bool enabled = value == ENABLE_CODE; + gba->extensions.extensionsEnabled[extensionId] = enabled; + _GBAExtensionsIOWrite(gba, address, enabled ? ENABLED_VALUE : 0); break; } // Return codes @@ -205,6 +190,7 @@ void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { default: mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); } + mLOG(GBA_IO, GAME_ERROR, "Write to: %06X", address); } void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { @@ -214,10 +200,10 @@ void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { } bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state) { - state->enabled = gba->extensions.enabled; + state->globalEnabled = gba->extensions.globalEnabled; state->version = REG_HWEX_VERSION_VALUE; memcpy(state->memory, gba->extensions.io, sizeof(gba->extensions.io)); - memcpy(state->moreRam, gba->extensions.moreRam, sizeof(gba->extensions.moreRam)); + memcpy(state->extraRam, gba->extensions.extraRam, sizeof(gba->extensions.extraRam)); return true; } @@ -225,9 +211,11 @@ bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* if (size < sizeof(*state)) { return false; } - gba->extensions.enabled = state->enabled; + gba->extensions.globalEnabled = state->globalEnabled; memcpy(gba->extensions.io, state->memory, sizeof(gba->extensions.io)); - memcpy(gba->extensions.moreRam, state->moreRam, sizeof(gba->extensions.moreRam)); + gba->extensions.extensionsEnabled[GBAEX_ID_EXTRA_RAM] = *_getHwExIOPointer(gba, REG_HWEX0_ENABLE); + + memcpy(gba->extensions.extraRam, state->extraRam, sizeof(gba->extensions.extraRam)); return true; } @@ -265,13 +253,13 @@ static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* me return pointer; } -enum GBAEX_MORE_RAM_COMMANDS { - GBAEX_MORE_RAM_CMD_WRITE = 0, - GBAEX_MORE_RAM_CMD_READ = 1, - GBAEX_MORE_RAM_CMD_SWAP = 2 +enum GBAEX_EXTRA_RAM_COMMANDS { + GBAEX_EXTRA_RAM_CMD_WRITE = 0, + GBAEX_EXTRA_RAM_CMD_READ = 1, + GBAEX_EXTRA_RAM_CMD_SWAP = 2 }; -static uint16_t _GBAExtensionMoreRAM(struct GBA* gba) { +static uint16_t _GBAExtensionExtraRAM(struct GBA* gba) { uint32_t command = _GBAExtensionsIORead32(gba, REG_HWEX0_P0_LO); uint32_t index = _GBAExtensionsIORead32(gba, REG_HWEX0_P1_LO); uint32_t dataPointer = _GBAExtensionsIORead32(gba, REG_HWEX0_P2_LO); @@ -291,22 +279,22 @@ static uint16_t _GBAExtensionMoreRAM(struct GBA* gba) { } switch (command) { - case GBAEX_MORE_RAM_CMD_WRITE: - memcpy(((uint8_t*)gba->extensions.moreRam) + index, data, dataSize); + case GBAEX_EXTRA_RAM_CMD_WRITE: + memcpy(((uint8_t*)gba->extensions.extraRam) + index, data, dataSize); break; - case GBAEX_MORE_RAM_CMD_READ: + case GBAEX_EXTRA_RAM_CMD_READ: if (isRom) { return HWEX_RET_ERR_WRITE_TO_ROM; } - memcpy(data, ((uint8_t*)gba->extensions.moreRam) + index, dataSize); + memcpy(data, ((uint8_t*)gba->extensions.extraRam) + index, dataSize); break; - case GBAEX_MORE_RAM_CMD_SWAP: + case GBAEX_EXTRA_RAM_CMD_SWAP: if (isRom) { return HWEX_RET_ERR_WRITE_TO_ROM; } // TODO: make this more efficient uint8_t* data1 = data; - uint8_t* data2 = (uint8_t*) gba->extensions.moreRam; + uint8_t* data2 = (uint8_t*) gba->extensions.extraRam; data2 += index; for (uint32_t i = 0; i < dataSize; i++) { uint8_t aux = data1[i]; diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index abbfdf37eae..4a15af68b14 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -337,49 +337,50 @@ SettingsView::SettingsView(ConfigController* controller, InputController* inputC shortcutView->setInputController(inputController); addPage(tr("Shortcuts"), shortcutView, Page::SHORTCUTS); - // Hardware extensions - memset(m_hwExtensionsCheckboxes, 0, sizeof(m_hwExtensionsCheckboxes)); - m_hwExtensionsCheckboxes[0] = m_ui.hwEx0CheckBox; + // GBA extensions + m_gbaExtCheckboxesCounter = 0; + m_gbaExtCheckboxes[m_gbaExtCheckboxesCounter++] = m_ui.gbaExtExtraRamCheckBox; + m_enabledExtensionsCounter = 0; - for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { - if (m_hwExtensionsCheckboxes[i] && Qt::Checked == m_hwExtensionsCheckboxes[i]->checkState()) { + for (size_t i = 0; i < m_gbaExtCheckboxesCounter; i++) { + if (m_gbaExtCheckboxes[i] && Qt::Checked == m_gbaExtCheckboxes[i]->checkState()) { m_enabledExtensionsCounter++; } } - if (m_enabledExtensionsCounter == HWEX_EXTENSIONS_COUNT) { - m_ui.hwExAllCheckBox->setCheckState(Qt::Checked); + if (m_enabledExtensionsCounter == m_gbaExtCheckboxesCounter) { + m_ui.gbaExtAllCheckBox->setCheckState(Qt::Checked); } // connect "All" checkbox - connect(m_ui.hwExAllCheckBox, &QCheckBox::stateChanged, this, [this](int state) { - for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { + connect(m_ui.gbaExtAllCheckBox, &QCheckBox::stateChanged, this, [this](int state) { + for (size_t i = 0; i < m_gbaExtCheckboxesCounter; i++) { m_enabledExtensionsCounter = 0; - if (m_hwExtensionsCheckboxes[i] && state != m_hwExtensionsCheckboxes[i]->checkState()) { - m_hwExtensionsCheckboxes[i]->blockSignals(true); - m_hwExtensionsCheckboxes[i]->setCheckState((Qt::CheckState) state); - m_hwExtensionsCheckboxes[i]->blockSignals(false); + if (m_gbaExtCheckboxes[i] && state != m_gbaExtCheckboxes[i]->checkState()) { + m_gbaExtCheckboxes[i]->blockSignals(true); + m_gbaExtCheckboxes[i]->setCheckState((Qt::CheckState) state); + m_gbaExtCheckboxes[i]->blockSignals(false); m_enabledExtensionsCounter++; } } }); - for (size_t i = 0; i < HWEX_EXTENSIONS_COUNT; i++) { - if (m_hwExtensionsCheckboxes[i]) { - connect(m_hwExtensionsCheckboxes[i], &QCheckBox::stateChanged, this, [this](int state) { + for (size_t i = 0; i < m_gbaExtCheckboxesCounter; i++) { + if (m_gbaExtCheckboxes[i]) { + connect(m_gbaExtCheckboxes[i], &QCheckBox::stateChanged, this, [this](int state) { // update "All" checkbox m_enabledExtensionsCounter += (state == Qt::Checked) ? 1 : -1; - switch (m_ui.hwExAllCheckBox->checkState()) { + switch (m_ui.gbaExtAllCheckBox->checkState()) { case Qt::Checked: - if (m_enabledExtensionsCounter < HWEX_EXTENSIONS_COUNT) { - m_ui.hwExAllCheckBox->blockSignals(true); - m_ui.hwExAllCheckBox->setCheckState(Qt::Unchecked); - m_ui.hwExAllCheckBox->blockSignals(false); + if (m_enabledExtensionsCounter < m_gbaExtCheckboxesCounter) { + m_ui.gbaExtAllCheckBox->blockSignals(true); + m_ui.gbaExtAllCheckBox->setCheckState(Qt::Unchecked); + m_ui.gbaExtAllCheckBox->blockSignals(false); } break; default: - if (m_enabledExtensionsCounter == HWEX_EXTENSIONS_COUNT) { - m_ui.hwExAllCheckBox->blockSignals(true); - m_ui.hwExAllCheckBox->setCheckState(Qt::Checked); - m_ui.hwExAllCheckBox->blockSignals(false); + if (m_enabledExtensionsCounter == m_gbaExtCheckboxesCounter) { + m_ui.gbaExtAllCheckBox->blockSignals(true); + m_ui.gbaExtAllCheckBox->setCheckState(Qt::Checked); + m_ui.gbaExtAllCheckBox->blockSignals(false); } } }); @@ -650,8 +651,8 @@ void SettingsView::updateConfig() { saveSetting("gb.colors", gbColors); #endif - saveSetting("hwExtensions", m_ui.hwExtensionsCheckBox); - saveSetting("hwExtensionsFlags_0000", m_ui.hwEx0CheckBox); + saveSetting("gba.extensions", m_ui.gbaExtensionsCheckBox); + saveSetting("gba.ext.extraRam", m_ui.gbaExtExtraRamCheckBox); m_controller->write(); @@ -832,8 +833,8 @@ void SettingsView::reloadConfig() { m_ui.multiplayerAudioAll->setChecked(true); } - loadSetting("hwExtensions", m_ui.hwExtensionsCheckBox, false); - loadSetting("hwExtensionsFlags_0000", m_ui.hwEx0CheckBox, false); + loadSetting("gba.extensions", m_ui.gbaExtensionsCheckBox, false); + loadSetting("gba.ext.extraRam", m_ui.gbaExtExtraRamCheckBox, false); } void SettingsView::addPage(const QString& name, QWidget* view, Page index) { diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 034cd7c0206..25be071a206 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -80,7 +80,8 @@ private slots: LogConfigModel m_logModel; unsigned int m_enabledExtensionsCounter; - QCheckBox* m_hwExtensionsCheckboxes[HWEX_EXTENSIONS_COUNT]; + QCheckBox* m_gbaExtCheckboxes[GBAEX_EXTENSIONS_COUNT]; + unsigned int m_gbaExtCheckboxesCounter; #ifdef M_CORE_GB uint32_t m_gbColors[12]{}; diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index 88287b2f1b7..6562ebed0bd 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -1152,7 +1152,7 @@ - Hardware extensions + GBA extensions @@ -1166,7 +1166,7 @@ - + Enable @@ -1187,16 +1187,16 @@ - + All - + - More RAM + Extra RAM From 11a741373c12448e89ea1e2cf111add7074de6f6 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Fri, 23 Jul 2021 17:06:27 -0300 Subject: [PATCH 19/21] Merged extensions-ids.h with extensions.h. And replaced mCore's extensions serialization functions with more generic extdata serialization functions. --- include/mgba/core/config.h | 2 -- include/mgba/core/core.h | 5 ++-- include/mgba/core/serialize.h | 4 +-- .../mgba/internal/gba/extra/extensions-ids.h | 14 ---------- include/mgba/internal/gba/extra/extensions.h | 6 +++- src/core/serialize.c | 12 ++++---- src/gba/core.c | 28 +++++++++++++------ src/platform/qt/SettingsView.h | 2 ++ 8 files changed, 37 insertions(+), 36 deletions(-) delete mode 100644 include/mgba/internal/gba/extra/extensions-ids.h diff --git a/include/mgba/core/config.h b/include/mgba/core/config.h index 3676accafdf..063b14e02f1 100644 --- a/include/mgba/core/config.h +++ b/include/mgba/core/config.h @@ -12,8 +12,6 @@ CXX_GUARD_START #include -#include - struct mCoreConfig { struct Configuration configTable; struct Configuration defaultsTable; diff --git a/include/mgba/core/core.h b/include/mgba/core/core.h index 506c656638f..51573bdbee8 100644 --- a/include/mgba/core/core.h +++ b/include/mgba/core/core.h @@ -11,6 +11,7 @@ CXX_GUARD_START #include +#include #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 #include #endif @@ -161,8 +162,8 @@ struct mCore { void (*endVideoLog)(struct mCore*); #endif - size_t (*hwExtensionsSerialize)(struct mCore*, void** sram); - bool (*hwExtensionsDeserialize)(struct mCore*, const void* sram, size_t size); + size_t (*extDataSerialize)(struct mCore*, enum mStateExtdataTag tag, void** sram); + bool (*extDataDeserialize)(struct mCore*, enum mStateExtdataTag tag, const void* sram, size_t size); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/include/mgba/core/serialize.h b/include/mgba/core/serialize.h index 7c2d58686cc..2381d6b3878 100644 --- a/include/mgba/core/serialize.h +++ b/include/mgba/core/serialize.h @@ -16,7 +16,7 @@ enum mStateExtdataTag { EXTDATA_SAVEDATA = 2, EXTDATA_CHEATS = 3, EXTDATA_RTC = 4, - EXTDATA_HW_EXTENSIONS = 5, + EXTDATA_GBA_EXTENSIONS = 0x80, EXTDATA_META_TIME = 0x101, EXTDATA_MAX }; @@ -26,7 +26,7 @@ enum mStateExtdataTag { #define SAVESTATE_CHEATS 4 #define SAVESTATE_RTC 8 #define SAVESTATE_METADATA 16 -#define SAVESTATE_HW_EXTENSIONS 32 +#define SAVESTATE_GBA_EXTENSIONS 32 struct mStateExtdataItem { int32_t size; diff --git a/include/mgba/internal/gba/extra/extensions-ids.h b/include/mgba/internal/gba/extra/extensions-ids.h deleted file mode 100644 index 0a6fc2d701f..00000000000 --- a/include/mgba/internal/gba/extra/extensions-ids.h +++ /dev/null @@ -1,14 +0,0 @@ -/* 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_EXTENSIONS_IDS_H -#define GBA_EXTENSIONS_IDS_H - -enum GBA_EXTENSIONS_IDS { - GBAEX_ID_EXTRA_RAM = 0, - GBAEX_EXTENSIONS_COUNT -}; - -#endif diff --git a/include/mgba/internal/gba/extra/extensions.h b/include/mgba/internal/gba/extra/extensions.h index 118f223146c..bff4ecfa15c 100644 --- a/include/mgba/internal/gba/extra/extensions.h +++ b/include/mgba/internal/gba/extra/extensions.h @@ -14,7 +14,11 @@ CXX_GUARD_START #include #include -#include + +enum GBA_EXTENSIONS_IDS { + GBAEX_ID_EXTRA_RAM = 0, + GBAEX_EXTENSIONS_COUNT +}; #define REG_HWEX_VERSION_VALUE GBAEX_EXTENSIONS_COUNT #define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB diff --git a/src/core/serialize.c b/src/core/serialize.c index 3a9fa4b4e7a..1816e5ff6f0 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -421,16 +421,16 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { mStateExtdataPut(&extdata, EXTDATA_RTC, &item); } } - if ((true || flags & SAVESTATE_HW_EXTENSIONS) && core->hwExtensionsSerialize) { + if ((true || flags & SAVESTATE_GBA_EXTENSIONS) && core->extDataSerialize) { void* sram = NULL; - size_t size = core->hwExtensionsSerialize(core, &sram); + size_t size = core->extDataSerialize(core, EXTDATA_GBA_EXTENSIONS, &sram); if (size) { struct mStateExtdataItem item = { .size = size, .data = sram, .clean = free }; - mStateExtdataPut(&extdata, EXTDATA_HW_EXTENSIONS, &item); + mStateExtdataPut(&extdata, EXTDATA_GBA_EXTENSIONS, &item); } } #ifdef USE_PNG @@ -549,9 +549,9 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { core->rtc.d.deserialize(&core->rtc.d, &item); } } - if ((true || flags & SAVESTATE_HW_EXTENSIONS) && core->hwExtensionsDeserialize && mStateExtdataGet(&extdata, EXTDATA_HW_EXTENSIONS, &item)) { - mLOG(SAVESTATE, INFO, "Loading hardware extensions"); - core->hwExtensionsDeserialize(core, item.data, item.size); + if ((true || flags & SAVESTATE_GBA_EXTENSIONS) && core->extDataDeserialize && mStateExtdataGet(&extdata, EXTDATA_GBA_EXTENSIONS, &item)) { + mLOG(SAVESTATE, INFO, "Loading GBA extensions"); + core->extDataDeserialize(core, EXTDATA_GBA_EXTENSIONS, item.data, item.size); } mStateExtdataDeinit(&extdata); return success; diff --git a/src/gba/core.c b/src/gba/core.c index 5e6c065453b..20399329dfd 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -1172,19 +1172,29 @@ static void _GBACoreEndVideoLog(struct mCore* core) { } #endif -static size_t _GBAExtensionsSerialize(struct mCore* core, void** sram) { - size_t size = sizeof(struct GBAExtensionsState); - *sram = malloc(size); - if (!GBAExtensionsSerialize(core->board, *sram)) { - free(*sram); +static size_t _GBAExtDataSerialize(struct mCore* core, enum mStateExtdataTag tag, void** sram) { + size_t size; + if (tag == EXTDATA_GBA_EXTENSIONS) { + size = sizeof(struct GBAExtensionsState); + *sram = malloc(size); + if (!GBAExtensionsSerialize(core->board, *sram)) { + free(*sram); + size = 0; + *sram = NULL; + } + } else { size = 0; *sram = NULL; } + return size; } -static bool _GBAExtensionsDeserialize(struct mCore* core, const void* sram, size_t size) { - return GBAExtensionsDeserialize(core->board, sram, size); +static bool _GBAExtDataDeserialize(struct mCore* core, enum mStateExtdataTag tag, const void* sram, size_t size) { + if (tag == EXTDATA_GBA_EXTENSIONS) { + return GBAExtensionsDeserialize(core->board, sram, size); + } + return false; } struct mCore* GBACoreCreate(void) { @@ -1271,8 +1281,8 @@ struct mCore* GBACoreCreate(void) { core->startVideoLog = _GBACoreStartVideoLog; core->endVideoLog = _GBACoreEndVideoLog; #endif - core->hwExtensionsSerialize = _GBAExtensionsSerialize; - core->hwExtensionsDeserialize = _GBAExtensionsDeserialize; + core->extDataSerialize = _GBAExtDataSerialize; + core->extDataDeserialize = _GBAExtDataDeserialize; return core; } diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 25be071a206..30b84634b74 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -17,6 +17,8 @@ #include #endif +#include + #include "ui_SettingsView.h" namespace QGBA { From d89678a3a50883b513a07a6a61603ff553176a36 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 25 Jul 2021 13:47:07 -0300 Subject: [PATCH 20/21] Fixed error on GB, while attempting to deserialize extensions data. --- src/gb/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gb/core.c b/src/gb/core.c index 51599eb8283..c8c4231d614 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -1141,6 +1141,8 @@ struct mCore* GBCoreCreate(void) { core->startVideoLog = _GBCoreStartVideoLog; core->endVideoLog = _GBCoreEndVideoLog; #endif + core->extDataSerialize = NULL; + core->extDataDeserialize = NULL; return core; } From b2c2e55679b7fd648dbfabeab13f35e801cfb6c0 Mon Sep 17 00:00:00 2001 From: kaisermg5 Date: Sun, 25 Jul 2021 13:56:02 -0300 Subject: [PATCH 21/21] Changes to dynamically alloc GBA extensions IO and extra RAM. Added three more commands to the extra RAM extension: init, resize and destroy. --- include/mgba/internal/gba/extra/extensions.h | 31 ++- src/gba/core.c | 8 +- src/gba/extra/extensions.c | 267 ++++++++++++++++--- src/gba/gba.c | 2 + 4 files changed, 256 insertions(+), 52 deletions(-) diff --git a/include/mgba/internal/gba/extra/extensions.h b/include/mgba/internal/gba/extra/extensions.h index bff4ecfa15c..ddf87113028 100644 --- a/include/mgba/internal/gba/extra/extensions.h +++ b/include/mgba/internal/gba/extra/extensions.h @@ -15,13 +15,15 @@ CXX_GUARD_START #include +#include + enum GBA_EXTENSIONS_IDS { GBAEX_ID_EXTRA_RAM = 0, GBAEX_EXTENSIONS_COUNT }; #define REG_HWEX_VERSION_VALUE GBAEX_EXTENSIONS_COUNT -#define HWEX_MORE_RAM_SIZE 0x100000 // 1 MB +#define GBAEX_IO_SIZE (REG_HWEX_END - REG_HWEX0_ENABLE) struct GBAExtensions { bool globalEnabled; @@ -30,30 +32,37 @@ struct GBAExtensions { bool userExtensionsEnabled[GBAEX_EXTENSIONS_COUNT]; // IO: - uint16_t io[(REG_HWEX_END - REG_HWEX0_ENABLE) / 2]; + uint16_t* io; // Other data - uint32_t extraRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + uint8_t* extraRam; + uint32_t extraRamSize; + uint32_t extraRamRealSize; +}; + +struct GBAExtensionsStateBlockHeader { + uint32_t id; + uint32_t offset; + uint32_t size; }; struct GBAExtensionsState { - uint32_t globalEnabled; // boolean uint32_t version; + uint32_t extensionsBlockCount; - // IO: - uint32_t memory[128]; - - // Other data - uint32_t extraRam[HWEX_MORE_RAM_SIZE / sizeof(uint32_t)]; + struct GBAExtensionsStateBlockHeader ioBlockHeader; + // More blocks can come after the IO one }; struct GBA; -void GBAExtensionsInit(struct GBAExtensions* hw); +void GBAExtensionsInit(struct GBAExtensions* extensions); +void GBAExtensionsReset(struct GBAExtensions* extensions); +void GBAExtensionsDestroy(struct GBAExtensions* extensions); uint16_t GBAExtensionsIORead(struct GBA* gba, uint32_t address); uint32_t GBAExtensionsIORead32(struct GBA* gba, uint32_t address); void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value); void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value); -bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state); +size_t GBAExtensionsSerialize(struct GBA* gba, void** sram); bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* state, size_t size); CXX_GUARD_END diff --git a/src/gba/core.c b/src/gba/core.c index 20399329dfd..d291701fe59 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -1175,13 +1175,7 @@ static void _GBACoreEndVideoLog(struct mCore* core) { static size_t _GBAExtDataSerialize(struct mCore* core, enum mStateExtdataTag tag, void** sram) { size_t size; if (tag == EXTDATA_GBA_EXTENSIONS) { - size = sizeof(struct GBAExtensionsState); - *sram = malloc(size); - if (!GBAExtensionsSerialize(core->board, *sram)) { - free(*sram); - size = 0; - *sram = NULL; - } + return GBAExtensionsSerialize(core->board, sram); } else { size = 0; *sram = NULL; diff --git a/src/gba/extra/extensions.c b/src/gba/extra/extensions.c index 81f4a9bc920..d55f5b6647d 100644 --- a/src/gba/extra/extensions.c +++ b/src/gba/extra/extensions.c @@ -4,7 +4,6 @@ * 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 -#include #include #include @@ -22,9 +21,14 @@ enum HWEX_RETURN_CODES { HWEX_RET_ERR_WRITE_TO_ROM = 0x103, HWEX_RET_ERR_ABORTED = 0x104, HWEX_RET_ERR_DISABLED = 0x105, - HWEX_RET_ERR_DISABLED_BY_USER = 0x106 + HWEX_RET_ERR_DISABLED_BY_USER = 0x106, + HWEX_RET_ERR_NOT_INITIALIZED = 0x107, + HWEX_RET_ERR_ALREADY_INITIALIZED = 0x108, }; + +#define GBAEX_EXTRA_RAM_MAX_SIZE 0x4000000 // 64 MB + #define SIMPLIFY_HWEX_REG_ADDRESS(address) ((address - REG_HWEX0_ENABLE) >> 1) const uint16_t extensionIdByRegister[] = { @@ -58,23 +62,60 @@ static uint16_t _getExtensionIdFromAddress(uint32_t address) { struct GBAExtensionHandlers { uint16_t (*onCall)(struct GBA* gba); - bool (*onAbort)(void); + bool (*onAbort)(struct GBA* gba); + void (*onDisable)(struct GBAExtensions* extensions); }; static uint16_t _GBAExtensionExtraRAM(struct GBA* gba); +static void _GBAExtensionExtraRAMDisable(struct GBAExtensions* extensions); static const struct GBAExtensionHandlers extensionHandlers[] = { - [GBAEX_ID_EXTRA_RAM] = { .onCall = _GBAExtensionExtraRAM, .onAbort = NULL } + [GBAEX_ID_EXTRA_RAM] = { .onCall = _GBAExtensionExtraRAM, .onAbort = NULL, .onDisable = _GBAExtensionExtraRAMDisable } }; -void GBAExtensionsInit(struct GBAExtensions* hwExtensions) { - hwExtensions->globalEnabled = false; - memset(hwExtensions->extensionsEnabled, 0, sizeof(hwExtensions->extensionsEnabled)); +void GBAExtensionsInit(struct GBAExtensions* extensions) { + extensions->globalEnabled = false; + memset(extensions->extensionsEnabled, 0, sizeof(extensions->extensionsEnabled)); + + extensions->userGlobalEnabled = false; + memset(extensions->userExtensionsEnabled, 0, sizeof(extensions->userExtensionsEnabled)); + + extensions->io = NULL; + + extensions->extraRam = NULL; +} + +static void _GBAExtensionsFreeExtensionsData(struct GBAExtensions* extensions) { + for (uint32_t i = 0; i < GBAEX_EXTENSIONS_COUNT; i++) { + if (extensionHandlers[i].onDisable && extensions->extensionsEnabled[i]) { + extensionHandlers[i].onDisable(extensions); + } + } +} + +static void _GBAExtensionsFreeIO(struct GBAExtensions* extensions) { + if (extensions->io) { + free(extensions->io); + extensions->io = NULL; + } +} + +void GBAExtensionsReset(struct GBAExtensions* extensions) { + _GBAExtensionsFreeExtensionsData(extensions); + + extensions->globalEnabled = false; + memset(extensions->extensionsEnabled, 0, sizeof(extensions->extensionsEnabled)); + + _GBAExtensionsFreeIO(extensions); +} + +void GBAExtensionsDestroy(struct GBAExtensions* extensions) { + _GBAExtensionsFreeExtensionsData(extensions); - hwExtensions->userGlobalEnabled = false; - memset(hwExtensions->userExtensionsEnabled, 0, sizeof(hwExtensions->userExtensionsEnabled)); + extensions->globalEnabled = false; + memset(extensions->extensionsEnabled, 0, sizeof(extensions->extensionsEnabled)); - memset(hwExtensions->io, 0, sizeof(hwExtensions->io)); + _GBAExtensionsFreeIO(extensions); } static uint16_t* _getHwExIOPointer(struct GBA* gba, uint32_t address) { @@ -133,7 +174,7 @@ static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, ui // call flag set to 0 // abort if (handlers->onAbort) { - handlers->onAbort(); + handlers->onAbort(gba); *cnt = currentValue; *returnCode = HWEX_RET_ERR_ABORTED; } @@ -152,16 +193,32 @@ static void GBAExtensionsHandleCntWrite(struct GBA* gba, uint32_t cntAddress, ui } void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { + if ((!gba->extensions.userGlobalEnabled || !gba->extensions.globalEnabled) && address != REG_HWEX_ENABLE) { + mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address); + return; + } switch (address) { - case REG_HWEX_ENABLE: + case REG_HWEX_ENABLE: { gba->extensions.globalEnabled = value == ENABLE_CODE; + if (gba->extensions.globalEnabled && !gba->extensions.io) { + gba->extensions.io = malloc(GBAEX_IO_SIZE); + memset(gba->extensions.io, 0, GBAEX_IO_SIZE); + } else if (!gba->extensions.globalEnabled && gba->extensions.io) { + _GBAExtensionsFreeExtensionsData(&gba->extensions); + _GBAExtensionsFreeIO(&gba->extensions); + } break; + } // Enable flags case REG_HWEX0_ENABLE: { uint32_t extensionId = _getExtensionIdFromAddress(address); bool enabled = value == ENABLE_CODE; + bool wasEnabled = gba->extensions.extensionsEnabled[extensionId]; gba->extensions.extensionsEnabled[extensionId] = enabled; _GBAExtensionsIOWrite(gba, address, enabled ? ENABLED_VALUE : 0); + if (wasEnabled && !enabled && extensionHandlers[extensionId].onDisable) { + extensionHandlers[extensionId].onDisable(&gba->extensions); + } break; } // Return codes @@ -190,32 +247,110 @@ void GBAExtensionsIOWrite(struct GBA* gba, uint32_t address, uint16_t value) { default: mLOG(GBA_IO, GAME_ERROR, "Write non hardware extensions I/O register: %06X", address); } - mLOG(GBA_IO, GAME_ERROR, "Write to: %06X", address); } void GBAExtensionsIOWrite8(struct GBA* gba, uint32_t address, uint8_t value) { + if (!gba->extensions.userGlobalEnabled || !gba->extensions.globalEnabled) { + mLOG(GBA_IO, GAME_ERROR, "Write to unused I/O register: %03X", address); + return; + } uint32_t address16 = address & 0xFFFFFE; uint16_t* reg = _getHwExIOPointer(gba, address16); GBAExtensionsIOWrite(gba, address16, address & 1 ? (value << 8) | (*reg & 0xFF) : (value | (*reg & 0xFF00))); } -bool GBAExtensionsSerialize(struct GBA* gba, struct GBAExtensionsState* state) { - state->globalEnabled = gba->extensions.globalEnabled; +#define IO_BLOCK_HEADER_ID 0xFFFFFFFF + +size_t GBAExtensionsSerialize(struct GBA* gba, void** sram) { + if (!gba->extensions.io) { + // Disabled + return 0; + } + + struct GBAExtensionsStateBlockHeader tmpHeaders[GBAEX_EXTENSIONS_COUNT + 1]; + void* blocksDataSrc[GBAEX_EXTENSIONS_COUNT + 1]; + uint32_t blocksCount = 1; + size_t blocksDataSize = 0; + + // Serialize IO + tmpHeaders[0].id = IO_BLOCK_HEADER_ID; + tmpHeaders[0].size = GBAEX_IO_SIZE; + blocksDataSrc[0] = gba->extensions.io; + blocksDataSize += GBAEX_IO_SIZE; + + // Serialize extra RAM + if (gba->extensions.extraRam) { + tmpHeaders[blocksCount].id = GBAEX_ID_EXTRA_RAM; + tmpHeaders[blocksCount].size = gba->extensions.extraRamSize; + blocksDataSrc[blocksCount++] = gba->extensions.extraRam; + blocksDataSize += gba->extensions.extraRamSize; + } + + // Alloc state + uint32_t offset = sizeof(struct GBAExtensionsState) + sizeof(struct GBAExtensionsStateBlockHeader) * (blocksCount - 1); + size_t stateSize = offset + blocksDataSize; + struct GBAExtensionsState* state = malloc(stateSize); + struct GBAExtensionsStateBlockHeader* blockHeaders = &state->ioBlockHeader; + + // Copy data blocks + for (size_t i = 0; i < blocksCount; i++) { + blockHeaders[i].id = tmpHeaders[i].id; + blockHeaders[i].size = tmpHeaders[i].size; + blockHeaders[i].offset = offset; + memcpy(((uint8_t*) state) + offset, blocksDataSrc[i], tmpHeaders[i].size); + offset += tmpHeaders[i].size; + } + state->version = REG_HWEX_VERSION_VALUE; - memcpy(state->memory, gba->extensions.io, sizeof(gba->extensions.io)); - memcpy(state->extraRam, gba->extensions.extraRam, sizeof(gba->extensions.extraRam)); - return true; + state->extensionsBlockCount = blocksCount; + + *sram = state; + return stateSize; } bool GBAExtensionsDeserialize(struct GBA* gba, const struct GBAExtensionsState* state, size_t size) { - if (size < sizeof(*state)) { + _GBAExtensionsFreeExtensionsData(&gba->extensions); + memset(gba->extensions.extensionsEnabled, 0, sizeof(gba->extensions.extensionsEnabled)); + + if (!state || state->extensionsBlockCount == 0 || state->ioBlockHeader.id != IO_BLOCK_HEADER_ID + || state->ioBlockHeader.size == 0) { + // No data, extensions disabled + _GBAExtensionsFreeIO(&gba->extensions); + gba->extensions.globalEnabled = false; return false; } - gba->extensions.globalEnabled = state->globalEnabled; - memcpy(gba->extensions.io, state->memory, sizeof(gba->extensions.io)); - gba->extensions.extensionsEnabled[GBAEX_ID_EXTRA_RAM] = *_getHwExIOPointer(gba, REG_HWEX0_ENABLE); - memcpy(gba->extensions.extraRam, state->extraRam, sizeof(gba->extensions.extraRam)); + // Deserialize IO + if (!gba->extensions.io) { + gba->extensions.io = malloc(GBAEX_IO_SIZE); + memset(gba->extensions.io, 0, GBAEX_IO_SIZE); + gba->extensions.globalEnabled = true; + } + uint8_t* blocksData = (uint8_t*) state; + size_t ioSerializedSize = GBAEX_IO_SIZE; + if (state->ioBlockHeader.size < GBAEX_IO_SIZE) { + memset(((uint8_t*) gba->extensions.io) + state->ioBlockHeader.size, 0, GBAEX_IO_SIZE - state->ioBlockHeader.size); + ioSerializedSize = state->ioBlockHeader.size; + } + memcpy(gba->extensions.io, blocksData + state->ioBlockHeader.offset, ioSerializedSize); + + // Deserialize extensions + const struct GBAExtensionsStateBlockHeader* extBlocksHeaders = (&state->ioBlockHeader) + 1; + for (size_t i = 0; i < (state->extensionsBlockCount - 1); i++) { + if (extBlocksHeaders[i].size > 0 && (extBlocksHeaders[i].offset + extBlocksHeaders[i].size) <= size) { + switch(extBlocksHeaders[i].id) { + case GBAEX_ID_EXTRA_RAM: { + size_t extraRAMSize = extBlocksHeaders[i].size <= GBAEX_EXTRA_RAM_MAX_SIZE ? extBlocksHeaders[i].size : GBAEX_EXTRA_RAM_MAX_SIZE; + gba->extensions.extraRam = malloc(extraRAMSize); + memcpy(gba->extensions.extraRam, blocksData + extBlocksHeaders[i].offset, extraRAMSize); + gba->extensions.extraRamSize = extraRAMSize; + gba->extensions.extraRamRealSize = extraRAMSize; + gba->extensions.extensionsEnabled[GBAEX_ID_EXTRA_RAM] = true; + break; + } + } + } + } return true; } @@ -256,7 +391,10 @@ static void* GBAGetMemoryPointer(struct GBA* gba, uint32_t address, uint32_t* me enum GBAEX_EXTRA_RAM_COMMANDS { GBAEX_EXTRA_RAM_CMD_WRITE = 0, GBAEX_EXTRA_RAM_CMD_READ = 1, - GBAEX_EXTRA_RAM_CMD_SWAP = 2 + GBAEX_EXTRA_RAM_CMD_SWAP = 2, + GBAEX_EXTRA_RAM_CMD_INIT = 3, + GBAEX_EXTRA_RAM_CMD_RESIZE = 4, + GBAEX_EXTRA_RAM_CMD_DESTROY = 5, }; static uint16_t _GBAExtensionExtraRAM(struct GBA* gba) { @@ -265,19 +403,58 @@ static uint16_t _GBAExtensionExtraRAM(struct GBA* gba) { uint32_t dataPointer = _GBAExtensionsIORead32(gba, REG_HWEX0_P2_LO); uint32_t dataSize = _GBAExtensionsIORead32(gba, REG_HWEX0_P3_LO); void* data; - // Check if the pointer is valid bool isRom; uint32_t memoryMaxSize; - data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); - if (data == NULL) { - return HWEX_RET_ERR_BAD_ADDRESS; - } - // Check if index and size are valid - if (index >= HWEX_MORE_RAM_SIZE || (index + dataSize) >= HWEX_MORE_RAM_SIZE || dataSize >= memoryMaxSize) { + // Validate parameters + switch (command) { + case GBAEX_EXTRA_RAM_CMD_WRITE: + case GBAEX_EXTRA_RAM_CMD_READ: + case GBAEX_EXTRA_RAM_CMD_SWAP: + if (!gba->extensions.extraRam) { + return HWEX_RET_ERR_NOT_INITIALIZED; + } + + // Check if the pointer is valid + data = GBAGetMemoryPointer(gba, dataPointer, &memoryMaxSize, &isRom); + if (data == NULL) { + return HWEX_RET_ERR_BAD_ADDRESS; + } + + // Check if index and size are valid + if (index >= gba->extensions.extraRamSize || (index + dataSize) >= gba->extensions.extraRamSize || dataSize >= memoryMaxSize) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + break; + case GBAEX_EXTRA_RAM_CMD_INIT: + if (gba->extensions.extraRam) { + return HWEX_RET_ERR_ALREADY_INITIALIZED; + } + // Check if size is valid + if (index == 0 || index > GBAEX_EXTRA_RAM_MAX_SIZE) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + break; + case GBAEX_EXTRA_RAM_CMD_RESIZE: + if (!gba->extensions.extraRam) { + return HWEX_RET_ERR_NOT_INITIALIZED; + } + // Check if size is valid + if (index == 0 || index > GBAEX_EXTRA_RAM_MAX_SIZE) { + return HWEX_RET_ERR_INVALID_PARAMETERS; + } + break; + case GBAEX_EXTRA_RAM_CMD_DESTROY: + if (!gba->extensions.extraRam) { + return HWEX_RET_ERR_NOT_INITIALIZED; + } + break; + default: + // invalid command return HWEX_RET_ERR_INVALID_PARAMETERS; } + // Execute command switch (command) { case GBAEX_EXTRA_RAM_CMD_WRITE: memcpy(((uint8_t*)gba->extensions.extraRam) + index, data, dataSize); @@ -302,10 +479,32 @@ static uint16_t _GBAExtensionExtraRAM(struct GBA* gba) { data2[i] = aux; } break; - default: - // invalid command - return HWEX_RET_ERR_INVALID_PARAMETERS; + case GBAEX_EXTRA_RAM_CMD_INIT: + gba->extensions.extraRam = malloc(index); + gba->extensions.extraRamSize = index; + gba->extensions.extraRamRealSize = index; + break; + case GBAEX_EXTRA_RAM_CMD_RESIZE: + if (index > gba->extensions.extraRamRealSize) { + uint8_t* newExtraRam = malloc(index); + memcpy(newExtraRam, gba->extensions.extraRam, gba->extensions.extraRamSize); + free(gba->extensions.extraRam); + gba->extensions.extraRam = newExtraRam; + gba->extensions.extraRamRealSize = index; + } + gba->extensions.extraRamSize = index; + break; + case GBAEX_EXTRA_RAM_CMD_DESTROY: + free(gba->extensions.extraRam); + break; } return HWEX_RET_OK; } + +static void _GBAExtensionExtraRAMDisable(struct GBAExtensions* extensions) { + if (extensions->extraRam) { + free(extensions->extraRam); + extensions->extraRam = NULL; + } +} \ No newline at end of file diff --git a/src/gba/gba.c b/src/gba/gba.c index b59329f4c1d..f4e917dc3e2 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -173,6 +173,7 @@ void GBADestroy(struct GBA* gba) { GBAVideoDeinit(&gba->video); GBAAudioDeinit(&gba->audio); GBASIODeinit(&gba->sio); + GBAExtensionsDestroy(&gba->extensions); mTimingDeinit(&gba->timing); mCoreCallbacksListDeinit(&gba->coreCallbacks); } @@ -216,6 +217,7 @@ void GBAReset(struct ARMCore* cpu) { GBAAudioReset(&gba->audio); GBAIOInit(gba); GBATimerInit(gba); + GBAExtensionsReset(&gba->extensions); GBASIOReset(&gba->sio);