;;;LZ77UnCompWram;;; ; r0: Source ; r1: Destination 000010FC push r4-r6,r14 00001100 ldr r5,[r0],4h 00001104 mov r2,r5,lsr 8h 00001108 movs r12,r2 0000110C bl 0BA4h 00000BA4 cmp r12,0h 00000BA8 beq + 00000BAC bic r12,r12,0FE000000h 00000BB0 add r12,r0,r12 00000BB4 tst r0,0E000000h 00000BB8 tstne r12,0E000000h + 00000BBC bx r14 00001110 beq BRANCH_RETURN BRANCH_A: 00001114 cmp r2,0h 00001118 ble BRANCH_RETURN 0000111C ldrb r14,[r0],1h 00001120 mov r4,8h BRANCH_B: 00001124 subs r4,r4,1h 00001128 blt BRANCH_A 0000112C tst r14,80h 00001130 bne BRANCH_C 00001134 ldrb r6,[r0],1h 00001138 strb r6,[r1],1h 0000113C sub r2,r2,1h 00001140 b BRANCH_E BRANCH_C: 00001144 ldrb r5,[r0] 00001148 mov r6,3h 0000114C add r3,r6,r5,asr 4h 00001150 ldrb r6,[r0],1h 00001154 and r5,r6,0Fh 00001158 mov r12,r5,lsl 8h 0000115C ldrb r6,[r0],1h 00001160 orr r5,r6,r12 00001164 add r12,r5,1h 00001168 sub r2,r2,r3 BRANCH_D: 0000116C ldrb r5,[r1,-r12] 00001170 strb r5,[r1],1h 00001174 subs r3,r3,1h 00001178 bgt BRANCH_D BRANCH_E: 0000117C cmp r2,0h 00001180 movgt r14,r14,lsl 1h 00001184 bgt BRANCH_B 00001188 b BRANCH_A BRANCH_RETURN: 0000118C pop r4-r6,r14 00001190 bx r14 ;;;LZ77UnCompVram;;; ; r0: Source ; r1: Destination 00001194 push r4-r10,r14 00001198 mov r3,0h ; Initialise halfword construction 0000119C ldr r8,[r0],4h ;\ 000011A0 mov r10,r8,lsr 8h ;} Size of decompressed data 000011A4 mov r2,0h ; Initialise the MSB/LSB flag 000011A8 movs r12,r10 ;\ 000011AC bl 0BA4h ;} Validity check 00000BA4 cmp r12,0h ;\ 00000BA8 beq + ;} Return if size == 0 00000BAC bic r12,r12,0FE000000h ;\ 00000BB0 add r12,r0,r12 ;} Get end address 00000BB4 tst r0,0E000000h ; Check start address (ROM or VRAM) 00000BB8 tstne r12,0E000000h ; Check end address (ROM or VRAM) + 00000BBC bx r14 000011B0 beq BRANCH_RETURN BRANCH_A: 000011B4 cmp r10,0h ;\ 000011B8 ble BRANCH_RETURN ;} Return if size <= 0 000011BC ldrb r6,[r0],1h ; Load the flags byte 000011C0 mov r7,8h ; Flags left to process BRANCH_B: 000011C4 subs r7,r7,1h ;\ 000011C8 blt BRANCH_A ;} If processed all flags, process next block 000011CC tst r6,80h ;\ 000011D0 bne BRANCH_C ;} If flag is clear, single copy: 000011D4 ldrb r9,[r0],1h ;\ 000011D8 orr r3,r3,r9,lsl r2 ;} Construct little endian halfword with two flag iterations 000011DC sub r10,r10,1h ; Decrement size 000011E0 eors r2,r2,8h ; Set LSB/MSB flag for next iteration 000011E4 streqh r3,[r1],2h ; Write the halfword if fully constructed 000011E8 moveq r3,0h ; Re-initialise the halfword if written 000011EC b BRANCH_E ; Next! BRANCH_C: 000011F0 ldrb r9,[r0] ;\ 000011F4 mov r8,3h ;} Block size + 3 000011F8 add r5,r8,r9,asr 4h ;/ 000011FC ldrb r9,[r0],1h ;\ 00001200 and r8,r9,0Fh ;| 00001204 mov r4,r8,lsl 8h ;| 00001208 ldrb r9,[r0],1h ;} Offset + 1 0000120C orr r8,r9,r4 ;| 00001210 add r4,r8,1h ;/ 00001214 rsb r8,r2,8h ;\ 00001218 and r9,r4,1h ;} If LSB XOR odd-offset, r14 = 8h 0000121C eor r14,r8,r9,lsl 3h ;/ 00001220 sub r10,r10,r5 ; Subtract block size from size BRANCH_D: 00001224 eor r14,r14,8h ; Toggle r14's 8h 00001228 rsb r8,r2,8h ;\ 0000122C add r8,r4,r8,lsr 3h ;| 00001230 mov r8,r8,lsr 1h ;} Halfword-align offset 00001234 mov r8,r8,lsl 1h ;/ 00001238 ldrh r9,[r1,-r8] ; Load halfword [dest-offset] 0000123C mov r8,0FFh ;\ 00001240 and r8,r9,r8,lsl r14 ;} Get the LSB/MSB byte (r14) 00001244 mov r8,r8,asr r14 ;/ 00001248 orr r3,r3,r8,lsl r2 ; Add the byte to the halfword construction 0000124C eors r2,r2,8h ; Set the LSB/MSB flag for the next iteration 00001250 streqh r3,[r1],2h ; Write the halfword if fully constructed 00001254 moveq r3,0h ; Re-initialise the halfword if written 00001258 subs r5,r5,1h ;\ 0000125C bgt BRANCH_D ;} Repeat block size times BRANCH_E: 00001260 cmp r10,0h ;\ 00001264 movgt r6,r6,lsl 1h ;} If size > 0, process next flag 00001268 bgt BRANCH_B ;/ 0000126C b BRANCH_A ; Else return BRANCH_RETURN: 00001270 pop r4-r10,r14 00001274 bx r14 ---------------------------------------------------------------------------------------------- bool LZ77Decompress(Pointer Source, void* indest, word DestLimit) // Decompresses LZ77 encoded data { // Source is a pointer to data in the ROM, Dest is the buffer that will contain the decompressed data byte* Dest((byte*)indest); word size; // The remaining size of the compressed data Source.Return(&size, 4); Source += 4; size >>= 8; // (only the upper 24 bits are the size) if (size > DestLimit) return true; if ((Source.pointer & 0x08000000) == 0 || (Source.pointer+size & 0x08000000) == 0) // Check that start and end are within ROM range return true; while (size > 0) { byte flags; // Flags for next 8 blocks, 0: single copy, 1: block copy, MSB first Source.Return(&flags); ++Source; for (int i(0); i < 8; ++i) { if ((flags & 0x80) == 0) // Single copy { Source.Return(Dest); ++Source; ++Dest; // Copy a single byte --size; // Decrement the Size remaining } else // Block copy: { byte blocksize; // The remaining size of the compressed block halfword offset; // Number of byte backwards from the current Dest to copy data Source.Return(&blocksize); // Number of bytes to copy - 3 blocksize = (blocksize>>4) + 3; // (only upper 4 bits) size -= blocksize; // Decrement Size remaining Source.Return((byte*)(&offset)+1); ++Source; // MSBs; byte pointer cast needed because of pointer arithmetic offset &= 0x0F00; // (only the lower 4 bits of Source byte) Source.Return(&offset); ++Source; // LSBs - 1 ++offset; for (; blocksize > 0; --blocksize) // Copy blocksize bytes from Dest-offset to Dest { *Dest = *(Dest-offset); ++Dest; } } if (size <= 0) break; flags <<= 1; // Onto next block } } return false; }