-
Notifications
You must be signed in to change notification settings - Fork 0
/
unpack.asm
290 lines (253 loc) · 6.35 KB
/
unpack.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
; SHORT+IRQLOAD 354 bytes
; no rle =~ -83 bytes -> 271
; fixed params =~ -48 bytes -> 306
; 223 bytes
SHORT = 0 ;1 ; assume file is ok
IRQLOAD = 0 ;1
; processor 6502
; ORG $c000
.unpack
{
; Call with X = HI of packed data, Y = LO of packed data
; Returns exec address in X = HI and Y = LO
; Carry will be set for error, cleared for OK
IF SHORT=0
;sei
;lda #&35 ; C64 processor flags, unneeded
;sta 1
ENDIF
IF IRQLOAD=1
;jsr initloader
ELSE
; Setup read pointer
sty INPOS
stx INPOS+1
ENDIF
IF SHORT=1
ldx #5
222$ jsr getbyt ; skip 'p', 'u', endAddr HI&LO, leave starting escape in A
dex
bne 222$
ELSE
jsr getbyt ; 'p'
cmp #112
beq s9
sec ; error
jmp eof2
.s9: jsr getbyt ; 'u'
cmp #117
beq s8
sec ; error
jmp eof2
.s8: jsr getbyt ; skip endAddr
jsr getbyt
jsr getbyt
ENDIF
sta esc+1 ; starting escape
jsr getbyt ; read startAddr
sta OUTPOS
jsr getbyt
sta OUTPOS+1
jsr getbyt ; read # of escape bits
sta escB0+1
sta escB1+1
lda #8
sec
sbc escB1+1
sta noesc+1 ; 8-escBits
jsr getbyt
sta mg+1 ; maxGamma + 1
lda #9
sec
sbc mg+1 ; 8 - maxGamma == (8 + 1) - (maxGamma + 1)
sta longrle+1
jsr getbyt
sta mg1+1 ; (1<<maxGamma)
asl a
clc
sbc #0
sta mg21+1 ; (2<<maxGamma) - 1
jsr getbyt
sta elzpb+1
jsr getbyt ; exec address
sta lo+1 ; lo
jsr getbyt
sta hi+1 ; hi
jsr getbyt ; rleUsed
ldx #0
tay
.s0: beq s1 ; Y == 0 ?
jsr getbyt
sta unpackTable,x
inx
dey
bne s0
.s1: ; setup bit store - $80 means empty
lda #&80
sta bitstr
jmp main
.getbyt:jsr getnew
lda bitstr
ror a
rts
.newesc:ldy esc+1 ; remember the old code (top bits for escaped byte)
.escB0: ldx #2 ; ** PARAMETER 0..8
jsr getchkf ; get & save the new escape code
sta esc+1
tya ; pre-set the bits
; Fall through and get the rest of the bits.
.noesc: ldx #6 ; ** PARAMETER 8..0
jsr getchkf
jsr putch ; output the escaped/normal byte
; Fall through and check the escape bits again
.main: ldy #0 ; Reset to a defined state
tya ; A = 0
.escB1: ldx #2 ; ** PARAMETER 0..8
jsr getchkf ; X = 0
.esc: cmp #0
bne noesc
; Fall through to packed code
jsr getval ; X = 0
sta LZPOS ; xstore - save the length for a later time
lsr a ; cmp #1 ; LEN == 2 ? (A is never 0)
bne lz77 ; LEN != 2 -> LZ77
;tya ; A = 0
jsr get1bit ; X = 0
lsr a ; bit -> C, A = 0
bcc lz77_2 ; A=0 -> LZPOS+1
;***FALL THRU***
; e..e01
jsr get1bit ; X = 0
lsr a ; bit -> C, A = 0
bcc newesc ; e..e010
;***FALL THRU***
; e..e011
.srle: iny ; Y is 1 bigger than MSB loops
jsr getval ; Y is 1, get len, X = 0
sta LZPOS ; xstore - Save length LSB
.mg1: cmp #64 ; ** PARAMETER 63-64 -> C clear, 64-64 -> C set..
bcc chrcode ; short RLE, get bytecode
.longrle:ldx #2 ; ** PARAMETER 111111xxxxxx
jsr getbits ; get 3/2/1 more bits to get a full byte, X = 0
sta LZPOS ; xstore - Save length LSB
jsr getval ; length MSB, X = 0
tay ; Y is 1 bigger than MSB loops
.chrcode: jsr getval ; Byte Code, X = 0
tax ; this is executed most of the time anyway
lda unpackTable-1,x ; Saves one jump if done here (loses one txa)
cpx #32 ; 31-32 -> C clear, 32-32 -> C set..
bcc s1a ; 1..31, we got the right byte from the table
; Ranks 32..64 (11111°xxxxx), get byte..
txa ; get back the value (5 valid bits)
ldx #3
jsr getbits ; get 3 more bits to get a full byte, X = 0
.s1a: ldx LZPOS ; xstore - get length LSB
inx ; adjust for cpx#$ff;bne -> bne
.dorle: jsr putch
dex
bne dorle ; xstore 0..255 -> 1..256
dey
bne dorle ; Y was 1 bigger than wanted originally
.mainbeq: beq main ; reverse condition -> jump always
.lz77: jsr getval ; X = 0
.mg21: cmp #127 ; ** PARAMETER Clears carry (is maximum value)
bne noeof
; EOF
.eof:
IF SHORT=0
; EOF
clc
.eof2: ;lda #&37 ; c64 processofr flags, unneeded
; sta 1
cli
ENDIF
IF IRQLOAD=1
;jsr endloader
lo = .+1
hi = .+2
jmp $aaaa
ELSE
.hi: ldx #0
.lo: ldy #0
rts
ENDIF
.noeof: sbc #0 ; C is clear -> subtract 1 (1..126 -> 0..125)
.elzpb: ldx #0 ; ** PARAMETER (more bits to get)
jsr getchkf ; clears Carry, X = 0
.lz77_2:sta LZPOS+1 ; offset MSB
jsr getbyte ; clears Carry, X = 0
; Note: Already eor:ed in the compressor..
;eor #255 ; offset LSB 2's complement -1 (i.e. -X = ~X+1)
adc OUTPOS ; -offset -1 + curpos (C is clear)
ldx LZPOS ; xstore = LZLEN (read before it's overwritten)
sta LZPOS
lda OUTPOS+1
sbc LZPOS+1 ; takes C into account
sta LZPOS+1 ; copy X+1 number of chars from LZPOS to OUTPOS
;ldy #0 ; Y was 0 originally, we don't change it
inx ; adjust for cpx#$ff;bne -> bne
.lzloop:lda (LZPOS),y ; using abs,y is 3 bytes longer, only 1 cycle/byte faster
jsr putch ; Note: must be copied forwards!
iny ; Y does not wrap because X=0..255 and Y initially 0
dex
bne lzloop ; X loops, (256,1..255)
beq mainbeq ; jump through another beq (-1 byte, +3 cycles)
.getnew:pha ; 1 Byte/3 cycles
if IRQLOAD=1
;jsr READBYTE ; should not change X or Y, return byte in A
; An implementation would first check if any bytes are available
; and if not, transfer a block from drive.
ELSE
INPOS = *+1
lda &aaaa ; ** PARAMETER
inc INPOS
bne s0a
inc INPOS+1
ENDIF
.s0a: sec
rol a ; Shift out the next bit and
; shift in C=1 (last bit marker)
sta bitstr ; bitstr initial value = $80 == empty
pla ; 1 Byte/4 cycles
rts
; 25+12 = 37
; getval : Gets a 'static huffman coded' value
; ** Scratches X, returns the value in A **
.getval:inx ; X <- 1
txa ; set the top bit (value is 1..255)
.gv0: asl bitstr
bne s1b
jsr getnew
.s1b: bcc getchk ; got 0-bit
inx
.mg: cpx #7 ; ** PARAMETER unary code maximum length + 1
bne gv0
beq getchk ; inverse condition -> jump always
; getval: 18 bytes
; 15 + 17*n + 6+15*n+12 + 36*n/8 = 33 + 32*n + 36*n/8 cycles
; getbits: Gets X bits from the stream
; ** Scratches X, returns the value in A **
.getbyte: ldx #7
.get1bit: inx ;2
.getbits: asl bitstr
bne s1c
jsr getnew
.s1c: rol a ;2
.getchk: dex ;2 more bits to get ?
.getchkf: bne getbits ;2/3
clc ;2 return carry cleared
rts ;6+6
OUTPOS = *+1 ; ZP
.putch: sta &aaaa ; ** parameter
inc OUTPOS ; ZP
bne s0b
inc OUTPOS+1 ; ZP
.s0b: rts
IF 0
.table:
EQUB 0,0,0,0,0,0,0
EQUB 0,0,0,0,0,0,0,0
EQUB 0,0,0,0,0,0,0,0
EQUB 0,0,0,0,0,0,0,0
ENDIF
}