********************************* * * * LZ4FH uncompression for 65816 * * By Andy McFadden * * Version 1.0.1, August 2015 * * * * Refactored for size & speed * * by Peter Ferrie. * * * * Developed with Merlin-16 * * * ********************************* lst off org $0300 xc ;allow 65c02 opcodes xc ;allow 65816 opcodes * * Constants * lz4fh_magic equ $66 ;ascii 'f' tok_empty equ 253 tok_eod equ 254 * * Variable storage * savmix equ $00 ;2b savlen equ $02 ;2b * * ROM routines * bell equ $ff3a monitor equ $ff69 * * Parameters. * * in_dst must be $2000 or $4000 * in_src equ $2fc ;2b in_dst equ $2fe ;2b * Main entry point. entry clc ;go native xce rep #$30 ;16-bit acc/index mx %00 ; tell Merlin ldx in_src ldy in_dst sty _dstmod+1 lda $0000,x inx and #$00ff cmp #lz4fh_magic beq mainloop fail jsr bell jmp monitor notempty cmp #tok_eod ;end-of-data or error * exit sec ;return to emulation mode xce bne fail rts mx %00 ;undo the sec/xce * handle "special" match length values (in A) specialmatch cmp #tok_empty bne notempty mainloop lda $0000,x inx sta savmix and #$00f0 beq noliteral lsr A lsr A lsr A lsr A cmp #$000f bne shortlit lda $0000,x ;length >= 15, get next inx and #$00ff adc #14 ;(carry set) +15 - won't exceed 255 * At this point, Y holds the address of the next * compressed data byte, X has the address of the * next output position, and A has the length of * the literal. * * The MVN instruction moves (A+1) bytes from X * to Y, advancing X and Y. shortlit dec A ;MVN wants length-1 mvn $00,$00 ;7 cycles/byte * Now handle the match. noliteral lda savmix and #$000f cmp #$000f blt :shortmatch ;BCC lda $0000,x ;add length extension inx and #$00ff cmp #237 ;"normal" values are 0-236 bge specialmatch adc #15 ;carry clear; won't exceed 255 :shortmatch adc #3 ;min match, -1 for MVN sta savlen ;spill A while we get offset lda $0000,x ;load source buffer offset inx inx phx ;save srcptr for later _dstmod ora #$ff00 ;OR in hi-res page tax lda savlen mvn $00,$00 plx ;restore srcptr bra mainloop lst on sav LZ4FH65816 lst off