; ; Lauri Kasanen, 6 Jun 2017 ; (C) Mega Cat Studios ; An optimized LZ4 decompressor ; .importzp sp, sreg, regsave, regbank .importzp tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4 .macpack longbranch .import memcpy_upwards,pushax,popax .export _decompress_lz4 _out = regsave _written = regsave + 2 _tmp = tmp1 _token = tmp2 _offset = ptr3 _in = sreg _outlen = ptr4 ; --------------------------------------------------------------- ; void decompress_lz4 (const u8 *in, u8 * const out, const u16 outlen) ; --------------------------------------------------------------- .segment "CODE" .proc _decompress_lz4: near sta _outlen stx _outlen+1 jsr popax sta _out stx _out+1 jsr popax sta _in stx _in+1 ; ; written = 0; ; lda #$00 sta _written ; ; while (written < outlen) { ; jmp L0046 ; ; token = *in++; ; L0004: ldy #0 lda (_in),y sta _token inc _in bne L000A inc _in+1 L000A: ; ; offset = token >> 4; ; ldx #$00 lsr a lsr a lsr a lsr a sta _offset stx _offset+1 ; ; token &= 0xf; ; token += 4; // Minmatch ; lda _token and #$0F clc adc #4 sta _token ; ; if (offset == 15) { ; lda _offset cmp #$0F L0013: bne L001A ; ; tmp = *in++; ; ldy #0 lda (_in),y sta _tmp inc _in bne L0017 inc _in+1 L0017: ; ; offset += tmp; ; clc adc _offset sta _offset lda #$00 adc _offset+1 sta _offset+1 ; ; if (tmp == 255) ; lda _tmp cmp #$FF ; ; goto moreliterals; ; jmp L0013 ; ; if (offset) { ; L001A: lda _offset ora _offset+1 beq L001C ; ; memcpy(&out[written], in, offset); ; lda _out clc adc _written sta ptr2 lda _out+1 adc _written+1 tax lda ptr2 stx ptr2+1 jsr pushax lda _in ldx _in+1 sta ptr1 stx ptr1+1 ldy #0 jsr memcpy_upwards ; ; written += offset; ; lda _offset clc adc _written sta _written lda _offset+1 adc _written+1 sta _written+1 ; ; in += offset; ; lda _offset clc adc _in sta _in lda _offset+1 adc _in+1 sta _in+1 ; ; if (written >= outlen) ; L001C: lda _written cmp _outlen lda _written+1 sbc _outlen+1 ; ; return; ; bcc L0047 rts ; ; memcpy(&offset, in, 2); ; L0047: ldy #0 lda (_in),y sta _offset iny lda (_in),y sta _offset+1 ; ; in += 2; ; lda #$02 clc adc _in sta _in bcc L002F inc _in+1 ; ; copysrc = out + written - offset; ; L002F: lda _out clc adc _written pha lda _out+1 adc _written+1 tax pla sec sbc _offset sta ptr1 txa sbc _offset+1 sta ptr1+1 ; ; offset = token; ; lda #$00 sta _offset+1 lda _token sta _offset ; ; if (token == 19) { ; cmp #$13 L0045: bne L003C ; ; tmp = *in++; ; ldy #0 lda (_in),y sta _tmp inc _in bne L0039 inc _in+1 L0039: ; ; offset += tmp; ; clc adc _offset sta _offset tya adc _offset+1 sta _offset+1 ; ; if (tmp == 255) ; lda _tmp cmp #$FF ; ; goto morematches; ; jmp L0045 ; ; memcpy(&out[written], copysrc, offset); ; L003C: lda _out clc adc _written sta ptr2 lda _out+1 adc _written+1 tax lda ptr2 stx ptr2+1 jsr pushax jsr memcpy_upwards ; ; written += offset; ; lda _offset clc adc _written sta _written lda _offset+1 adc _written+1 L0046: sta _written+1 ; ; while (written < outlen) { ; lda _written cmp _outlen lda _written+1 sbc _outlen+1 jcc L0004 rts .endproc