GBA BIOS: Clean up decompression routines and add writeback

This commit is contained in:
Jeffrey Pfau 2015-01-07 21:31:39 -08:00
parent 7059fcc257
commit fb35a8b3f7
1 changed files with 72 additions and 59 deletions

View File

@ -12,10 +12,10 @@
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, uint32_t dest, int width); static void _unLz77(struct GBA* gba, int width);
static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest); static void _unHuffman(struct GBA* gba);
static void _unRl(struct GBA* gba, uint32_t source, uint32_t dest, int width); static void _unRl(struct GBA* gba, int width);
static void _unFilter(struct GBA* gba, uint32_t source, uint32_t dest, int inwidth, int outwidth); static void _unFilter(struct GBA* gba, int inwidth, int outwidth);
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];
@ -180,7 +180,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case REGION_WORKING_RAM: case REGION_WORKING_RAM:
case REGION_WORKING_IRAM: case REGION_WORKING_IRAM:
case REGION_VRAM: case REGION_VRAM:
_unLz77(gba, cpu->gprs[0], cpu->gprs[1], immediate == 0x11 ? 1 : 2); _unLz77(gba, immediate == 0x11 ? 1 : 2);
break; break;
} }
break; break;
@ -194,7 +194,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case REGION_WORKING_RAM: case REGION_WORKING_RAM:
case REGION_WORKING_IRAM: case REGION_WORKING_IRAM:
case REGION_VRAM: case REGION_VRAM:
_unHuffman(gba, cpu->gprs[0], cpu->gprs[1]); _unHuffman(gba);
break; break;
} }
break; break;
@ -209,7 +209,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case REGION_WORKING_RAM: case REGION_WORKING_RAM:
case REGION_WORKING_IRAM: case REGION_WORKING_IRAM:
case REGION_VRAM: case REGION_VRAM:
_unRl(gba, cpu->gprs[0], cpu->gprs[1], immediate == 0x14 ? 1 : 2); _unRl(gba, immediate == 0x14 ? 1 : 2);
break; break;
} }
break; break;
@ -225,7 +225,7 @@ void GBASwi16(struct ARMCore* cpu, int immediate) {
case REGION_WORKING_RAM: case REGION_WORKING_RAM:
case REGION_WORKING_IRAM: case REGION_WORKING_IRAM:
case REGION_VRAM: case REGION_VRAM:
_unFilter(gba, cpu->gprs[0], cpu->gprs[1], immediate == 0x18 ? 2 : 1, immediate == 0x16 ? 1 : 2); _unFilter(gba, immediate == 0x18 ? 2 : 1, immediate == 0x16 ? 1 : 2);
break; break;
} }
break; break;
@ -250,13 +250,14 @@ uint32_t GBAChecksum(uint32_t* memory, size_t size) {
return sum; return sum;
} }
static void _unLz77(struct GBA* gba, uint32_t source, uint32_t dest, int width) { static void _unLz77(struct GBA* gba, int width) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
uint32_t source = cpu->gprs[0];
uint32_t dest = cpu->gprs[1];
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 = 0; // Some compilers warn if this isn't set, even though it's trivially provably always set int blockheader = 0; // Some compilers warn if this isn't set, even though it's trivially provably always set
uint32_t sPointer = source + 4; source += 4;
uint32_t dPointer = dest;
int blocksRemaining = 0; int blocksRemaining = 0;
int block; int block;
uint32_t disp; uint32_t disp;
@ -267,51 +268,54 @@ static void _unLz77(struct GBA* gba, uint32_t source, uint32_t dest, int width)
if (blocksRemaining) { if (blocksRemaining) {
if (blockheader & 0x80) { if (blockheader & 0x80) {
// Compressed // Compressed
block = cpu->memory.loadU8(cpu, sPointer, 0) | (cpu->memory.loadU8(cpu, sPointer + 1, 0) << 8); block = cpu->memory.loadU8(cpu, source, 0) | (cpu->memory.loadU8(cpu, source + 1, 0) << 8);
sPointer += 2; source += 2;
disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1; disp = dest - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1;
bytes = ((block & 0x00F0) >> 4) + 3; bytes = ((block & 0x00F0) >> 4) + 3;
while (bytes-- && remaining) { while (bytes-- && remaining) {
--remaining; --remaining;
byte = cpu->memory.loadU8(cpu, disp, 0); byte = cpu->memory.loadU8(cpu, disp, 0);
++disp; ++disp;
if (width == 2) { if (width == 2) {
if (dPointer & 1) { if (dest & 1) {
halfword |= byte << 8; halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0); cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
} else { } else {
halfword = byte; halfword = byte;
} }
} else { } else {
cpu->memory.store8(cpu, dPointer, byte, 0); cpu->memory.store8(cpu, dest, byte, 0);
} }
++dPointer; ++dest;
} }
} else { } else {
// Uncompressed // Uncompressed
byte = cpu->memory.loadU8(cpu, sPointer, 0); byte = cpu->memory.loadU8(cpu, source, 0);
++sPointer; ++source;
if (width == 2) { if (width == 2) {
if (dPointer & 1) { if (dest & 1) {
halfword |= byte << 8; halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0); cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
} else { } else {
halfword = byte; halfword = byte;
} }
} else { } else {
cpu->memory.store8(cpu, dPointer, byte, 0); cpu->memory.store8(cpu, dest, byte, 0);
} }
++dPointer; ++dest;
--remaining; --remaining;
} }
blockheader <<= 1; blockheader <<= 1;
--blocksRemaining; --blocksRemaining;
} else { } else {
blockheader = cpu->memory.loadU8(cpu, sPointer, 0); blockheader = cpu->memory.loadU8(cpu, source, 0);
++sPointer; ++source;
blocksRemaining = 8; blocksRemaining = 8;
} }
} }
cpu->gprs[0] = source;
cpu->gprs[1] = dest;
cpu->gprs[3] = 0;
} }
DECL_BITFIELD(HuffmanNode, uint8_t); DECL_BITFIELD(HuffmanNode, uint8_t);
@ -319,9 +323,10 @@ 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) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
source = source & 0xFFFFFFFC; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC;
uint32_t dest = cpu->gprs[1];
uint32_t header = cpu->memory.load32(cpu, source, 0); uint32_t header = cpu->memory.load32(cpu, source, 0);
int remaining = header >> 8; int remaining = header >> 8;
int bits = header & 0xF; int bits = header & 0xF;
@ -335,8 +340,7 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest) {
int treesize = (cpu->memory.loadU8(cpu, source + 4, 0) << 1) + 1; int treesize = (cpu->memory.loadU8(cpu, source + 4, 0) << 1) + 1;
int block = 0; int block = 0;
uint32_t treeBase = source + 5; uint32_t treeBase = source + 5;
uint32_t sPointer = source + 5 + treesize; source += 5 + treesize;
uint32_t dPointer = dest;
uint32_t nPointer = treeBase; uint32_t nPointer = treeBase;
HuffmanNode node; HuffmanNode node;
int bitsRemaining; int bitsRemaining;
@ -344,8 +348,8 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest) {
int bitsSeen = 0; int bitsSeen = 0;
node = cpu->memory.load8(cpu, nPointer, 0); node = cpu->memory.load8(cpu, nPointer, 0);
while (remaining > 0) { while (remaining > 0) {
uint32_t bitstream = cpu->memory.load32(cpu, sPointer, 0); uint32_t bitstream = cpu->memory.load32(cpu, source, 0);
sPointer += 4; source += 4;
for (bitsRemaining = 32; bitsRemaining > 0 && remaining > 0; --bitsRemaining, bitstream <<= 1) { for (bitsRemaining = 32; bitsRemaining > 0 && remaining > 0; --bitsRemaining, bitstream <<= 1) {
uint32_t next = (nPointer & ~1) + HuffmanNodeGetOffset(node) * 2 + 2; uint32_t next = (nPointer & ~1) + HuffmanNodeGetOffset(node) * 2 + 2;
if (bitstream & 0x80000000) { if (bitstream & 0x80000000) {
@ -374,8 +378,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;
cpu->memory.store32(cpu, dPointer, block, 0); cpu->memory.store32(cpu, dest, block, 0);
dPointer += 4; dest += 4;
remaining -= 4; remaining -= 4;
block = 0; block = 0;
} }
@ -383,82 +387,89 @@ static void _unHuffman(struct GBA* gba, uint32_t source, uint32_t dest) {
} }
if (padding) { if (padding) {
cpu->memory.store32(cpu, dPointer, block, 0); cpu->memory.store32(cpu, dest, block, 0);
} }
cpu->gprs[0] = source;
cpu->gprs[1] = dest;
} }
static void _unRl(struct GBA* gba, uint32_t source, uint32_t dest, int width) { static void _unRl(struct GBA* gba, int width) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
source = source & 0xFFFFFFFC; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC;
int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8; int remaining = (cpu->memory.load32(cpu, source, 0) & 0xFFFFFF00) >> 8;
int padding = (4 - remaining) & 0x3; int padding = (4 - remaining) & 0x3;
// We assume the signature byte (0x30) is correct // We assume the signature byte (0x30) is correct
int blockheader; int blockheader;
int block; int block;
uint32_t sPointer = source + 4; source += 4;
uint32_t dPointer = dest; uint32_t dest = cpu->gprs[1];
int halfword = 0; int halfword = 0;
while (remaining > 0) { while (remaining > 0) {
blockheader = cpu->memory.loadU8(cpu, sPointer++, 0); blockheader = cpu->memory.loadU8(cpu, source, 0);
++source;
if (blockheader & 0x80) { if (blockheader & 0x80) {
// Compressed // Compressed
blockheader &= 0x7F; blockheader &= 0x7F;
blockheader += 3; blockheader += 3;
block = cpu->memory.loadU8(cpu, sPointer++, 0); block = cpu->memory.loadU8(cpu, source, 0);
++source;
while (blockheader-- && remaining) { while (blockheader-- && remaining) {
--remaining; --remaining;
if (width == 2) { if (width == 2) {
if (dPointer & 1) { if (dest & 1) {
halfword |= block << 8; halfword |= block << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0); cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
} else { } else {
halfword = block; halfword = block;
} }
} else { } else {
cpu->memory.store8(cpu, dPointer, block, 0); cpu->memory.store8(cpu, dest, block, 0);
} }
++dPointer; ++dest;
} }
} else { } else {
// Uncompressed // Uncompressed
blockheader++; blockheader++;
while (blockheader-- && remaining) { while (blockheader-- && remaining) {
--remaining; --remaining;
int byte = cpu->memory.loadU8(cpu, sPointer, 0); int byte = cpu->memory.loadU8(cpu, source, 0);
++sPointer; ++source;
if (width == 2) { if (width == 2) {
if (dPointer & 1) { if (dest & 1) {
halfword |= byte << 8; halfword |= byte << 8;
cpu->memory.store16(cpu, dPointer ^ 1, halfword, 0); cpu->memory.store16(cpu, dest ^ 1, halfword, 0);
} else { } else {
halfword = byte; halfword = byte;
} }
} else { } else {
cpu->memory.store8(cpu, dPointer, byte, 0); cpu->memory.store8(cpu, dest, byte, 0);
} }
++dPointer; ++dest;
} }
} }
} }
if (width == 2) { if (width == 2) {
if (dPointer & 1) { if (dest & 1) {
--padding; --padding;
++dPointer; ++dest;
} }
for (; padding > 0; padding -= 2, dPointer += 2) { for (; padding > 0; padding -= 2, dest += 2) {
cpu->memory.store16(cpu, dPointer, 0, 0); cpu->memory.store16(cpu, dest, 0, 0);
} }
} else { } else {
while (padding--) { while (padding--) {
cpu->memory.store8(cpu, dPointer, 0, 0); cpu->memory.store8(cpu, dest, 0, 0);
++dPointer; ++dest;
} }
} }
cpu->gprs[0] = source;
cpu->gprs[1] = dest;
} }
static void _unFilter(struct GBA* gba, uint32_t source, uint32_t dest, int inwidth, int outwidth) { static void _unFilter(struct GBA* gba, int inwidth, int outwidth) {
struct ARMCore* cpu = gba->cpu; struct ARMCore* cpu = gba->cpu;
source = source & 0xFFFFFFFC; uint32_t source = cpu->gprs[0] & 0xFFFFFFFC;
uint32_t dest = cpu->gprs[1];
uint32_t header = cpu->memory.load32(cpu, source, 0); uint32_t header = cpu->memory.load32(cpu, source, 0);
int remaining = header >> 8; int remaining = header >> 8;
// We assume the signature nybble (0x8) is correct // We assume the signature nybble (0x8) is correct
@ -487,4 +498,6 @@ static void _unFilter(struct GBA* gba, uint32_t source, uint32_t dest, int inwid
source += inwidth; source += inwidth;
remaining -= outwidth; remaining -= outwidth;
} }
cpu->gprs[0] = source;
cpu->gprs[1] = dest;
} }