Merge branch 'peterferrie-master'

This commit is contained in:
Andy McFadden 2015-08-14 17:11:02 -07:00
commit 9221ef09d1
3 changed files with 340 additions and 77 deletions

View File

@ -2,7 +2,10 @@
* *
* LZ4FH uncompression for 6502 *
* By Andy McFadden *
* Version 1.0, August 2015 *
* Version 1.0.1, August 2015 *
* *
* Refactored for size & speed *
* by Peter Ferrie. *
* *
* Developed with Merlin-16 *
* *
@ -59,13 +62,54 @@ entry
lda (srcptr),y
cmp #lz4fh_magic ;does magic match?
beq goodmagic
jmp fail
fail
jsr bell
jmp monitor
* These stubs increment the high byte and then jump
* back. This saves a cycle because branch-not-taken
* becomes the common case. We assume that we're not
* unpacking data at $FFxx, so BNE is branch-always.
hi2
inc srcptr+1
bne nohi2
hi3
inc srcptr+1
clc
bcc nohi3
hi4
inc dstptr+1
bne nohi4
notempty
cmp #tok_eod
bne fail
rts ;success!
* handle "special" match values (value in A)
specialmatch
cmp #tok_empty
bne notempty
tya ;empty match, advance srcptr
adc srcptr ; past and jump to main loop
sta srcptr
bcc mainloop
inc srcptr+1
bne mainloop
hi5
inc srcptr+1
clc
bcc nohi5
goodmagic
inc srcptr
bne :nohi
bne mainloop
inc srcptr+1
:nohi
mainloop
* Get the mixed-length byte and handle the literal.
@ -77,16 +121,14 @@ mainloop
lsr A
lsr A
beq noliteral
cmp #$0f
cmp #$0f ;sets carry for >= 15
bne shortlit
inc srcptr
bne :nohi
inc srcptr+1
:nohi
beq hi2
nohi2
lda (srcptr),y ;get length extension
clc
adc #15 ;add 15 - will not exceed 255
adc #14 ;(carry set) add 15 - will not exceed 255
* At this point, srcptr holds the address of the "mix"
* word or the length extension, and dstptr holds the
@ -98,7 +140,7 @@ mainloop
* We could save a couple of cycles by substituting
* addr,y in place of (dp),y, but the added setup cost
* would only benefit longer literal strings.
shortlit sta savlen
shortlit tax
tay
:litloop
lda (srcptr),y ;5
@ -107,21 +149,18 @@ shortlit sta savlen
bne :litloop ;3 -> 16 cycles/byte
* Advance srcptr by savlen+1, and dstptr by savlen
lda srcptr
txa
sec ;this gets us the +1
adc savlen
adc srcptr
sta srcptr
bcc :nohi
inc srcptr+1
clc
:nohi
lda dstptr
adc savlen
bcs hi3
nohi3 ;carry cleared by hi3
txa
adc dstptr
sta dstptr
bcc :nohi1
inc dstptr+1
:nohi1
ldy #$ff ;next INY rolls back to zero
bcs hi4
nohi4
dey ;Y=0; DEY so next INY goes to 0
* Handle match. Y holds an offset into srcptr such
* that we need to increment it once to get the next
@ -155,13 +194,13 @@ _desthi ora #$00 ;OR in hi-res page
* remember how many bytes it took to encode. Y is
* indexing the last value used, so we want to go
* advance srcptr by Y+1.
tya
sec
adc srcptr
sta srcptr
bcc :nohi
inc srcptr+1
:nohi
bcs hi5
nohi5 ;hi5 clears carry
* Copy the match. The length is in X. Note this
* must be a forward copy so overlapped data works.
@ -180,46 +219,24 @@ _desthi ora #$00 ;OR in hi-res page
* advance dstptr past copied data
lda dstptr
clc
adc savlen
adc savlen ;carry is clear
sta dstptr
bcc :nohi1
bcc mainloop
inc dstptr+1
:nohi1
DO overrun_check
LDA dstptr+1
CMP #$60
BLT :OKAY
bcc mainloop
BRK
BRK
:OKAY
jmp mainloop
ELSE
bne mainloop ;branch always
bne mainloop ;always (not unpacking at $FFxx)
FIN
* handle "special" match values (value in A)
specialmatch
cmp #tok_empty
bne :notempty
tya ;empty match, advance srcptr
adc srcptr ; past and jump to main loop
sta srcptr
bcc :nohi
inc srcptr+1
clc
:nohi
jmp mainloop
:notempty
cmp #tok_eod
bne fail
rts ;success!
fail
jsr bell
jmp monitor
lst on
sav LZ4FH6502
lst off

240
LZ4FH6502.SMA.S Normal file
View File

@ -0,0 +1,240 @@
********************************
* *
* LZ4FH uncompression for 6502 *
* By Andy McFadden *
* Version 1.0.1, August 2015 *
* *
* Refactored for size & speed *
* by Peter Ferrie. (This *
* version favors code size.) *
* *
* Developed with Merlin-16 *
* *
********************************
lst off
org $0300
*
* Constants
*
lz4fh_magic equ $66 ;ascii 'f'
tok_empty equ 253
tok_eod equ 254
overrun_check equ 0
*
* Variable storage
*
srcptr equ $3c ;2b a1l
dstptr equ $3e ;2b a1h
copyptr equ $00 ;2b
savmix equ $02 ;1b
savlen equ $03 ;1b
savsrc equ $04 ;1b
*
* ROM routines
*
bell equ $ff3a
monitor equ $ff69
*
* Parameters, stashed at the top of the text input
* buffer. We use this, rather than just having them
* poked directly into the code, so that the 6502 and
* 65816 implementations work the same way without
* either getting weird.
*
in_src equ $2fc ;2b
in_dst equ $2fe ;2b
entry
lda in_src ;copy source address to zero page
sta srcptr
lda in_src+1
sta srcptr+1
lda in_dst ;copy destination address to zero page
sta dstptr
lda in_dst+1
sta dstptr+1
sta _desthi+1
ldy #$00
lda (srcptr),y
cmp #lz4fh_magic ;does magic match?
beq goodmagic
fail
jsr bell
jmp monitor
* These stubs increment the high byte and then jump
* back. This saves a cycle because branch-not-taken
* becomes the common case. We assume that we're not
* unpacking data at $ffxx, so BNE is branch-always.
hi2
inc srcptr+1
bne nohi2
hi3
inc srcptr+1
clc
bcc nohi3
hi4
inc dstptr+1
bne nohi4
notempty
cmp #tok_eod
bne fail
rts ;success!
* handle "special" match values (value in A)
specialmatch
cmp #tok_empty
bne notempty
advsrc1
sec
advsrc2
tya ;empty match, advance srcptr
adc srcptr ; past and jump to main loop
sta srcptr
bcc mainloop
inc srcptr+1
bne mainloop
goodmagic
inc srcptr
bne mainloop
inc srcptr+1
mainloop
* Get the mixed-length byte and handle the literal.
ldy #$00
lda (srcptr),y ;get mixed-length byte
sta savmix
lsr A ;get the literal length
lsr A
lsr A
lsr A
beq noliteral
cmp #$0f ;sets carry for >= 15
bne shortlit
inc srcptr
beq hi2
nohi2
lda (srcptr),y ;get length extension
adc #14 ;(carry set) add 15 - will not exceed 255
* At this point, srcptr holds the address of the "mix"
* word or the length extension, and dstptr holds the
* address of the next output location. So we want to
* read from (srcptr),y+1 and write to (dstptr),y.
* We can do this by sticking the DEY between the LDA
* and STA.
*
* We could save a couple of cycles by substituting
* addr,y in place of (dp),y, but the added setup cost
* would only benefit longer literal strings.
shortlit tax
tay
:litloop
lda (srcptr),y ;5
dey ;2 if len is 255, copy 0-254
sta (dstptr),y ;6
bne :litloop ;3 -> 16 cycles/byte
* Advance srcptr by savlen+1, and dstptr by savlen
txa
sec ;this gets us the +1
adc srcptr
sta srcptr
bcs hi3
nohi3
txa
adc dstptr
sta dstptr
bcs hi4
nohi4
dey ;Y=0; DEY so next INY goes to 0
* Handle match. Y holds an offset into srcptr such
* that we need to increment it once to get the next
* interesting byte.
noliteral
lda savmix
and #$0f
cmp #$0f
blt :shortmatch ;BCC
iny
lda (srcptr),y ;get length extension
cmp #237 ;"normal" values are 0-236
bge specialmatch ;BCS
adc #15 ;will not exceed 255
* Put the destination address into copyptr.
:shortmatch
adc #4 ;min match; won't exceed 255
sta savlen ;save match len for later
tax ;and keep it in X
iny
lda (srcptr),y ;match offset, lo
sta copyptr
iny
lda (srcptr),y ;match offset, hi
_desthi ora #$00 ;OR in hi-res page
sta copyptr+1
* Advance srcptr past the encoded match while we still
* remember how many bytes it took to encode. Y is
* indexing the last value used, so we want to go
* advance srcptr by Y+1.
sty savsrc
* Copy the match. The length is in X. Note this
* must be a forward copy so overlapped data works.
*
* We know the match is at least 4 bytes long, so
* we could save a few cycles by not doing the
* ADC #4 earlier, and unrolling the first 4
* load/store operations here.
ldy #$00
:copyloop
lda (copyptr),y ;5
sta (dstptr),y ;6
iny ;2
dex ;2
bne :copyloop ;3 -> 18 cycles/byte
* advance dstptr past copied data
lda dstptr
adc savlen ;carry should still be clear
sta dstptr
ldy savsrc
linkadv
bcc advsrc1
inc dstptr+1
DO overrun_check
LDA dstptr+1
CMP #$60
bcc linkadv
BRK
BRK
ELSE
bne advsrc2
FIN
lst on
sav LZ4FH6502
lst off

View File

@ -2,7 +2,10 @@
* *
* LZ4FH uncompression for 65816 *
* By Andy McFadden *
* Version 1.0, August 2015 *
* Version 1.0.1, August 2015 *
* *
* Refactored for size & speed *
* by Peter Ferrie. *
* *
* Developed with Merlin-16 *
* *
@ -55,7 +58,27 @@ entry
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
@ -73,8 +96,7 @@ mainloop
lda $0000,x ;length >= 15, get next
inx
and #$00ff
clc
adc #15
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
@ -115,22 +137,6 @@ _dstmod ora #$ff00 ;OR in hi-res page
plx ;restore srcptr
bra mainloop
* handle "special" match length values (in A)
specialmatch
cmp #tok_empty
beq mainloop ;empty match, just loop
cmp #tok_eod
bne fail
* exit
sec ;return to emulation mode
xce
rts
fail
sec
xce
jsr bell
jmp monitor
lst on
sav LZ4FH65816
lst off