mirror of https://github.com/mgba-emu/mgba.git
GBA Unlicensed Carts: Prevent multicarts from remapping after being locked
This commit is contained in:
parent
822a2c8df5
commit
a5e3e746b2
|
@ -42,6 +42,7 @@ struct GBAMulticart {
|
|||
uint8_t offset;
|
||||
uint8_t size;
|
||||
bool sramActive;
|
||||
bool locked;
|
||||
uint8_t unk;
|
||||
};
|
||||
|
||||
|
|
|
@ -295,6 +295,7 @@ DECL_BITS(GBASerializedUnlCartFlags, Subtype, 5, 3);
|
|||
|
||||
DECL_BITFIELD(GBASerializedMulticartFlags, uint32_t);
|
||||
DECL_BIT(GBASerializedMulticartFlags, DustSettling, 0);
|
||||
DECL_BIT(GBASerializedMulticartFlags, Locked, 1);
|
||||
|
||||
DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t);
|
||||
DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2);
|
||||
|
|
|
@ -69,6 +69,7 @@ void GBAUnlCartReset(struct GBA* gba) {
|
|||
gba->memory.unl.multi.bank = 0;
|
||||
gba->memory.unl.multi.offset = 0;
|
||||
gba->memory.unl.multi.size = 0;
|
||||
gba->memory.unl.multi.locked = false;
|
||||
gba->memory.rom = gba->memory.unl.multi.rom;
|
||||
gba->memory.romSize = GBA_SIZE_ROM0;
|
||||
}
|
||||
|
@ -93,22 +94,25 @@ void GBAUnlCartWriteSRAM(struct GBA* gba, uint32_t address, uint8_t value) {
|
|||
mLOG(GBA_MEM, DEBUG, "Multicart writing SRAM %06X:%02X", address, value);
|
||||
switch (address) {
|
||||
case GBA_MULTICART_CFG_BANK:
|
||||
unl->multi.bank = value >> 4;
|
||||
if (!(unl->multi.offset & 0x80)) {
|
||||
if (!unl->multi.locked) {
|
||||
unl->multi.bank = value >> 4;
|
||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
||||
}
|
||||
break;
|
||||
case GBA_MULTICART_CFG_OFFSET:
|
||||
unl->multi.offset = value;
|
||||
if (!(unl->multi.offset & 0x80)) {
|
||||
if (!unl->multi.locked) {
|
||||
unl->multi.offset = value;
|
||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
||||
if (unl->multi.offset & 0x80) {
|
||||
unl->multi.locked = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GBA_MULTICART_CFG_SIZE:
|
||||
unl->multi.size = 0x40 - (value & 0x3F);
|
||||
if (!(unl->multi.offset & 0x80)) {
|
||||
if (!unl->multi.locked) {
|
||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
||||
}
|
||||
|
@ -167,6 +171,7 @@ static void _multicartSettle(struct mTiming* timing, void* context, uint32_t cyc
|
|||
|
||||
void GBAUnlCartSerialize(const struct GBA* gba, struct GBASerializedState* state) {
|
||||
GBASerializedUnlCartFlags flags = 0;
|
||||
GBASerializedMulticartFlags multiFlags = 0;
|
||||
const struct GBAUnlCart* unl = &gba->memory.unl;
|
||||
switch (unl->type) {
|
||||
case GBA_UNL_CART_NONE:
|
||||
|
@ -187,11 +192,13 @@ void GBAUnlCartSerialize(const struct GBA* gba, struct GBASerializedState* state
|
|||
state->multicart.sramActive = unl->multi.sramActive;
|
||||
state->multicart.unk = unl->multi.unk;
|
||||
state->multicart.currentSize = gba->memory.romSize / MULTI_BLOCK;
|
||||
multiFlags = GBASerializedMulticartFlagsSetLocked(flags, unl->multi.locked);
|
||||
STORE_16((gba->memory.rom - unl->multi.rom) / 0x20000, 0, &state->multicart.currentOffset);
|
||||
STORE_32(unl->multi.settle.when, 0, &state->multicart.settleNextEvent);
|
||||
if (mTimingIsScheduled(&gba->timing, &unl->multi.settle)) {
|
||||
STORE_32(GBASerializedMulticartFlagsFillDustSettling(0), 0, &state->multicart.flags);
|
||||
multiFlags = GBASerializedMulticartFlagsFillDustSettling(multiFlags);
|
||||
}
|
||||
STORE_32(multiFlags, 0, &state->multicart.flags);
|
||||
break;
|
||||
}
|
||||
STORE_32(flags, 0, &state->hw.unlCartFlags);
|
||||
|
@ -238,6 +245,7 @@ void GBAUnlCartDeserialize(struct GBA* gba, const struct GBASerializedState* sta
|
|||
gba->memory.rom = unl->multi.rom + offset;
|
||||
}
|
||||
LOAD_32(multiFlags, 0, &state->multicart.flags);
|
||||
unl->multi.locked = GBASerializedMulticartFlagsGetLocked(multiFlags);
|
||||
if (GBASerializedMulticartFlagsIsDustSettling(multiFlags)) {
|
||||
LOAD_32(when, 0, &state->multicart.settleNextEvent);
|
||||
mTimingSchedule(&gba->timing, &unl->multi.settle, when);
|
||||
|
|
|
@ -1033,7 +1033,6 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
STORE_32(gba->bus, 0, &state->bus);
|
||||
|
||||
GBAHardwareSerialize(&gba->memory.hw, state);
|
||||
GBAUnlCartSerialize(gba, state);
|
||||
}
|
||||
|
||||
void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
||||
|
@ -1083,5 +1082,4 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
GBADMARecalculateCycles(gba);
|
||||
GBADMAUpdate(gba);
|
||||
GBAHardwareDeserialize(&gba->memory.hw, state);
|
||||
GBAUnlCartDeserialize(gba, state);
|
||||
}
|
||||
|
|
|
@ -83,6 +83,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
|
||||
GBAMemorySerialize(&gba->memory, state);
|
||||
GBAIOSerialize(gba, state);
|
||||
GBAUnlCartSerialize(gba, state);
|
||||
GBAVideoSerialize(&gba->video, state);
|
||||
GBAAudioSerialize(&gba->audio, state);
|
||||
GBASavedataSerialize(&gba->memory.savedata, state);
|
||||
|
@ -180,6 +181,9 @@ bool GBADeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
mLOG(GBA_STATE, WARN, "Savestate has unaligned PC and is probably corrupted");
|
||||
gba->cpu->gprs[ARM_PC] &= ~1;
|
||||
}
|
||||
|
||||
// Since this can remap the ROM, we need to do this before we reset the pipeline
|
||||
GBAUnlCartDeserialize(gba, state);
|
||||
gba->memory.activeRegion = -1;
|
||||
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
|
||||
if (state->biosPrefetch) {
|
||||
|
|
Loading…
Reference in New Issue