diff --git a/CHANGES b/CHANGES index 4c29f1696..5371cb06a 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ Bugfixes: Misc: - Qt: Window size command line options are now supported - Qt: Increase usability of key mapper + - GBA Memory: Use a dynamically sized mask for ROM memory 0.3.0: (2015-08-16) Features: diff --git a/src/gba/gba.c b/src/gba/gba.c index 2ae273760..f10ec8c6c 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -17,6 +17,7 @@ #include "util/crc32.h" #include "util/memory.h" +#include "util/math.h" #include "util/patch.h" #include "util/vfs.h" @@ -156,6 +157,7 @@ void GBAReset(struct ARMCore* cpu) { if (gba->yankedRomSize) { gba->memory.romSize = gba->yankedRomSize; + gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->yankedRomSize = 0; } GBAMemoryReset(gba); @@ -403,6 +405,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char gba->memory.rom = gba->pristineRom; gba->activeFile = fname; gba->memory.romSize = gba->pristineRomSize; + gba->memory.romMask = toPow2(gba->memory.romSize) - 1; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); GBASavedataInit(&gba->memory.savedata, sav); GBAHardwareInit(&gba->memory.hw, &((uint16_t*) gba->memory.rom)[GPIO_REG_DATA >> 1]); @@ -412,6 +415,7 @@ void GBALoadROM(struct GBA* gba, struct VFile* vf, struct VFile* sav, const char void GBAYankROM(struct GBA* gba) { gba->yankedRomSize = gba->memory.romSize; gba->memory.romSize = 0; + gba->memory.romMask = 0; GBARaiseIRQ(gba, IRQ_GAMEPAK); } @@ -452,6 +456,7 @@ void GBAApplyPatch(struct GBA* gba, struct Patch* patch) { return; } gba->memory.romSize = patchedSize; + gba->memory.romMask = SIZE_CART0 - 1; gba->romCrc32 = doCrc32(gba->memory.rom, gba->memory.romSize); } diff --git a/src/gba/memory.c b/src/gba/memory.c index d736141a8..056058af2 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -50,6 +50,7 @@ void GBAMemoryInit(struct GBA* gba) { gba->memory.iwram = 0; gba->memory.rom = 0; gba->memory.romSize = 0; + gba->memory.romMask = 0; gba->memory.hw.p = gba; int i; @@ -269,7 +270,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { case REGION_CART2: case REGION_CART2_EX: cpu->memory.activeRegion = memory->rom; - cpu->memory.activeMask = SIZE_CART0 - 1; + cpu->memory.activeMask = memory->romMask; if ((address & (SIZE_CART0 - 1)) < memory->romSize) { break; } @@ -893,6 +894,7 @@ void GBAPatch32(struct ARMCore* cpu, uint32_t address, int32_t value, int32_t* o _pristineCow(gba); if ((address & (SIZE_CART0 - 4)) >= gba->memory.romSize) { gba->memory.romSize = (address & (SIZE_CART0 - 4)) + 4; + gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } LOAD_32(oldValue, address & (SIZE_CART0 - 4), gba->memory.rom); STORE_32(value, address & (SIZE_CART0 - 4), gba->memory.rom); @@ -960,6 +962,7 @@ void GBAPatch16(struct ARMCore* cpu, uint32_t address, int16_t value, int16_t* o _pristineCow(gba); if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; + gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } LOAD_16(oldValue, address & (SIZE_CART0 - 2), gba->memory.rom); STORE_16(value, address & (SIZE_CART0 - 2), gba->memory.rom); @@ -1017,6 +1020,7 @@ void GBAPatch8(struct ARMCore* cpu, uint32_t address, int8_t value, int8_t* old) _pristineCow(gba); if ((address & (SIZE_CART0 - 1)) >= gba->memory.romSize) { gba->memory.romSize = (address & (SIZE_CART0 - 2)) + 2; + gba->memory.romMask = toPow2(gba->memory.romSize) - 1; } oldValue = ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)]; ((int8_t*) memory->rom)[address & (SIZE_CART0 - 1)] = value; diff --git a/src/gba/memory.h b/src/gba/memory.h index dd9d4066b..e0f059730 100644 --- a/src/gba/memory.h +++ b/src/gba/memory.h @@ -118,6 +118,7 @@ struct GBAMemory { struct GBACartridgeHardware hw; struct GBASavedata savedata; size_t romSize; + uint32_t romMask; uint16_t romID; int fullBios; diff --git a/src/util/math.h b/src/util/math.h index 06dca22e5..31709e20a 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -14,4 +14,46 @@ static inline uint32_t popcount32(unsigned bits) { return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; } +static inline unsigned clz32(uint32_t bits) { +#if defined(__GNUC__) || __clang__ + return __builtin_clz(bits); +#else + static const int table[256] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (bits & 0xFF000000) { + return table[bits >> 24]; + } else if (bits & 0x00FF0000) { + return table[bits >> 16] + 8; + } else if (bits & 0x0000FF00) { + return table[bits >> 8] + 16; + } + return table[bits] + 24; +#endif +} + +static inline uint32_t toPow2(uint32_t bits) { + if (!bits) { + return 0; + } + unsigned lz = clz32(bits - 1); + return 1 << (32 - lz); +} + #endif