1
0
mirror of https://github.com/pfusik/zlib6502.git synced 2024-06-08 13:29:27 +00:00

Use less memory. More verbatim labels.

This commit is contained in:
Piotr Fusik 2002-08-06 17:03:06 +02:00
parent 3455fd77a5
commit 3a52942f94

View File

@ -1,386 +1,427 @@
* 'Inflate' lib zpage equ $f0 ; 11 bytes
inflate equ $b600
* 'Inflate'
; Written by Piotr Fusik (a.k.a. Fox/Taquart) ; Written by Piotr Fusik (a.k.a. Fox/Taquart)
; Purpose: to uncompress Deflate format compressed data on 6502-based system. ; Purpose: to uncompress Deflate format compressed data on 6502-based system.
; Source in X-Assembler's format (www.6502.org/users/fox/xasm)
* const * const
; Maximum length of a Huffman code ; Maximum length of a Huffman code
MAX_BITS equ 15 MAX_BITS equ 15
; Index in bitsCount, bitsPointer_l and bitsPointer_h for literal tree ; Index in bitsCount, bitsPointer_l and bitsPointer_h
LITERAL_TREE equ 0 ; for temporary tree and literal/length tree
PRIMARY_TREE equ 0
; Index in bitsCount, bitsPointer_l and bitsPointer_h for distance tree ; Index in bitsCount, bitsPointer_l and bitsPointer_h for distance tree
DISTANCE_TREE equ MAX_BITS DISTANCE_TREE equ MAX_BITS
; Size of each of bitsCount, bitsPointer_l and bitsPointer_h ; Size of each of bitsCount, bitsPointer_l and bitsPointer_h
TREES_SIZE equ 2*MAX_BITS+1 TREES_SIZE equ 2*MAX_BITS
* page zero * page zero
org zpage
; (public) Pointer to compressed data ; (public) Pointer to compressed data
inputPointer org *+2 inputPointer equ zpage ; 2 bytes
; (public) Pointer to uncompressed data ; (public) Pointer to uncompressed data
outputPointer org *+2 outputPointer equ zpage+2 ; 2 bytes
; Buffer for getBit ; Local variables
getBitHold org *+1 getBit_hold equ zpage+10 ; 1 byte
; Local variables. Variables from different routines use same memory.
cnt org *+1 inflateDynamicBlock_cnt equ zpage+4 ; 1 byte
tmp equ * ; 1 byte inflateCodes_src equ zpage+4 ; 2 bytes
ptr org *+2 buildHuffmanTree_src equ zpage+4 ; 2 bytes
len equ * ; 2 bytes getNextLength_last equ zpage+4 ; 1 byte
nl org *+1 getNextLength_index equ zpage+5 ; 1 byte
nd org *+1
src equ * ; 2 bytes buildHuffmanTree_ptr equ zpage+6 ; 2 bytes
dest org *+2 fetchCode_ptr equ zpage+6 ; 2 bytes
getBits_tmp equ zpage+6 ; 1 byte
moveBlock_len equ zpage+8 ; 2 bytes
inflateDynamicBlock_np equ zpage+8 ; 1 byte
inflateDynamicBlock_nd equ zpage+9 ; 1 byte
* code * code
org inflate org inflate
* (public) inflate * (public) inflate
; Decompresses Deflate data pointed by inputPointer ; Decompress Deflate data pointed by inputPointer
; to memory at outputPointer ; to memory at outputPointer
mvy #1 getBitHold mvy #1 getBit_hold
bne inflate_2 !
inflate_1
jsr inflate_3
inflate_2
; Get a bit of EOF and two bits of block type ; Get a bit of EOF and two bits of block type
extr1 ldx #3 ldx #3
lda #0 lda #0
jsr getBits jsr getBits
lsr @ lsr @
tax bcc inflate_1
; X contains block type, C contains EOF flag inflate_3
bcs extr2 bne inflateCompressedBlock
; If not last block, put return address to extr1
lda:pha >extr1-1
lda:pha <extr1-1
; Go to routine decompressing this block
extr2 lda:pha extr_h,x
lda:pha extr_l,x
rts
* inflateCopyBlock * inflateCopyBlock
; Decompresses 'stored' data block ; Decompress 'stored' data block
inflateCopyBlock inflateCopyBlock
; Ignore bits until byte boundary ; Ignore bits until byte boundary
mvy #1 getBitHold mvy #1 getBit_hold
; Get 16-bit length ; Get 16-bit length
mva (inputPointer),y- len+1 ldx #inputPointer
mva (inputPointer),y len mva (0,x) moveBlock_len
; Skip length and one's compliment length mva (inputPointer),y moveBlock_len+1
; Skip length and one's complement length
lda #4 lda #4
add:sta inputPointer add:sta inputPointer
scc:inc inputPointer+1 scc:inc inputPointer+1
ldx #inputPointer
* moveBlock * moveBlock
; Copies block of length len from (0,x) to output ; Copy block of length moveBlock_len from (0,x) to output
moveBlock moveBlock
ldy len ldy moveBlock_len
beq mov1 beq moveBlock_1
ldy #0 ldy #0
inc len+1 inc moveBlock_len+1
mov1 mva (0,x) (outputPointer),y moveBlock_1
mva (0,x) (outputPointer),y
inw 0,x inw 0,x
inw outputPointer inw outputPointer
dec len dec moveBlock_len
bne mov1 bne moveBlock_1
dec len+1 dec moveBlock_len+1
bne mov1 bne moveBlock_1
rts rts
* inflateCompressedBlock
; Decompress Huffman-coded data block
; A = 1: fixed, A = 2: dynamic
inflateCompressedBlock
lsr @
bne inflateDynamicBlock
* inflateFixedBlock * inflateFixedBlock
; Decompresses Huffman-coded data block with default Huffman trees: ; Decompress Huffman-coded data block with default Huffman trees:
; literalCodeLength :144 dta 8 ; literalCodeLength :144 dta 8
; :112 dta 9 ; :112 dta 9
; endCodeLength :24 dta 7 ; endCodeLength :24 dta 7
; :6 dta 8 ; :6 dta 8
; distanceCodeLength :30 dta 5 ; distanceCodeLength :30 dta 5+DISTANCE_TREE
; :2 dta 8 ; codes from literal tree, not used ; :2 dta 8
; (two 8-bit codes from primary tree are not used)
inflateFixedBlock inflateFixedBlock
ldx #159 ldx #159
stx distanceCodeLength+32 stx distanceCodeLength+32
lda #8 lda #8
fixd1 sta literalCodeLength-1,x inflateFixedBlock_1
sta literalCodeLength-1,x
sta literalCodeLength+159-1,x- sta literalCodeLength+159-1,x-
bne fixd1 bne inflateFixedBlock_1
ldx #112 ldx #112
lda #9 inc:rne literalCodeLength+144-1,x-
sta:rne literalCodeLength+144-1,x-
ldx #24 ldx #24
lda #7 dec:rne endCodeLength-1,x-
sta:rne endCodeLength-1,x-
ldx #30 ldx #30
lda #5+DISTANCE_TREE lda #5+DISTANCE_TREE
sta:rne distanceCodeLength-1,x- sta:rne distanceCodeLength-1,x-
jmp inflateCodes beq inflateCodes !
* inflateDynamicBlock * inflateDynamicBlock
; Decompresses Huffman-coded data block, reading Huffman trees first ; Decompress Huffman-coded data block, reading Huffman trees first
inflateDynamicBlock inflateDynamicBlock
; numberOfLiteralCodes = getBits(5) + 257; ; numberOfPrimaryCodes = 257 + getBits(5)
ldx #5 ldx #5
lda <lengthCodeLength-1 ; lda #1
jsr getBits jsr getBits
sta nl sta inflateDynamicBlock_np
; numberOfDistanceCodes = getBits(5) + 1; ; numberOfDistanceCodes = 1 + getBits(5)
ldx #5 ldx #5
lda #1 lda #1+29+1
jsr getBits jsr getBits
sta nd sta inflateDynamicBlock_nd
add:sta nl ; numberOfTemporaryCodes = 4 + getBits(4)
; numberOfTemporaryCodes = getBits(4) + 4;
lda:tax #4 lda:tax #4
jsr getBits jsr getBits
sta cnt sta inflateDynamicBlock_cnt
; Clear lengths of temporary codes (there're 19 temp codes max), ; Get lengths of temporary codes in order stored in tempCodeLengthOrder
; clear literalCodeLength-1 (it may be used by temporary code 16) lda:tay #0
; and leave #0 in Y inflateDynamicBlock_1
ldy #20 ldx #3 ; A = 0
lda #0 jsr getBits ; does not change Y
sta:rne literalCodeLength-2,y- inflateDynamicBlock_2
; Get lengths of temporary codes in order stored in bll ldx tempCodeLengthOrder,y
dyn1 ldx #3
lda #0
; Doesn't change Y
jsr getBits
ldx bll,y
sta literalCodeLength,x sta literalCodeLength,x
lda #0
iny iny
cpy cnt cpy inflateDynamicBlock_cnt
bcc dyn1 bcc inflateDynamicBlock_1
cpy #19
bcc inflateDynamicBlock_2
ror literalCodeLength+19 + ror literalCodeLength+19 +
; Build tree for temporary codes ; Build tree for temporary codes
jsr buildHuffmanTree jsr buildHuffmanTree
; Use temporary codes to get lengths for literal and distance codes ; Use temporary codes to get lengths for literal/length and distance codes
; dest is target-1, so we can access last written byte by (dest,0) ldx #0
lda <literalCodeLength-1
ldy >literalCodeLength-1
dyf1 sta dest
sty dest+1
jsr fetchLiteralCode
; Temporary code 0..15: put this length
ldy #1 ldy #1
cmp #16 stx getNextLength_last
bcc dynst inflateDynamicBlock_3
bne dif1 jsr getNextLength
; Temporary code 16: repeat last length 3..6 times sta literalCodeLength,x+
ldx #2 bne inflateDynamicBlock_3
lda #3 inflateDynamicBlock_4
jsr getBits jsr getNextLength
tay sta endCodeLength,x+
lda (dest,x) ; (dest,0) cpx inflateDynamicBlock_np
jmp dynst bcc inflateDynamicBlock_4
dif1 lsr @
; Temporary code 17: put zero length 3..10 times
lda:tax #3
bcs dynst0
; Temporary code 18: put zero length 11..138 times
ldx #7
lda #11
dynst0 jsr getBits
tay
lda #0 lda #0
; Write A length Y times bcs inflateDynamicBlock_6 !
dynst sty cnt inflateDynamicBlock_5
sta:rne (dest),y- sta endCodeLength,x+
lda dest inflateDynamicBlock_6
ldy dest+1 cpx #1+29
add cnt bcc inflateDynamicBlock_5
scc:iny inflateDynamicBlock_7
cpy >literalCodeLength jsr getNextLength
beq dyf1 cmp #0
cmp nl seq:adc #DISTANCE_TREE-1 +
bne dyf1 sta endCodeLength,x+
; Mark end of distance lengths cpx inflateDynamicBlock_nd
ldx nd bcc inflateDynamicBlock_7
tay ror endCodeLength,x +
ror distanceCodeLength,x +
; Move distance lengths to distanceCodeLength table
dadt dex
lda endCodeLength,y
; Mark existing codes (of non-zero length) as distance tree codes
seq:add #DISTANCE_TREE
sta distanceCodeLength,x
mva #0 endCodeLength,y-
txa
bne dadt
* inflateCodes * inflateCodes
; Decompresses data block basing on given Huffman trees ; Decompress data block basing on given Huffman trees
inflateCodes inflateCodes
jsr buildHuffmanTree jsr buildHuffmanTree
codes1 jsr fetchLiteralCode inflateCodes_1
bcs codes2 jsr fetchPrimaryCode
bcs inflateCodes_2
; Literal code ; Literal code
sta (outputPointer),0 sta (outputPointer),0
inw outputPointer inc outputPointer
jmp codes1 bne inflateCodes_1
inc outputPointer+1
bcc inflateCodes_1 !
; End of block ; End of block
codret rts inflateCodes_ret
codes2 beq codret rts
inflateCodes_2
beq inflateCodes_ret
; Repeat block ; Repeat block
jsr getValue jsr getValue
sta len sta moveBlock_len
tya tya
jsr getBits jsr getBits
sta len+1 sta moveBlock_len+1
ldx #DISTANCE_TREE ldx #DISTANCE_TREE
jsr fetchCode jsr fetchCode
jsr getValue jsr getValue
sta src sec
eor #$ff
adc outputPointer
sta inflateCodes_src
php
tya tya
jsr getBits jsr getBits
sta src+1 plp
lda outputPointer eor #$ff
sub src adc outputPointer+1
sta src sta inflateCodes_src+1
lda outputPointer+1 ldx #inflateCodes_src
sbc src+1
sta src+1
ldx #src
jsr moveBlock jsr moveBlock
jmp codes1 beq inflateCodes_1 !
* buildHuffmanTree * buildHuffmanTree
; Builds Huffman trees basing on code lengths. ; Build Huffman trees basing on code lengths.
; Lengths (in bits) are stored in literalCodeLength. ; Lengths (in bits) are stored in *CodeLength tables.
; A byte with highest bit set marks end of length table. ; A byte with highest bit set marks end of length table.
buildHuffmanTree buildHuffmanTree
mva <literalCodeLength tr2+1 mwa #literalCodeLength buildHuffmanTree_src
sta tr6+1 ; Clear bitsCount and bitsPointer_l
mva >literalCodeLength tr2+2 ldy #2*TREES_SIZE+1
sta tr6+2
; Clear counts
ldx #TREES_SIZE-1
lda #0 lda #0
sta:rpl bitsCount,x- sta:rne bitsCount-1,y-
bmi tr2 ! beq buildHuffmanTree_3 !
; Count number of codes of each length ; Count number of codes of each length
tr1 inc bitsCount,x buildHuffmanTree_2
inw tr2+1 tax
tr2 ldx a:0 inc bitsPointer_l,x
bpl tr1 iny
bne buildHuffmanTree_3
inc buildHuffmanTree_src+1
buildHuffmanTree_3
lda (buildHuffmanTree_src),y
bpl buildHuffmanTree_2
; Calculate pointer for each length ; Calculate pointer for each length
tax #0 ldx #0
stx bitsCount lda #<sortedCodes
lda <sortedCodes ldy #>sortedCodes
ldy >sortedCodes clc
tr3 sta bitsPointer_l,x buildHuffmanTree_4
sta bitsPointer_l,x
tya:sta bitsPointer_h,x tya:sta bitsPointer_h,x
lda bitsCount,x lda bitsPointer_l+1,x
asl @ adc bitsPointer_l,x -
scc:iny
add bitsPointer_l,x
scc:iny scc:iny
inx inx
cpx #TREES_SIZE cpx #TREES_SIZE
bcc tr3 bcc buildHuffmanTree_4
bcs tr6 ! mva #>literalCodeLength buildHuffmanTree_src+1
ldy #0
bcs buildHuffmanTree_9 !
; Put codes into their place in sorted table ; Put codes into their place in sorted table
tr4 beq tr5 buildHuffmanTree_6
mva bitsPointer_l,x ptr beq buildHuffmanTree_7
add #2 tax
sta bitsPointer_l,x mva bitsPointer_l-1,x buildHuffmanTree_ptr
mva bitsPointer_h,x ptr+1 mva bitsPointer_h-1,x buildHuffmanTree_ptr+1
adc #0 tya
sta bitsPointer_h,x ldy:inc bitsCount-1,x
mva tr6+2 (ptr),0+ sta (buildHuffmanTree_ptr),y
mva tr6+1 (ptr),y tay
tr5 inw tr6+1 buildHuffmanTree_7
tr6 ldx a:0 iny
bpl tr4 bne buildHuffmanTree_9
inc buildHuffmanTree_src+1
ldx #MAX_BITS-1
mva:rpl bitsCount,x literalCount,x-
buildHuffmanTree_9
lda (buildHuffmanTree_src),y
bpl buildHuffmanTree_6
rts rts
* fetchLiteralCode * getNextLength
; Reads code basing on literal tree ; Get next code length basing on temporary codes
fetchLiteralCode getNextLength
ldx #LITERAL_TREE stx getNextLength_index
dey
bne getNextLength_1
; Fetch a temporary code
jsr fetchPrimaryCode
; Temporary code 0..15: put this length
ldy #1
cmp #16
bcc getNextLength_2
; Temporary code 16: repeat last length 3 + getBits(2) times
; Temporary code 17: put zero length 3 + getBits(3) times
; Temporary code 18: put zero length 11 + getBits(7) times
tay
ldx tempExtraBits-16,y
lda tempBaseValue-16,y
jsr getBits
cpy #17
tay
lda #0
bcs getNextLength_2
getNextLength_1
lda getNextLength_last
getNextLength_2
sta getNextLength_last
ldx getNextLength_index
rts
* fetchPrimaryCode
; Read code basing on primary tree
fetchPrimaryCode
ldx #PRIMARY_TREE
* fetchCode * fetchCode
; Reads code from input stream basing on tree given in X. ; Read code from input stream basing on tree given in X.
; Returns code in A, C is set if non-literal code. ; Return low byte of code in A.
; For literal/length tree C is set if non-literal code.
fetchCode fetchCode
lda #0 lda #0
fcode1 jsr getBit fetchCode_1
jsr getBit
rol @ rol @
cmp bitsCount+1,x
bcc fcode2
sbc bitsCount+1,x
inx inx
bcs fcode1 ! sub bitsCount-1,x
fcode2 mvy bitsPointer_l,x ptr bcs fetchCode_1
ldy bitsPointer_h,x adc bitsCount-1,x -
asl @ cmp literalCount-1,x
scc:iny sta fetchCode_ptr
sty ptr+1 ldy bitsPointer_l-1,x
tay mva bitsPointer_h-1,x fetchCode_ptr+1
lda (ptr),y+ lda (fetchCode_ptr),y
cmp >endCodeLength
lda (ptr),y
rts rts
* getValue * getValue
; Reads low byte of value (length or distance), basing on code A ; Read low byte of value (length or distance), basing on code A
getValue getValue
tay tay
ldx lengthExtraBits-<lengthCodeLength,y ldx lengthExtraBits-1,y
lda:pha lengthCode_l-<lengthCodeLength,y lda:pha lengthBaseValue_l-1,y
lda:tay lengthCode_h-<lengthCodeLength,y lda:tay lengthBaseValue_h-1,y
pla pla
* getBits * getBits
; Reads X-bit number from input stream and adds it to A. ; Read X-bit number from input stream and add it to A.
; In case of carry, Y is incremented. ; In case of carry, Y is incremented.
; If X > 8, only 8 bits are read. ; If X > 8, only 8 bits are read.
; On return X holds number of unread bits: X = (X > 8 ? X - 8 : 0); ; On return X holds number of unread bits: X = (X > 8 ? X - 8 : 0);
getBits getBits
cpx #0 cpx #0
beq gbitsr beq getBits_ret
pha pha
mva #1 tmp mva #1 getBits_tmp
pla pla
gbits1 jsr getBit getBits_1
bcc gbits2 jsr getBit
add tmp bcc getBits_2
add getBits_tmp
scc:iny scc:iny
gbits2 dex:beq gbitsr getBits_2
asl tmp dex
bcc gbits1 beq getBits_ret
gbitsr rts asl getBits_tmp
bcc getBits_1
getBits_ret
rts
* getBit * getBit
; Reads single bit from input stream, returns it in C flag ; Read single bit from input stream, returns it in C flag
getBit getBit
lsr getBitHold lsr getBit_hold
bne gbitr bne getBit_ret
pha pha
tya:pha tya:pha
lda (inputPointer),0 lda (inputPointer),0
inw inputPointer inw inputPointer
ror @ + ror @ +
sta getBitHold sta getBit_hold
pla:tay pla:tay
pla pla
gbitr rts getBit_ret
rts
* Addresses of functions extracting different blocks * Tables for temporary codes
extr_l dta l(inflateCopyBlock-1,inflateFixedBlock-1,inflateDynamicBlock-1) ; Value is BaseValue + getBits(ExtraBits)
extr_h dta h(inflateCopyBlock-1,inflateFixedBlock-1,inflateDynamicBlock-1)
* Order, in which lengths of temporary codes are stored ; Order, in which lengths of temporary codes are stored
bll dta b(16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15) tempCodeLengthOrder
dta b(16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15)
; Base values
tempBaseValue
dta b(3,3,11)
; Number of extra bits to read
tempExtraBits
dta b(2,3,7)
* Tables for length and distance codes * Tables for length and distance codes
; Value is Code + getBits(ExtraBits) ; Value is BaseValue + getBits(ExtraBits)
; Base values ; Base values
lengthCode_l lengthBaseValue_l
dta l(3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43) dta l(3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43)
dta l(51,59,67,83,99,115,131,163,195,227,258) dta l(51,59,67,83,99,115,131,163,195,227,258)
distanceCode_l distanceBaseValue_l
dta l(1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385) dta l(1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385)
dta l(513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577) dta l(513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577)
lengthCode_h lengthBaseValue_h
dta h(3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43) dta h(3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43)
dta h(51,59,67,83,99,115,131,163,195,227,258) dta h(51,59,67,83,99,115,131,163,195,227,258)
distanceCode_h distanceBaseValue_h
dta h(1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385) dta h(1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385)
dta h(513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577) dta h(513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577)
; Number of extra bits to read ; Number of extra bits to read
lengthExtraBits lengthExtraBits
dta b(0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4) dta b(0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4)
@ -389,28 +430,41 @@ distanceExtraBits
dta b(0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10) dta b(0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10)
dta b(11,11,12,12,13,13) dta b(11,11,12,12,13,13)
org inflate+$400 ; Number of literal codes of each length in primary tree
* Data for building literal tree ; (MAX_BITS bytes, overlap with literalCodeLength)
; Must begin at page boundary! literalCount
ert <*
; Length of literal codes * Data for building primary tree
literalCodeLength org *+256 ; Lengths of literal codes
; Length of 'end' code literalCodeLength
endCodeLength org *+1 org *+256
; Length of 'length' codes ; Length of end code
lengthCodeLength org *+29 endCodeLength
org *+1
; Lengths of length codes
lengthCodeLength
org *+29
* Data for building distance tree * Data for building distance tree
distanceCodeLength org *+30 ; Lengths of distance codes
; For two unused codes in fixed trees and a end flag distanceCodeLength
org *+3 org *+30
; For two unused codes in fixed trees and end-of-table flag
org *+3
* Huffman tree structure * Huffman tree structure
; Number of codes of each length ; Number of codes of each length
bitsCount org *+TREES_SIZE bitsCount
org *+TREES_SIZE
; Pointer to sorted codes of each length ; Pointer to sorted codes of each length
bitsPointer_l org *+TREES_SIZE bitsPointer_l
bitsPointer_h org *+TREES_SIZE org *+TREES_SIZE+1
bitsPointer_h
org *+TREES_SIZE
; Sorted codes ; Sorted codes
sortedCodes org *+2*[256+1+29+30+2] sortedCodes
org *+256+1+29+30+2
end end