all repos — mgba @ e83936152da8f87ef9e086c71530a5a6cb9e24f4

mGBA Game Boy Advance Emulator

Implement LZ77 decompression
Jeffrey Pfau jeffrey@endrift.com
Sat, 20 Apr 2013 02:52:10 -0700
commit

e83936152da8f87ef9e086c71530a5a6cb9e24f4

parent

cf9a7224a37c75b0e015ae857d32dbdde2febca9

1 files changed, 47 insertions(+), 0 deletions(-)

jump to
M src/gba/gba-bios.csrc/gba/gba-bios.c

@@ -3,6 +3,8 @@

#include "gba.h" #include "gba-memory.h" +static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest); + static void _CpuSet(struct GBA* gba) { uint32_t source = gba->cpu.gprs[0]; uint32_t dest = gba->cpu.gprs[1];

@@ -78,6 +80,12 @@ break;

case 0xC: _FastCpuSet(gba); break; + case 0x11: + _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->memory.wram)[(gba->cpu.gprs[1] & (SIZE_WORKING_RAM - 1))]); + break; + case 0x12: + _unLz77(&gba->memory, gba->cpu.gprs[0], &((uint8_t*) gba->video.renderer->vram)[(gba->cpu.gprs[1] & (SIZE_VRAM - 1))]); + break; default: GBALog(GBA_LOG_STUB, "Stub software interrupt: %02x", immediate); }

@@ -86,3 +94,42 @@

void GBASwi32(struct ARMBoard* board, int immediate) { GBASwi32(board, immediate >> 16); } + +static void _unLz77(struct GBAMemory* memory, uint32_t source, uint8_t* dest) { + int remaining = (GBALoad32(&memory->d, source) & 0xFFFFFF00) >> 8; + // We assume the signature byte (0x10) is correct + int blockheader; + uint32_t sPointer = source + 4; + uint8_t* dPointer = dest; + int blocksRemaining = 0; + int block; + uint8_t* disp; + int bytes; + while (remaining > 0) { + if (blocksRemaining) { + if (blockheader & 0x80) { + // Compressed + block = GBALoadU8(&memory->d, sPointer) | (GBALoadU8(&memory->d, sPointer + 1) << 8); + sPointer += 2; + disp = dPointer - (((block & 0x000F) << 8) | ((block & 0xFF00) >> 8)) - 1; + bytes = ((block & 0x00F0) >> 4) + 3; + while (bytes-- && remaining) { + --remaining; + *dPointer = *disp; + ++disp; + ++dPointer; + } + } else { + // Uncompressed + *dPointer = GBALoadU8(&memory->d, sPointer++); + ++dPointer; + --remaining; + } + blockheader <<= 1; + --blocksRemaining; + } else { + blockheader = GBALoadU8(&memory->d, sPointer++); + blocksRemaining = 8; + } + } +}