mirror of https://github.com/mgba-emu/mgba.git
GBA BIOS: Clean up decompression routines and add writeback
This commit is contained in:
parent
7059fcc257
commit
fb35a8b3f7
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue