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 offset;
|
||||||
uint8_t size;
|
uint8_t size;
|
||||||
bool sramActive;
|
bool sramActive;
|
||||||
|
bool locked;
|
||||||
uint8_t unk;
|
uint8_t unk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -295,6 +295,7 @@ DECL_BITS(GBASerializedUnlCartFlags, Subtype, 5, 3);
|
|||||||
|
|
||||||
DECL_BITFIELD(GBASerializedMulticartFlags, uint32_t);
|
DECL_BITFIELD(GBASerializedMulticartFlags, uint32_t);
|
||||||
DECL_BIT(GBASerializedMulticartFlags, DustSettling, 0);
|
DECL_BIT(GBASerializedMulticartFlags, DustSettling, 0);
|
||||||
|
DECL_BIT(GBASerializedMulticartFlags, Locked, 1);
|
||||||
|
|
||||||
DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t);
|
DECL_BITFIELD(GBASerializedSavedataFlags, uint8_t);
|
||||||
DECL_BITS(GBASerializedSavedataFlags, FlashState, 0, 2);
|
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.bank = 0;
|
||||||
gba->memory.unl.multi.offset = 0;
|
gba->memory.unl.multi.offset = 0;
|
||||||
gba->memory.unl.multi.size = 0;
|
gba->memory.unl.multi.size = 0;
|
||||||
|
gba->memory.unl.multi.locked = false;
|
||||||
gba->memory.rom = gba->memory.unl.multi.rom;
|
gba->memory.rom = gba->memory.unl.multi.rom;
|
||||||
gba->memory.romSize = GBA_SIZE_ROM0;
|
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);
|
mLOG(GBA_MEM, DEBUG, "Multicart writing SRAM %06X:%02X", address, value);
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case GBA_MULTICART_CFG_BANK:
|
case GBA_MULTICART_CFG_BANK:
|
||||||
unl->multi.bank = value >> 4;
|
if (!unl->multi.locked) {
|
||||||
if (!(unl->multi.offset & 0x80)) {
|
unl->multi.bank = value >> 4;
|
||||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||||
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GBA_MULTICART_CFG_OFFSET:
|
case GBA_MULTICART_CFG_OFFSET:
|
||||||
unl->multi.offset = value;
|
if (!unl->multi.locked) {
|
||||||
if (!(unl->multi.offset & 0x80)) {
|
unl->multi.offset = value;
|
||||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||||
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
mTimingSchedule(&gba->timing, &unl->multi.settle, MULTI_SETTLE);
|
||||||
|
if (unl->multi.offset & 0x80) {
|
||||||
|
unl->multi.locked = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GBA_MULTICART_CFG_SIZE:
|
case GBA_MULTICART_CFG_SIZE:
|
||||||
unl->multi.size = 0x40 - (value & 0x3F);
|
unl->multi.size = 0x40 - (value & 0x3F);
|
||||||
if (!(unl->multi.offset & 0x80)) {
|
if (!unl->multi.locked) {
|
||||||
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
mTimingDeschedule(&gba->timing, &unl->multi.settle);
|
||||||
mTimingSchedule(&gba->timing, &unl->multi.settle, 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) {
|
void GBAUnlCartSerialize(const struct GBA* gba, struct GBASerializedState* state) {
|
||||||
GBASerializedUnlCartFlags flags = 0;
|
GBASerializedUnlCartFlags flags = 0;
|
||||||
|
GBASerializedMulticartFlags multiFlags = 0;
|
||||||
const struct GBAUnlCart* unl = &gba->memory.unl;
|
const struct GBAUnlCart* unl = &gba->memory.unl;
|
||||||
switch (unl->type) {
|
switch (unl->type) {
|
||||||
case GBA_UNL_CART_NONE:
|
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.sramActive = unl->multi.sramActive;
|
||||||
state->multicart.unk = unl->multi.unk;
|
state->multicart.unk = unl->multi.unk;
|
||||||
state->multicart.currentSize = gba->memory.romSize / MULTI_BLOCK;
|
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_16((gba->memory.rom - unl->multi.rom) / 0x20000, 0, &state->multicart.currentOffset);
|
||||||
STORE_32(unl->multi.settle.when, 0, &state->multicart.settleNextEvent);
|
STORE_32(unl->multi.settle.when, 0, &state->multicart.settleNextEvent);
|
||||||
if (mTimingIsScheduled(&gba->timing, &unl->multi.settle)) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
STORE_32(flags, 0, &state->hw.unlCartFlags);
|
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;
|
gba->memory.rom = unl->multi.rom + offset;
|
||||||
}
|
}
|
||||||
LOAD_32(multiFlags, 0, &state->multicart.flags);
|
LOAD_32(multiFlags, 0, &state->multicart.flags);
|
||||||
|
unl->multi.locked = GBASerializedMulticartFlagsGetLocked(multiFlags);
|
||||||
if (GBASerializedMulticartFlagsIsDustSettling(multiFlags)) {
|
if (GBASerializedMulticartFlagsIsDustSettling(multiFlags)) {
|
||||||
LOAD_32(when, 0, &state->multicart.settleNextEvent);
|
LOAD_32(when, 0, &state->multicart.settleNextEvent);
|
||||||
mTimingSchedule(&gba->timing, &unl->multi.settle, when);
|
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);
|
STORE_32(gba->bus, 0, &state->bus);
|
||||||
|
|
||||||
GBAHardwareSerialize(&gba->memory.hw, state);
|
GBAHardwareSerialize(&gba->memory.hw, state);
|
||||||
GBAUnlCartSerialize(gba, state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* 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);
|
GBADMARecalculateCycles(gba);
|
||||||
GBADMAUpdate(gba);
|
GBADMAUpdate(gba);
|
||||||
GBAHardwareDeserialize(&gba->memory.hw, state);
|
GBAHardwareDeserialize(&gba->memory.hw, state);
|
||||||
GBAUnlCartDeserialize(gba, state);
|
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ void GBASerialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||||||
|
|
||||||
GBAMemorySerialize(&gba->memory, state);
|
GBAMemorySerialize(&gba->memory, state);
|
||||||
GBAIOSerialize(gba, state);
|
GBAIOSerialize(gba, state);
|
||||||
|
GBAUnlCartSerialize(gba, state);
|
||||||
GBAVideoSerialize(&gba->video, state);
|
GBAVideoSerialize(&gba->video, state);
|
||||||
GBAAudioSerialize(&gba->audio, state);
|
GBAAudioSerialize(&gba->audio, state);
|
||||||
GBASavedataSerialize(&gba->memory.savedata, 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");
|
mLOG(GBA_STATE, WARN, "Savestate has unaligned PC and is probably corrupted");
|
||||||
gba->cpu->gprs[ARM_PC] &= ~1;
|
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->memory.activeRegion = -1;
|
||||||
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
|
gba->cpu->memory.setActiveRegion(gba->cpu, gba->cpu->gprs[ARM_PC]);
|
||||||
if (state->biosPrefetch) {
|
if (state->biosPrefetch) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user