! LZSS decoder for SEGA 32X ! /Mic, 2009 .section .text .align 1 .global _lzss_decode ! In: r4 = compressed data, r5 = compressed size, r6 = destination ! _lzss_decode: mov.l r8,@-r15 mov.l r9,@-r15 mov.l r10,@-r15 mov.l r11,@-r15 mov.l r12,@-r15 mov.l r13,@-r15 mov.l r14,@-r15 mov.l text_buf,r3 mov #0,r1 mov.w N_minus_F,r0 mov r0,r7 _init_text_buf: ! Set all bytes in text_buf to 0x00 add #-1,r0 mov.b r1,@(r0,r3) cmp/pl r0 bt _init_text_buf mov.w buf_pos_mask,r9 mov.l text_buf,r11 mov #0,r3 ! Input stream position mov #0,r13 ! Hi/lo byte counter mov #0,r14 _lzss_loop: cmp/hs r5,r3 bt _lzss_done mov r4,r0 mov.b @(r0,r3),r8 ! The first byte of each block contains the flags mov #8,r10 ! 8 flags in one byte add #1,r3 _check_flags: shlr r8 ! Shift the next flag into T bf _flag_clear cmp/hs r5,r3 ! Make sure we're not beyond the last byte of the input stream bt _lzss_done mov r4,r0 mov.b @(r0,r3),r1 mov r11,r0 add #1,r3 bra _output_byte mov #1,r2 ! Make sure the bf after _output_byte isn't taken _flag_clear: cmp/hs r5,r3 bt _lzss_done mov r4,r0 mov.b @(r0,r3),r2 ! idx extu.b r2,r2 add #1,r3 mov.b @(r0,r3),r1 ! j add #1,r3 extu.b r1,r12 shlr2 r12 shlr2 r12 shll8 r12 ! r12 = (j & 0xf0) << 4 or r2,r12 ! r12 = ((j & 0xf0) << 4) | idx mov #15,r2 and r1,r2 mov r11,r0 add #3,r2 ! r2 = (j & 0x0f) + THRESHOLD + 1 _copy_string: and r9,r12 mov.b @(r0,r12),r1 add #1,r12 _output_byte: extu.b r1,r1 mov.b r1,@(r0,r7) ! Write to text_buf add #1,r7 tst r13,r13 bt _no_vram_write shll8 r14 or r1,r14 mov.w r14,@r6 ! Write to the output stream bra _wrap_adr add #2,r6 _no_vram_write: extu.b r1,r14 _wrap_adr: and r9,r7 mov #1,r1 xor r1,r13 _next_string_pos: dt r2 bf _copy_string _next_flag: dt r10 bt _lzss_loop bra _check_flags or r0,r0 _lzss_done: mov.l @r15+,r14 mov.l @r15+,r13 mov.l @r15+,r12 mov.l @r15+,r11 mov.l @r15+,r10 mov.l @r15+,r9 mov.l @r15+,r8 rts nop .align 2 text_buf: .long _text_buf N_minus_F: .short 4078 buf_pos_mask: .short 4095 .comm _text_buf,4078,4