GBA BIOS: Implement BitUnPack
Jeffrey Pfau jeffrey@endrift.com
Mon, 07 Nov 2016 13:51:53 -0800
2 files changed,
78 insertions(+),
0 deletions(-)
M
CHANGES
→
CHANGES
@@ -30,6 +30,7 @@ - GB Memory: Fix starting HDMAs during mode 0
- Qt: Fix Qt Multimedia audio driver on big endian - GBA: Fix IRQs firing after already being cleared - All: Fix fullscreen config option being ignored + - GBA BIOS: Implement BitUnPack Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers
M
src/gba/bios.c
→
src/gba/bios.c
@@ -20,6 +20,7 @@ static void _unLz77(struct GBA* gba, int width);
static void _unHuffman(struct GBA* gba); static void _unRl(struct GBA* gba, int width); static void _unFilter(struct GBA* gba, int inwidth, int outwidth); +static void _unBitPack(struct GBA* gba); static void _SoftReset(struct GBA* gba) { struct ARMCore* cpu = gba->cpu;@@ -385,6 +386,22 @@ break;
case 0xF: _ObjAffineSet(gba); break; + case 0x10: + if (cpu->gprs[0] < BASE_WORKING_RAM) { + mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source"); + break; + } + switch (cpu->gprs[1] >> BASE_OFFSET) { + default: + mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination"); + // Fall through + case REGION_WORKING_RAM: + case REGION_WORKING_IRAM: + case REGION_VRAM: + _unBitPack(gba); + break; + } + break; case 0x11: case 0x12: if (cpu->gprs[0] < BASE_WORKING_RAM) {@@ -736,3 +753,63 @@ }
cpu->gprs[0] = source; cpu->gprs[1] = dest; } + +static void _unBitPack(struct GBA* gba) { + struct ARMCore* cpu = gba->cpu; + uint32_t source = cpu->gprs[0]; + uint32_t dest = cpu->gprs[1]; + uint32_t info = cpu->gprs[2]; + unsigned sourceLen = cpu->memory.load16(cpu, info, 0); + unsigned sourceWidth = cpu->memory.load8(cpu, info + 2, 0); + unsigned destWidth = cpu->memory.load8(cpu, info + 3, 0); + switch (sourceWidth) { + case 1: + case 2: + case 4: + case 8: + break; + default: + mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack source width: %u", sourceWidth); + return; + } + switch (destWidth) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + break; + default: + mLOG(GBA_BIOS, GAME_ERROR, "Bad BitUnPack destination width: %u", destWidth); + return; + } + uint32_t bias = cpu->memory.load32(cpu, info + 4, 0); + uint8_t in = 0; + uint32_t out = 0; + int bitsRemaining = 0; + int bitsEaten = 0; + while (sourceLen > 0) { + if (!bitsRemaining) { + in = cpu->memory.load8(cpu, source, 0); + bitsRemaining = 8; + ++source; + --sourceLen; + } + unsigned scaled = in & ((1 << sourceWidth) - 1); + in >>= sourceWidth; + if (scaled || bias & 0x80000000) { + scaled += bias & 0x7FFFFFFF; + scaled &= (1 << destWidth) - 1; + } + bitsRemaining -= sourceWidth; + out |= scaled << bitsEaten; + bitsEaten += destWidth; + if (bitsEaten == 32) { + cpu->memory.store32(cpu, dest, out, 0); + bitsEaten = 0; + out = 0; + dest += 4; + } + } +}