-
Notifications
You must be signed in to change notification settings - Fork 1
/
aplib.asm
286 lines (253 loc) · 11.9 KB
/
aplib.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
; ***************************************************************************
; ***************************************************************************
;
; aplib.asm
;
; 65C816 decompressor for data stored in Jorgen Ibsen's aPLib format.
;
; Includes support for Emmanuel Marty's enhancements to the aPLib format.
;
; The code is 413 bytes long.
;
; This code is written for the ASAR assembler.
;
; Based off of the NMOS 6502 decompressor, Copyright 2019, John Brandwood:
; https://github.com/emmanuel-marty/apultra/blob/master/asm/6502/aplib_6502.asm
;
; Distributed under the Boost Software License, Version 1.0.
;
; Permission is hereby granted, free of charge, to any person or organization
; obtaining a copy of the software and accompanying documentation covered by
; this license (the "Software") to use, reproduce, display, distribute,
; execute, and transmit the Software, and to prepare derivative works of the
; Software, and to permit third-parties to whom the Software is furnished to
; do so, all subject to the following:
;
; The copyright notices in the Software and this entire statement, including
; the above license grant, this restriction and the following disclaimer,
; must be included in all copies of the Software, in whole or in part, and
; all derivative works of the Software, unless such copies or derivative
; works are solely in the form of machine-executable object code generated by
; a source language processor.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
; SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
; FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
; DEALINGS IN THE SOFTWARE.
;
; ***************************************************************************
; ***************************************************************************
; ***************************************************************************
; ***************************************************************************
;
; Decompression Macros
;
; Register usage
!scratch = $f0 ; 2-byte. Scratch+1 must remain #$00!
!hilen = $f2 ; 1-byte. Temporary for high byte of length.
!bitbuf = $f3 ; 1-byte.
!offset = $f4 ; 2-byte.
!spbuf = $f6 ; 2-byte.
!tdstptr = $f8 ; 2-byte. Temporary dstptr location.
!srcptr = $fa ; 3-byte.
!dstptr = $fd ; 2-byte.
!dstbank = $7f ; const.
;
; Macro to increment the source pointer to the next page.
; opt: duplication: removes costly jmps.
;
macro APL_GET_SRC()
lda [!srcptr], y ; opt: keep lowbyte in reg.
iny ; inc src addr.
bne +
inc !srcptr+1 ; highbyte in zeropage.
bne +
inc !srcptr+2 ; page in zeropage.
+:
endmacro
;
; Macro for byte & bit handling.
; opt: duplication: removes costly jmps.
;
macro APL_LOAD_BIT()
%APL_GET_SRC() ; Reload an empty bit-buffer
rol ; from the compressed source.
sta !bitbuf
endmacro
;
; Macro for gamma handling.
; opt: duplication: removes costly jmps.
;
macro APL_GET_GAMMA()
lda #$1 ; Get a gamma-coded value.
--: asl !bitbuf
bne ++
tcs ; opt: 2-cycle.
%APL_LOAD_BIT() ; Reload an empty bit-buffer
tsc ; opt: 2-cycle.
++: rol
rol !hilen
asl !bitbuf
bne ++
tcs ; opt: 2-cycle.
%APL_LOAD_BIT() ; Reload an empty bit-buffer
tsc ; opt: 2-cycle.
++: bcs --
endmacro
; ***************************************************************************
; ***************************************************************************
;
; apl_decompress - Decompress data stored in Jorgen Ibsen's aPLib format.
;
; Uses: lots!
;
; As an optimization, the code to handle window offsets > 64768 bytes has
; been removed, since these don't occur with a 16-bit address range.
;
; As an optimization, the code to handle window offsets > 32000 bytes can
; be commented-out, since these don't occur in typical 8-bit computer usage.
;
; Overall opts: reduce register pressure on y & x, use stack ptr, mvn, remove subroutine jumps.
macro APL()
apl_decompress:
; setup init.
sep #$30
phb ; push bank.
lda #!dstbank ; load new bank.
pha
plb
rep #$30
sei ; disable interrupts.
lda #$0000
sta !scratch ; clear scratch.
sta $004200 ; disable nmi.
tsc ; opt: use sp as free reg.
sta !spbuf ; store sp.
sep #$30
; ---.
ldy !srcptr ; Initialize source index.
stz !srcptr ; Opt: set lowbyte to zero.
lda #$80 ; Initialize an empty
sta !bitbuf ; bit-buffer.
;
; 0 bbbbbbbb - One byte from compressed data, i.e. a "literal".
;
.literal: % APL_GET_SRC()
.write_byte: ldx #$00 ; LWM=0.
sta (!dstptr) ; Write the byte directly to the output.
inc !dstptr
bne .next_tag
inc !dstptr+1
.next_tag: asl !bitbuf ; 0 bbbbbbbb
bne .skip0
%APL_LOAD_BIT() ; opt: no jsr.
.skip0: bcc .literal
.skip1: asl !bitbuf ; 1 0 <offset> <length>
bne .skip2
%APL_LOAD_BIT() ; opt: no jsr.
.skip2: bcc .copy_large
asl !bitbuf ; 1 1 0 dddddddn
bne .skip3
%APL_LOAD_BIT() ; opt: no jsr.
.skip3: bcc .copy_normal
; 1 1 1 dddd - Copy 1 byte within 15 bytes (or zero).
.copy_short: lda #$10
.nibble_loop: asl !bitbuf
bne .skip4
tcs ; opt: 2-cycle.
%APL_LOAD_BIT() ; opt: no jsr.
tsc ; opt: 2-cycle.
.skip4: rol
bcc .nibble_loop
beq .write_byte ; Offset=0 means write zero.
sta !scratch ; +1 of scratch must remain zero.
rep #$20
lda !dstptr
sbc !scratch
sta !tdstptr
sep #$20
lda (!tdstptr)
bra .write_byte
.finished: rep #$30 ; Fin.
lda !spbuf ; load sp.
tcs ; restore sp.
lda $80
sta $004200 ; enable
cli ; enable interrupts.
sep #$30
plb ; restore bank.
rep #$30
rtl ; All decompressed!
;
; 1 1 0 dddddddn - Copy 2 or 3 within 128 bytes.
;
.copy_normal: % APL_GET_SRC() ; 1 1 0 dddddddn
lsr
beq .finished ; Offset 0 == EOF.
sta !offset ; Preserve offset.
tdc ; opt: Clear high byte of length.
sta !offset+1 ; clear high byte of offset.
adc #$2 ; +2 length.
jmp .copy_page ; NZ from previous ADC.
;
; 1 0 <offset> <length> - gamma-coded LZSS pair.
;
.copy_large: tdc ; opt: Clear high byte of length
sta !hilen
%APL_GET_GAMMA() ; opt: no jsr, Get length.
cpx #$1 ; CC if LWM==0, CS if LWM==1.
sbc #$2 ; -3 if LWM==0, -2 if LWM==1.
bcs .normal_pair ; CC if LWM==0 && offset==2.
%APL_GET_GAMMA() ; opt: no jsr, Get length.
xba ; non-opt: put together length.
lda !hilen ; load highbyte of length.
xba ; non-opt: put together length.
bra .copy_page ; Use previous Offset.
.normal_pair: tax ; opt: keep for cmp.
stx !offset+1 ; Save bits 8..15 of offset.
% APL_GET_SRC() ; opt: no jsr.
sta !offset ; Save bits 0...7 of offset.
%APL_GET_GAMMA() ; opt: no jsr.
xba ; non-opt: put together length.
lda !hilen ; load highbyte of length.
xba ; non-opt: put together length.
;
cpx #$00 ; If offset < 256.
beq .lt256
cpx #$7D ; If offset >= 32000, length += 1.
bcs .match_plus2
cpx #$05 ; If offset >= 1280, length += 0.
bcs .match_plus1
.copy_page: ; opt: mvn, Calc address of match and store.
dec
sty !scratch ; opt: 2-cycle, store srcptr lowbyte.
rep #$30
tcs ; opt: 2-cycle, store 2 byte length.
lda !dstptr ; load precomputed destptr.
tay ; transfer cur dest.
sec ; non opt: need to keep this.
sbc !offset ; opt: subtract full offset in one go.
tax ; transfer src.
tsc ; opt: 2-cycle, load 2 byte length.
mvn !dstbank, !dstbank ; opt: mvn.
sty !dstptr ; opt: free computation of next dstptr
sep #$30
ldx #$01 ; transfer 1 to x. ; LWM=1.
ldy !scratch ; opt: 2-cycle, load srcptr lowbyte.
jmp .next_tag
.lt256: ldx !offset ; If offset < 128, length += 1.
bmi .copy_page
sec
.match_plus2: adc #$1 ; CS, so ADC #2.
bcs .match_plus256
.match_plus1: adc #$0 ; CS, so ADC #1, or CC if fall
bcc .copy_page ; through from .match_plus2.
.match_plus256: xba ; rare.
inc
xba
bra .copy_page
.end:
endmacro