GBA BIOS: Fix HLE Lz77 and RL functions to properly account for width and invalid addresses

This commit is contained in:
Jeffrey Pfau 2014-12-17 02:35:57 -08:00
parent 9bd5b02644
commit 9eca161dc9
2 changed files with 89 additions and 51 deletions

View File

@ -6,6 +6,7 @@ Bugfixes:
- Qt: Fix issue with set frame sizes being the wrong height - Qt: Fix issue with set frame sizes being the wrong height
- Qt: Fix emulator crashing when full screen if a game is not running - Qt: Fix emulator crashing when full screen if a game is not running
- GBA Thread: Allow halted games to exit cleanly - GBA Thread: Allow halted games to exit cleanly
- GBA BIOS: Fix HLE Lz77 and RL functions to properly account for width and invalid addresses
Misc: Misc:
- Qt: Disable sync to video by default - Qt: Disable sync to video by default

View File

@ -12,9 +12,9 @@
const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F; const uint32_t GBA_BIOS_CHECKSUM = 0xBAAE187F;
const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880; const uint32_t GBA_DS_BIOS_CHECKSUM = 0xBAAE1880;
static void _unLz77(struct GBA* gba, uint32_t source, uint8_t* dest); static void _unLz77(struct GBA* gba, uint32_t source, uint32_t dest, int width);
static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest); static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest);
static void _unRl(struct GBA* gba, uint32_t source, uint8_t* dest); static void _unRl(struct GBA* gba, uint32_t source, uint32_t dest, int width);
static void _RegisterRamReset(struct GBA* gba) { static void _RegisterRamReset(struct GBA* gba) {
uint32_t registers = gba->cpu->gprs[0]; uint32_t registers = gba->cpu->gprs[0];
@ -172,40 +172,28 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case 0x12: case 0x12:
if (cpu->gprs[0] < BASE_WORKING_RAM) { if (cpu->gprs[0] < BASE_WORKING_RAM) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 source"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 source");
break;
} }
switch (cpu->gprs[1] >> BASE_OFFSET) { switch (cpu->gprs[1] >> BASE_OFFSET) {
case REGION_WORKING_RAM:
_unLz77(gba, cpu->gprs[0], &((uint8_t*) gba->memory.wram)[(cpu->gprs[1] & (SIZE_WORKING_RAM - 1))]);
break;
case REGION_WORKING_IRAM:
_unLz77(gba, cpu->gprs[0], &((uint8_t*) gba->memory.iwram)[(cpu->gprs[1] & (SIZE_WORKING_IRAM - 1))]);
break;
case REGION_VRAM:
_unLz77(gba, cpu->gprs[0], &((uint8_t*) gba->video.renderer->vram)[(cpu->gprs[1] & 0x0001FFFF)]);
break;
default: default:
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 destination"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad LZ77 destination");
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
_unLz77(gba, cpu->gprs[0], cpu->gprs[1], immediate == 0x11 ? 1 : 2);
break; break;
} }
break; break;
case 0x13: case 0x13:
if (cpu->gprs[0] < BASE_WORKING_RAM) { if (cpu->gprs[0] < BASE_WORKING_RAM) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman source"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman source");
break;
} }
switch (cpu->gprs[1] >> BASE_OFFSET) { switch (cpu->gprs[1] >> BASE_OFFSET) {
case REGION_WORKING_RAM:
_unHuffman(gba, cpu->gprs[0], &((uint32_t*) gba->memory.wram)[(cpu->gprs[1] & (SIZE_WORKING_RAM - 3)) >> 2]);
break;
case REGION_WORKING_IRAM:
_unHuffman(gba, cpu->gprs[0], &((uint32_t*) gba->memory.iwram)[(cpu->gprs[1] & (SIZE_WORKING_IRAM - 3)) >> 2]);
break;
case REGION_VRAM:
_unHuffman(gba, cpu->gprs[0], &((uint32_t*) gba->video.renderer->vram)[(cpu->gprs[1] & 0x0001FFFC) >> 2]);
break;
default: default:
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman destination"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad Huffman destination");
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
_unHuffman(gba, cpu->gprs[0], cpu->gprs[1]);
break; break;
} }
break; break;
@ -213,20 +201,14 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case 0x15: case 0x15:
if (cpu->gprs[0] < BASE_WORKING_RAM) { if (cpu->gprs[0] < BASE_WORKING_RAM) {
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL source"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL source");
break;
} }
switch (cpu->gprs[1] >> BASE_OFFSET) { switch (cpu->gprs[1] >> BASE_OFFSET) {
case REGION_WORKING_RAM:
_unRl(gba, cpu->gprs[0], &((uint8_t*) gba->memory.wram)[(cpu->gprs[1] & (SIZE_WORKING_RAM - 1))]);
break;
case REGION_WORKING_IRAM:
_unRl(gba, cpu->gprs[0], &((uint8_t*) gba->memory.iwram)[(cpu->gprs[1] & (SIZE_WORKING_IRAM - 1))]);
break;
case REGION_VRAM:
_unRl(gba, cpu->gprs[0], &((uint8_t*) gba->video.renderer->vram)[(cpu->gprs[1] & 0x0001FFFF)]);
break;
default: default:
GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL destination"); GBALog(gba, GBA_LOG_GAME_ERROR, "Bad RL destination");
case REGION_WORKING_RAM:
case REGION_WORKING_IRAM:
case REGION_VRAM:
_unRl(gba, cpu->gprs[0], cpu->gprs[1], immediate == 0x14 ? 1 : 2);
break; break;
} }
break; break;
@ -251,17 +233,19 @@ uint32_t GBAChecksum(uint32_t* memory, size_t size) {
return sum; return sum;
} }
static void _unLz77(struct GBA* gba, uint32_t source, uint8_t* dest) { static void _unLz77(struct GBA* gba, uint32_t source, uint32_t dest, int width) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8; int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8;
// We assume the signature byte (0x10) is correct // We assume the signature byte (0x10) is correct
int blockheader; int blockheader;
uint32_t sPointer = source + 4; uint32_t sPointer = source + 4;
uint8_t* dPointer = dest; uint32_t dPointer = dest;
int blocksRemaining = 0; int blocksRemaining = 0;
int block; int block;
uint8_t* disp; uint32_t disp;
int bytes; int bytes;
int byte;
int halfword;
while (remaining > 0) { while (remaining > 0) {
if (blocksRemaining) { if (blocksRemaining) {
if (blockheader & 0x80) { if (blockheader & 0x80) {
@ -272,20 +256,42 @@ static void _unLz77(struct GBA* gba, uint32_t source, uint8_t* dest) {
bytes = ((block & 0x00F0) >> 4) + 3; bytes = ((block & 0x00F0) >> 4) + 3;
while (bytes-- && remaining) { while (bytes-- && remaining) {
--remaining; --remaining;
*dPointer = *disp; byte = cpu->memory.loadU8(cpu, disp, 0);
++disp; ++disp;
if (width == 2) {
if (dPointer & 1) {
halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0);
} else {
halfword = byte;
}
} else {
cpu->memory.store8(cpu, dPointer, byte, 0);
}
++dPointer; ++dPointer;
} }
} else { } else {
// Uncompressed // Uncompressed
*dPointer = cpu->memory.loadU8(cpu, sPointer++, 0); byte = cpu->memory.loadU8(cpu, sPointer, 0);
++sPointer;
if (width == 2) {
if (dPointer & 1) {
halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0);
} else {
halfword = byte;
}
} else {
cpu->memory.store8(cpu, dPointer, byte, 0);
}
++dPointer; ++dPointer;
--remaining; --remaining;
} }
blockheader <<= 1; blockheader <<= 1;
--blocksRemaining; --blocksRemaining;
} else { } else {
blockheader = cpu->memory.loadU8(cpu, sPointer++, 0); blockheader = cpu->memory.loadU8(cpu, sPointer, 0);
++sPointer;
blocksRemaining = 8; blocksRemaining = 8;
} }
} }
@ -296,7 +302,7 @@ DECL_BITS(HuffmanNode, Offset, 0, 6);
DECL_BIT(HuffmanNode, RTerm, 6); DECL_BIT(HuffmanNode, RTerm, 6);
DECL_BIT(HuffmanNode, LTerm, 7); DECL_BIT(HuffmanNode, LTerm, 7);
static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) { static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
source = source & 0xFFFFFFFC; source = source & 0xFFFFFFFC;
uint32_t header = cpu->memory.load32(cpu, source, 0); uint32_t header = cpu->memory.load32(cpu, source, 0);
@ -313,7 +319,7 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
int block = 0; int block = 0;
uint32_t treeBase = source + 5; uint32_t treeBase = source + 5;
uint32_t sPointer = source + 5 + treesize; uint32_t sPointer = source + 5 + treesize;
uint32_t* dPointer = dest; uint32_t dPointer = dest;
uint32_t nPointer = treeBase; uint32_t nPointer = treeBase;
HuffmanNode node; HuffmanNode node;
int bitsRemaining; int bitsRemaining;
@ -351,8 +357,8 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
node = cpu->memory.load8(cpu, nPointer, 0); node = cpu->memory.load8(cpu, nPointer, 0);
if (bitsSeen == 32) { if (bitsSeen == 32) {
bitsSeen = 0; bitsSeen = 0;
*dPointer = block; cpu->memory.store32(cpu, dPointer, block, 0);
++dPointer; dPointer += 4;
remaining -= 4; remaining -= 4;
block = 0; block = 0;
} }
@ -360,11 +366,11 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t* dest) {
} }
if (padding) { if (padding) {
*dPointer = block; cpu->memory.store32(cpu, dPointer, block, 0);
} }
} }
static void _unRl(struct GBA* gba, uint32_t source, uint8_t* dest) { static void _unRl(struct GBA* gba, uint32_t source, uint32_t dest, int width) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
source = source & 0xFFFFFFFC; source = source & 0xFFFFFFFC;
int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8; int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8;
@ -373,7 +379,8 @@ static void _unRl(struct GBA* gba, uint32_t source, uint8_t* dest) {
int blockheader; int blockheader;
int block; int block;
uint32_t sPointer = source + 4; uint32_t sPointer = source + 4;
uint8_t* dPointer = dest; uint32_t dPointer = dest;
int halfword;
while (remaining > 0) { while (remaining > 0) {
blockheader = cpu->memory.loadU8(cpu, sPointer++, 0); blockheader = cpu->memory.loadU8(cpu, sPointer++, 0);
if (blockheader & 0x80) { if (blockheader & 0x80) {
@ -383,7 +390,16 @@ static void _unRl(struct GBA* gba, uint32_t source, uint8_t* dest) {
block = cpu->memory.loadU8(cpu, sPointer++, 0); block = cpu->memory.loadU8(cpu, sPointer++, 0);
while (blockheader-- && remaining) { while (blockheader-- && remaining) {
--remaining; --remaining;
*dPointer = block; if (width == 2) {
if (dPointer & 1) {
halfword |= block << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0);
} else {
halfword = block;
}
} else {
cpu->memory.store8(cpu, dPointer, block, 0);
}
++dPointer; ++dPointer;
} }
} else { } else {
@ -391,13 +407,34 @@ static void _unRl(struct GBA* gba, uint32_t source, uint8_t* dest) {
blockheader++; blockheader++;
while (blockheader-- && remaining) { while (blockheader-- && remaining) {
--remaining; --remaining;
*dPointer = cpu->memory.loadU8(cpu, sPointer++, 0); int byte = cpu->memory.loadU8(cpu, sPointer, 0);
++sPointer;
if (width == 2) {
if (dPointer & 1) {
halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0);
} else {
halfword = byte;
}
} else {
cpu->memory.store8(cpu, dPointer, byte, 0);
}
++dPointer; ++dPointer;
} }
} }
} }
while (padding--) { if (width == 2) {
*dPointer = 0; if (dPointer & 1) {
++dPointer; --padding;
++dPointer;
}
for (; padding > 0; padding -= 2, dPointer += 2) {
cpu->memory.store16(cpu, dPointer, 0, 0);
}
} else {
while (padding--) {
cpu->memory.store8(cpu, dPointer, 0, 0);
++dPointer;
}
} }
} }