gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Hot compression action (coder pr0n)

#31159 - Lord Graga - Wed Dec 08, 2004 2:40 pm

Heya. It's a little late, but as the chosen of the compo will be working a bit more to polish their games anyway, I would like to share this public domain compression function, by my good mate Mr. Spiv, for GBA with you:

Code:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@  >>> Decompressor for FXP3 algorithm (c) 2004 Jouni 'Mr.Spiv' Korhonen <<<
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Version:
@  v0.1 07-Sep-2004 JiK - initial release version for gcc
@
@
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ This file is released into the public domain for commercial
@ or non-commercial usage with no restrictions placed upon it.
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

      .section   .iwram,"ax",%progbits
      .TEXT

      .equ   SIZE_PRETABLE,   (8 + 16*8 + 16*4)
      .equ   M_POS,         SIZE_PRETABLE
      .equ   SIZE_LTMTABLE,   16+(8 + 16*8 + 512*4)
      .equ   SIZE_HGHTABLE,   16+(8 + 16*8 + 256*4)+8
      .equ   SIZE_LOWTABLE,   16+(8 + 16*8 + 256*4)
      .equ   M_SIZE,         16
      .equ   SIZE_STACK,      0x1300

      @
      @
      @

      .GLOBAL     decrunch3
        .ALIGN
        .CODE 32

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Parameters:
@  r0 - src i.e. a ptr to the compressed data. Must be 16bits aligned.
@  r1 - dst i.e. a ptr to the destination memory.
@
@ Returns:
@  none
@
@ Notes:
@  The routine does not check if source and destination memory areas
@  overlap. In such case a crash is very probable.
@  Runtime memory usage is 0x1300 bytes of stack space!
@
@ Prototype:
@  void decrunch3( void *src, void *dst );
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

decrunch3:
      stmdb   sp!,{r4-r12,lr}
      add      r12,r0,#12
      mov      r9,r1

      @ r12 - 4 = ptr to crunched data (ID already skipped)
      @ r9 = ptr to destination mem

      sub      sp,sp,#SIZE_STACK      @ space for huffman trees
      mov      r10,#16

      @
      @ Start of the block loop.. visited every 32K..
      @

blockLoop:
      cmp      r10,#16
      subeq   r12,r12,#4
      subne   r12,r12,#2
      ldrh   r8,[r12],#2      @ compressed size of block

      @ r8 = compressed block size, 0x0000 means EOF
      cmp      r8,#0
      addeq   sp,sp,#SIZE_STACK
      ldmeqia   sp!,{r4-r12,pc}      @ EOF

      @ Initialize the bitshifter
      ldrh   r11,[r12],#2
      mov      r10,#16
      ldrh   r1,[r12],#2
      orr      r11,r1,r11,lsl #16

      @
      @ r12 = b (r11 = _bb, r10 = _bc)
      @
      @ Build trees.. r2-r7 are free for use

decodeTrees:
      mov      r2,#8<<16
      mov      r3,#16
      mov      r4,sp
      bl      prepareDecodingStructure

      @ read in depths

      add      r6,sp,#16*8+4
0:      mov      r1,#3      
      rsb      r0,r1,#32            @ moved from getB()
      bl      getB
      orr      r1,r5,r0,lsl #16
      str      r1,[r6],#4
      add      r5,r5,#1
      cmp      r5,r3
      blo      0b

      @ build tree..
      @  r3 = num symbols = 16
      @  r4 = ptr to decoding structure..

      bl      buildDecodingTree   @ PRETREE

      @ init MTF table M

      mov      r0,#15
      add      r7,sp,#M_POS
1:      strb   r0,[r7,r0]
      subs   r0,r0,#1
      bpl      1b

      @ decoding structure for real decoding huffman..
      @ r7 = ptr to M

      mov      r2,#16<<16
      mov      r3,#512               @ Literals and matches
      add      r4,sp,#SIZE_PRETABLE+M_SIZE
      bl      prepareDecodingStructure
      bl      buildDecodingTree2      @ DECTREE

      mov      r3,#256               @ high offset
      add      r4,sp,#SIZE_PRETABLE+SIZE_LTMTABLE+M_SIZE
      bl      prepareDecodingStructure
      bl      buildDecodingTree2      @ DECTREE

                              @ low offset
      add      r4,sp,#SIZE_PRETABLE+SIZE_LTMTABLE+SIZE_HGHTABLE+M_SIZE
      bl      prepareDecodingStructure
      bl      buildDecodingTree2      @ DECTREE

      @
      @ r5 = oldLength (PMR)      no init required
      @ r6 = oldOffset (PMR)      no init required
      @ r7 = oldOffsetLong (PMR)  no init required
      @
      @ r9  = dest
      @ r0,r1,r8 are general trash registers (functions..)
      @ r10,r11,r12 are reserved for bit input
      @

mainLoop:
      add      r2,sp,#SIZE_PRETABLE+M_SIZE
      bl      getSyml
      subs   r3,r2,#256
decodeLiteral:
      bmi      copyLiteral
      beq      blockLoop
      subs   r3,r3,#1
      moveq   r3,r5
      moveq   r4,r6
      beq      copyLoop
decodeMatch:
      @ r3 = match_length-1
      mov      r5,r3            @ PMR oldLength
decodeOffset:
      add      r2,sp,#SIZE_PRETABLE+SIZE_LTMTABLE+M_SIZE
      bl      getSyml
      cmp      r2,#0
      moveq   r4,r7
      beq      oldOffsetLong
      and      r4,r2,#0x7f
      cmp      r4,r2

      addne   r2,sp,#SIZE_PRETABLE+SIZE_LTMTABLE+SIZE_HGHTABLE+M_SIZE
      blne   getSyml
      orrne   r4,r2,r4,lsl #8
      movne   r7,r4            @ PMR oldOffsetLong
oldOffsetLong:
      mov      r6,r4            @ PMR oldOffset
copyLoop:
      ldrb   r2,[r9,-r4]
      subs   r3,r3,#1
copyLiteral:
      strb   r2,[r9],#1
      bpl      copyLoop
      b      mainLoop

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Description:
@  This function decodes the next symbol from the given huffman tree.
@
@ Parameters:
@  r2 = ptr to (huffman)tables..
@
@ Returns:
@  r0 = bits encoding the symbol..
@  r1 = cnt (num bits needed for symbol..)
@  r2 = symbol
@
@ Trashes:
@  r0,r1,r2,r8
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

getSyml:
      add      r8,r2,#16*8+4
0:      ldr      r1,[r2],#8      @ _tbl->cde
      cmp      r11,r1
      bhi      0b

1:      ldrh   r1,[r2,#-2]      @ cnt = _tbl->bts
      ldrh   r2,[r2,#-4]      @ _tbl->ind
      rsb      r0,r1,#32
      rsb      r2,r2,r11,lsr r0
      ldr      r2,[r8,r2,lsl #2]

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Description:
@  This function extracts n bits from the compressed data stream and
@  returns them.
@
@ Parameters:
@  r0 = 32-num_bits_to_extract
@  r1 = num_bits_to_extract
@
@ Returns:
@  r0 = extracted bits
@
@ Trashes:
@  flags,r1
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

getB:   @rsb      r0,r1,#32
      subs   r10,r10,r1
      mov      r0,r11,lsr r0
      mov      r11,r11,lsl r1
      @
      ldrleh   r1,[r12],#2
      rsble   r10,r10,#0
      orrle   r11,r11,r1,lsl r10
      rsbles   r10,r10,#16
      mov      pc,lr

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Description:
@  Prepares huffman trees and decoding structures.
@
@ Parameters:
@  r2 = (_maxCodeLength+1) << 16
@  r3 = num symbols
@  r4 = dest i.e. ptr to the tree to be initialized.
@
@ Returns:
@  r5 = 0
@
@ Trashes:
@  r1,r2
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

prepareDecodingStructure:
      add      r1,r4,#16*8+4

      @ insert endmark to _alp..

      str      r2,[r1,r3,lsl #2]

      @ Prepare for _alp..

      mov      r5,#0
      str      r5,[r1,#-4]         @ note! no +4
      mov      pc,lr

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Description:
@  Build huffman tree & decoding structures. This function also reads symbols
@  from the comppressed stream and then does inverse MTF (move to front) to
@  symbols. This function is only used to decode/build the pretree.
@
@ Parameters:
@  r3 = num symbold
@  r4 = dest
@  sp = ptr to PRETREE
@
@ Returns:
@  None.
@
@ Trashes:
@  r0,r1,r4,r5,r6,r7
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

buildDecodingTree2:
      stmdb   sp!,{r2,lr}
      mov      r5,#0
      add      r6,r4,#16*8+4
1:      add      r2,sp,#8         @ pretable.. skip r2,r4,lr in stack
      bl      getSyml

      @ inverse MTF
                           @ j = M[i];
      mov      r0,r2
      ldrb   r2,[r7,r2]         @ M[i] = T[j];
      add      r7,r7,r0
2:      cmp      r0,#0            @ while (j > 0)
      ldrgtb   r1,[r7,#-1]         @   tmp = T[j - 1];
      subgt   r0,r0,#1         @   j--;
      strgtb   r1,[r7],#-1         @   T[j+1] = tmp;
      bgt      2b

      strb   r2,[r7]            @ T[0] = M[i];

      @
      
      orr      r0,r5,r2,lsl #16
      str      r0,[r6,r5,lsl #2]
      add      r5,r5,#1
      cmp      r5,r3
      blo      1b
      ldmia   sp!,{r2,lr}

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@
@ Description:
@  Build huffman tree & decoding structures. This function assumes that all
@  symbols are already loaded into memory.
@
@ Parameters:
@  r3 = num symbold
@  r4 = dest
@
@ Returns:
@  None.
@
@ Trashes:
@  r0,r1,r5,r6,r7
@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

buildDecodingTree:
      stmdb   sp!,{r2-r4,r7,lr}
      mov      r5,#0      @ i
      add      r2,r4,#16*8+4

inplaceShellsort:
      ldr      r0,[r2,r5,lsl #2]   @ r0 = (i | (depth << 16)
      add      r6,r2,r5,lsl #2
0:      ldr      r1,[r6,#-4]!      @ r1 = (i | (depth << 16)
      cmp      r1,r0
      strhi   r1,[r6,#4]
      bhi      0b
      str      r0,[r6,#4]
      add      r5,r5,#1
      cmp      r5,r3
      blo      inplaceShellsort

      @ Find _start.. i.e. find the first symbol with
      @ nonzero weight.
      @
      @ r2 = start of symbols

      mov      r5,#0
2:      cmp      r5,r3
      ldmhsia   sp!,{r2-r4,r7,pc}
      ldr      r1,[r2,r5,lsl #2]
      movs   r1,r1,lsr #16
      addeq   r5,r5,#1
      beq      2b

      @ move rest so that n will always be 0 at the beginning..
      
      mov      r6,#0
      sub      r3,r3,r5
3:      ldr      r1,[r2,r5,lsl #2]
      add      r5,r5,#1
      str      r1,[r2,r6,lsl #2]
      add      r6,r6,#1
      cmp      r6,r3
      bls      3b

calculateCanonicalCodes:

      mov      r5,#0
      mov      r6,#0
      mvn      r7,#0

      @ r2 = _alp+_start
      @ r3 = _alpsize
      @ r4 = _tlb
      @ r5 = n
      @ r6 = c = 0
      @ r7 = 0xffffffff

0:      ldrh   r0,[r2,#2]
      ldrh   r1,[r2,#6]
      subs   r1,r1,r0   @ if (r0 < r1) ??
      ble      1f

      mov      lr,r7,lsr r0
      orr      lr,lr,r6, ror r0   
      str      lr,[r4],#4      @ cde
      sub      lr,r6,r5      @ ind = (unsigned short)(c-n)
      strh   lr,[r4],#2      @ ind
      strh   r0,[r4],#2      @ bts

1:      add      r6,r6,#1
      movgt   r6,r6,lsl r1
      add      r5,r5,#1
      ldr      r0,[r2],#4
      cmp      r5,r3         @ for ( ; n < _alpsize; n++)..
      and      r0,r0,r7,lsr #16
      str      r0,[r2,#-4]
      blo      0b
      ldmia   sp!,{r2-r4,r7,pc}


Here is the compresor, it is called b2fxec: http://www.cs.helsinki.fi/u/jikorhon/condev/gp32/

Compress data like this:

Code:
b2fxec -d input.data output.fxe



If you are working with *VERY* limited space (say, a 4k intro) you may want to use LZ77 and then huffmann compression instead, since this function is somewhat big (around 630 bytes I believe). It's not as fast as LZ77, but it's even more sexy.


Last edited by Lord Graga on Wed Dec 08, 2004 7:42 pm; edited 1 time in total

#31176 - tepples - Wed Dec 08, 2004 5:59 pm

I'm not familiar with "FXP3", and Google didn't seem helpful. Is there a publicly available compressor?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#31187 - Lord Graga - Wed Dec 08, 2004 7:40 pm

tepples wrote:
I'm not familiar with "FXP3", and Google didn't seem helpful. Is there a publicly available compressor?


Ah, right! I forgot the damn compressor! ;P

Here you go: http://www.cs.helsinki.fi/u/jikorhon/condev/gp32/

#31189 - Lord Graga - Wed Dec 08, 2004 7:41 pm

tepples wrote:
I'm not familiar with "FXP3", and Google didn't seem helpful. Is there a publicly available compressor?


Ah, right! I forgot the damn compressor! ;P

Here you go. It is called b2fxec: http://www.cs.helsinki.fi/u/jikorhon/condev/gp32/

Compress data like this:

Code:
b2fxec -d input.data output.fxe

#31190 - Miked0801 - Wed Dec 08, 2004 7:47 pm

Or go download the ARM PUCrunch compressor/decompressor for really strong, but slow decompression.

#31209 - bertsnks - Wed Dec 08, 2004 9:58 pm

Is this compressor even close to compressing data better than PUcrunch or RNC2?

#31214 - Lord Graga - Wed Dec 08, 2004 10:32 pm

It beats RNC2 by several percents. I did a test on a 1.180.244 byte large file, and b2fxec got it down at 383.312 byte, while RNC2 got it down at 439.552 byte, taking a *LOT* longer time to compress it.

c64pack hangs at this machine, but I would be surprised if it was any better.

#31270 - FluBBa - Thu Dec 09, 2004 1:04 pm

Is this somewhat like his old StoneCruncher for the Amiga?
Oh, and doesn't the compressor output a GP32 exe file?
_________________
I probably suck, my not is a programmer.

#31296 - Lord Graga - Thu Dec 09, 2004 6:51 pm

FluBBa wrote:
Is this somewhat like his old StoneCruncher for the Amiga?
Oh, and doesn't the compressor output a GP32 exe file?


Not if you use -d.

#31301 - tepples - Thu Dec 09, 2004 8:00 pm

What's the approximate decompression rate in kilobytes of decompressed data per second on a 16.78 MHz ARM7TDMI?

And is the source code for b2fxec available?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#31304 - Lord Graga - Thu Dec 09, 2004 9:18 pm

tepples wrote:
What's the approximate decompression rate in kilobytes of decompressed data per second on a 16.78 MHz ARM7TDMI?

And is the source code for b2fxec available?
The decompression is pretty fast. Unpacking ~128 kbyte of data will take less than ?second, but I must admit never to have checked this.

I am sure that the source code is avaible if you ask Mr. Spiv nicely.