mirror of https://github.com/mgba-emu/mgba.git
GBA Memory: Implement adjustable EWRAM waitstates (closes #1276)
This commit is contained in:
parent
8c83570191
commit
f9e03e7182
1
CHANGES
1
CHANGES
|
@ -67,6 +67,7 @@ Misc:
|
|||
- GBA: Automatically skip BIOS if ROM has invalid logo
|
||||
- GBA: Refine multiboot detection (fixes mgba.io/i/2192)
|
||||
- GBA Cheats: Implement "never" type codes (closes mgba.io/i/915)
|
||||
- GBA Memory: Implement adjustable EWRAM waitstates (closes mgba.io/i/1276)
|
||||
- GBA DMA: Enhanced logging (closes mgba.io/i/2454)
|
||||
- GBA Video: Implement layer placement for OpenGL renderer (fixes mgba.io/i/1962)
|
||||
- GBA Video: Fix highlighting for sprites with mid-frame palette changes
|
||||
|
|
|
@ -154,6 +154,13 @@ enum GBAIORegisters {
|
|||
REG_POSTFLG = 0x300,
|
||||
REG_HALTCNT = 0x301,
|
||||
|
||||
REG_EXWAITCNT_LO = 0x800,
|
||||
REG_EXWAITCNT_HI = 0x802,
|
||||
|
||||
REG_INTERNAL_EXWAITCNT_LO = 0x210,
|
||||
REG_INTERNAL_EXWAITCNT_HI = 0x212,
|
||||
REG_INTERNAL_MAX = 0x214,
|
||||
|
||||
REG_DEBUG_STRING = 0xFFF600,
|
||||
REG_DEBUG_FLAGS = 0xFFF700,
|
||||
REG_DEBUG_ENABLE = 0xFFF780,
|
||||
|
|
|
@ -172,6 +172,7 @@ uint32_t GBAStoreMultiple(struct ARMCore*, uint32_t baseAddress, int mask, enum
|
|||
int* cycleCounter);
|
||||
|
||||
void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters);
|
||||
void GBAAdjustEWRAMWaitstates(struct GBA* gba, uint16_t parameters);
|
||||
|
||||
struct GBASerializedState;
|
||||
void GBAMemorySerialize(const struct GBAMemory* memory, struct GBASerializedState* state);
|
||||
|
|
|
@ -20,7 +20,7 @@ extern MGBA_EXPORT const uint32_t GBASavestateVersion;
|
|||
mLOG_DECLARE_CATEGORY(GBA_STATE);
|
||||
|
||||
/* Savestate format:
|
||||
* 0x00000 - 0x00003: Version Magic (0x01000005)
|
||||
* 0x00000 - 0x00003: Version Magic (0x01000006)
|
||||
* 0x00004 - 0x00007: BIOS checksum (e.g. 0xBAAE187F for official BIOS)
|
||||
* 0x00008 - 0x0000B: ROM CRC32
|
||||
* 0x0000C - 0x0000F: Master cycles
|
||||
|
|
35
src/gba/io.c
35
src/gba/io.c
|
@ -199,7 +199,7 @@ const char* const GBAIORegisterNames[] = {
|
|||
"IME"
|
||||
};
|
||||
|
||||
static const int _isValidRegister[REG_MAX >> 1] = {
|
||||
static const int _isValidRegister[REG_INTERNAL_MAX >> 1] = {
|
||||
// Video
|
||||
1, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
@ -238,10 +238,12 @@ static const int _isValidRegister[REG_MAX >> 1] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// Interrupts
|
||||
1, 1, 1, 0, 1
|
||||
1, 1, 1, 0, 1, 0, 0, 0,
|
||||
// Internal registers
|
||||
1, 1
|
||||
};
|
||||
|
||||
static const int _isRSpecialRegister[REG_MAX >> 1] = {
|
||||
static const int _isRSpecialRegister[REG_INTERNAL_MAX >> 1] = {
|
||||
// Video
|
||||
0, 0, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
@ -280,9 +282,12 @@ static const int _isRSpecialRegister[REG_MAX >> 1] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// Interrupts
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// Internal registers
|
||||
1, 1
|
||||
};
|
||||
|
||||
static const int _isWSpecialRegister[REG_MAX >> 1] = {
|
||||
static const int _isWSpecialRegister[REG_INTERNAL_MAX >> 1] = {
|
||||
// Video
|
||||
0, 0, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -321,7 +326,9 @@ static const int _isWSpecialRegister[REG_MAX >> 1] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// Interrupts
|
||||
1, 1, 0, 0, 1
|
||||
1, 1, 0, 0, 1, 0, 0, 0,
|
||||
// Internal registers
|
||||
1, 1
|
||||
};
|
||||
|
||||
void GBAIOInit(struct GBA* gba) {
|
||||
|
@ -333,6 +340,8 @@ void GBAIOInit(struct GBA* gba) {
|
|||
gba->memory.io[REG_BG2PD >> 1] = 0x100;
|
||||
gba->memory.io[REG_BG3PA >> 1] = 0x100;
|
||||
gba->memory.io[REG_BG3PD >> 1] = 0x100;
|
||||
gba->memory.io[REG_INTERNAL_EXWAITCNT_LO >> 1] = 0x20;
|
||||
gba->memory.io[REG_INTERNAL_EXWAITCNT_HI >> 1] = 0xD00;
|
||||
|
||||
if (!gba->biosVf) {
|
||||
gba->memory.io[REG_VCOUNT >> 1] = 0x7E;
|
||||
|
@ -574,6 +583,12 @@ void GBAIOWrite(struct GBA* gba, uint32_t address, uint16_t value) {
|
|||
case REG_MAX:
|
||||
// Some bad interrupt libraries will write to this
|
||||
break;
|
||||
case REG_EXWAITCNT_HI:
|
||||
// This register sits outside of the normal I/O block, so we need to stash it somewhere unused
|
||||
address = REG_INTERNAL_EXWAITCNT_HI;
|
||||
value &= 0xFF00;
|
||||
GBAAdjustEWRAMWaitstates(gba, value);
|
||||
break;
|
||||
case REG_DEBUG_ENABLE:
|
||||
gba->debug = value == 0xC0DE;
|
||||
return;
|
||||
|
@ -936,6 +951,11 @@ 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;
|
||||
// These registers sit outside of the normal I/O block, so we need to stash them somewhere unused
|
||||
case REG_EXWAITCNT_LO:
|
||||
case REG_EXWAITCNT_HI:
|
||||
address += REG_INTERNAL_EXWAITCNT_LO - REG_EXWAITCNT_LO;
|
||||
break;
|
||||
case REG_DEBUG_ENABLE:
|
||||
if (gba->debug) {
|
||||
return 0x1DEA;
|
||||
|
@ -950,7 +970,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
|
|||
|
||||
void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) {
|
||||
int i;
|
||||
for (i = 0; i < REG_MAX; i += 2) {
|
||||
for (i = 0; i < REG_INTERNAL_MAX; i += 2) {
|
||||
if (_isRSpecialRegister[i >> 1]) {
|
||||
STORE_16(gba->memory.io[i >> 1], i, state->io);
|
||||
} else if (_isValidRegister[i >> 1]) {
|
||||
|
@ -991,6 +1011,9 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
|
|||
GBAIOWrite(gba, i, reg);
|
||||
}
|
||||
}
|
||||
if (state->versionMagic >= 0x01000006) {
|
||||
GBAIOWrite(gba, REG_EXWAITCNT_HI, gba->memory.io[REG_INTERNAL_EXWAITCNT_HI >> 1]);
|
||||
}
|
||||
|
||||
uint32_t when;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
|
|
|
@ -127,6 +127,7 @@ void GBAMemoryReset(struct GBA* gba) {
|
|||
|
||||
memset(gba->memory.io, 0, sizeof(gba->memory.io));
|
||||
GBAAdjustWaitstates(gba, 0);
|
||||
GBAAdjustEWRAMWaitstates(gba, 0x0D00);
|
||||
|
||||
gba->memory.activeRegion = -1;
|
||||
gba->memory.agbPrintProtect = 0;
|
||||
|
@ -1714,6 +1715,31 @@ void GBAAdjustWaitstates(struct GBA* gba, uint16_t parameters) {
|
|||
}
|
||||
}
|
||||
|
||||
void GBAAdjustEWRAMWaitstates(struct GBA* gba, uint16_t parameters) {
|
||||
struct GBAMemory* memory = &gba->memory;
|
||||
struct ARMCore* cpu = gba->cpu;
|
||||
|
||||
int wait = 15 - ((parameters >> 8) & 0xF);
|
||||
if (wait) {
|
||||
memory->waitstatesNonseq16[REGION_WORKING_RAM] = wait;
|
||||
memory->waitstatesSeq16[REGION_WORKING_RAM] = wait;
|
||||
memory->waitstatesNonseq32[REGION_WORKING_RAM] = 2 * wait + 1;
|
||||
memory->waitstatesSeq32[REGION_WORKING_RAM] = 2 * wait + 1;
|
||||
|
||||
cpu->memory.activeSeqCycles32 = memory->waitstatesSeq32[memory->activeRegion];
|
||||
cpu->memory.activeSeqCycles16 = memory->waitstatesSeq16[memory->activeRegion];
|
||||
|
||||
cpu->memory.activeNonseqCycles32 = memory->waitstatesNonseq32[memory->activeRegion];
|
||||
cpu->memory.activeNonseqCycles16 = memory->waitstatesNonseq16[memory->activeRegion];
|
||||
} else {
|
||||
if (!gba->hardCrash) {
|
||||
mLOG(GBA_MEM, GAME_ERROR, "Cannot set EWRAM to 0 waitstates");
|
||||
} else {
|
||||
mLOG(GBA_MEM, FATAL, "Cannot set EWRAM to 0 waitstates");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GBAMemoryStall(struct ARMCore* cpu, int32_t wait) {
|
||||
struct GBA* gba = (struct GBA*) cpu->master;
|
||||
struct GBAMemory* memory = &gba->memory;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <fcntl.h>
|
||||
|
||||
MGBA_EXPORT const uint32_t GBASavestateMagic = 0x01000000;
|
||||
MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000005;
|
||||
MGBA_EXPORT const uint32_t GBASavestateVersion = 0x00000006;
|
||||
|
||||
mLOG_DEFINE_CATEGORY(GBA_STATE, "GBA Savestate", "gba.serialize");
|
||||
|
||||
|
|
Loading…
Reference in New Issue