lawless-legends/Platform/Apple/virtual/src/core/decomp.s

202 lines
4.4 KiB
ArmAsm
Raw Normal View History

;****************************************************************************************
; Copyright (C) 2017 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
; (the "License"); you may not use this file except in compliance with the License.
; You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
; Unless required by applicable law or agreed to in writing, software distributed under
; the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
; ANY KIND, either express or implied. See the License for the specific language
; governing permissions and limitations under the License.
;****************************************************************************************
;@com.wudsn.ide.asm.hardware=APPLE2
; Lx47 Decompressor
; ------------------
* = $DF00
2017-01-02 19:14:59 +00:00
tmp = $2 ; len 2
2017-01-07 01:49:51 +00:00
pTmp = $6 ; len 2 ; not at $4, to preserve memmgr's pTmp
bits = $8 ; len 1
2017-01-02 19:14:59 +00:00
2017-01-07 01:49:51 +00:00
pDst = $C ; len 2 ; opposite order from memmgr,
pSrc = $E ; len 2 ; so it can avoid swapping
2017-01-02 19:14:59 +00:00
pEnd = $10 ; len 2
DEBUG = 0
2017-01-02 19:33:52 +00:00
; Decompress from pSrc to pDst, stop at pEnd. The source and dest can overlap, as long as the
; source block ends (at least) 2 bytes beyond the end of the dest block, e.g.
; DDDDDDDDDDDDDDD
2017-01-02 19:33:52 +00:00
; SSSSSSSss <-- 2 bytes beyond dest
; This guarantees that the decompression won't overwrite any source material
; before it gets used.
2017-01-02 19:33:52 +00:00
decomp !zone {
2017-01-15 19:37:34 +00:00
jsr .chkdst
2017-01-02 19:33:52 +00:00
ldy #0 ; In lit loop Y must be zero
2023-09-02 18:30:15 +00:00
sec
2017-01-17 18:19:19 +00:00
.fill1A jsr .getbt2
2023-09-02 18:30:15 +00:00
bne .fill1B ; always taken
2017-01-15 19:31:02 +00:00
.incdst inc pDst+1
2017-01-15 19:37:34 +00:00
.chkdst ldx pDst+1
2017-01-15 19:31:02 +00:00
cpx pEnd+1
ldx #$B0 ; bcs
bcc +
clc
2017-01-15 19:31:02 +00:00
ldx #$90 ; bcc
+ stx .ifend
2017-01-15 19:31:02 +00:00
rts
2017-01-17 18:19:19 +00:00
.endchk lda pDst
cmp pEnd ; check for done at end of each literal string
2017-01-15 19:31:02 +00:00
bcc .seq
bne .bad
rts
.bad sta $C002 ; clrAuxRd
brk
2017-01-15 19:31:02 +00:00
2017-01-15 19:52:08 +00:00
.src1A inc pSrc+1
2017-01-17 18:19:19 +00:00
bne .src1B ; always taken
2017-01-15 19:52:08 +00:00
2017-01-17 18:29:49 +00:00
.src2Ay iny ; now Y=1
2017-01-15 19:52:08 +00:00
.src2A inc pSrc+1
2017-01-17 18:29:49 +00:00
clc
bcc .src2B ; always taken
2017-01-15 19:52:08 +00:00
2017-01-02 19:33:52 +00:00
.lits asl bits ; get bit that tells us whether there's a literal string
2017-01-17 18:19:19 +00:00
beq .fill1A ; if we ran out of bits, get more
.fill1B bcc .ifend ; if bit was zero, no literals: go straight to sequence (after end check)
; Yes we have literals. Is the count exactly 1?
asl bits
bcc .not1
bne .yes1 ; if we didn't run out of bits, we can conclude len=1
jsr .getbt2 ; get more bits
bcc .not1
; Count is exactly 1 (most common case other than zero)
.yes1 lda (pSrc),y
sta (pDst),y
inc pSrc
2017-01-17 18:29:49 +00:00
beq .src2Ay
inc pDst
2017-01-17 18:19:19 +00:00
clc
2017-01-17 18:29:49 +00:00
bne .ifend ; common case
beq .ldst ; otherwise, this is always taken
2017-01-17 18:19:19 +00:00
.not1 ; count is not 1, so parse out a full gamma count
lda #1
jsr .gamma2
tax
- lda (pSrc),y
sta (pDst),y
2017-01-09 14:57:39 +00:00
iny
dex
bne -
tya
clc
adc pSrc
sta pSrc
2017-01-17 18:29:49 +00:00
bcs .src2A
.src2B tya
2017-01-09 14:57:39 +00:00
adc pDst
sta pDst
2017-01-17 18:19:19 +00:00
bcc +
.ldst jsr .incdst
+ iny ; special case: long literal marked by len=255
2017-01-09 14:57:39 +00:00
beq .lits
ldy #0
2017-01-15 19:31:02 +00:00
.ifend bcs .endchk ; normally skipped; self-modified to take when pDst+1 == pEnd+1
.seq lda (pSrc),y
2017-01-02 17:06:11 +00:00
inc pSrc
2017-01-17 18:19:19 +00:00
beq .src1A
.src1B asl
php ; save high bit for later len check
bmi .bigoff ; second-to-hi bit signals large offset
lsr
sta tmp
2017-01-15 19:52:08 +00:00
ldx #$FF ; two's complement of zero
2017-01-02 17:06:11 +00:00
bcc .gotoff ; always taken
2017-01-15 19:54:21 +00:00
.bigoff asl ; sets carry
2017-01-02 17:06:11 +00:00
sta tmp
2017-01-02 19:33:52 +00:00
jsr .gamma
lsr
ror tmp
lsr
ror tmp
2017-01-15 19:52:08 +00:00
eor #$FF ; make two's complement of offset hi-byte
tax
2017-01-02 17:06:11 +00:00
clc ; effectively add 1 to offset.
2017-01-17 18:19:19 +00:00
.gotoff lda pDst
sbc tmp
sta pTmp
2017-01-15 19:52:08 +00:00
txa
adc pDst+1
2017-01-02 17:06:11 +00:00
sta pTmp+1
.len plp ; retrieve marker for match-len > 2
bcc .short
.long jsr .gamma ; longer matches handled here
tax
- lda (pTmp),y
sta (pDst),y
iny
dex
bne -
; Match is always at least two bytes, so unroll that part.
.short lda (pTmp),y
sta (pDst),y
iny
lda (pTmp),y
sta (pDst),y
sec ; rather than increment Y an extra time
tya ; advance dst ptr
ldy #0 ; as expected by lits loop
2017-01-02 19:14:59 +00:00
adc pDst
sta pDst
2017-01-17 18:34:35 +00:00
bcs .dst1A
- jmp .lits
.dst1A jsr .incdst
bcc - ; always taken
2017-01-02 19:14:59 +00:00
; Read an Elias Gamma value into A. Destroys X. Sets carry.
2017-01-15 23:19:22 +00:00
.gamma lda #1
asl bits
2017-01-15 23:19:22 +00:00
bcc .gbit0
2017-01-15 23:40:47 +00:00
beq .gfill1
2017-01-15 23:19:22 +00:00
rts
.gfill1 jsr .getbts
.glup bcc .gbit0
rts
2017-01-17 18:19:19 +00:00
.gamma2
2017-01-15 23:19:22 +00:00
.gbit0 asl bits
beq .gfill2
.gshift rol
asl bits
bne .glup
2017-01-15 23:19:22 +00:00
beq .gfill1
.gfill2 jsr .getbts
bne .gshift ; always taken
2017-01-02 19:14:59 +00:00
; Get another 8 bits into our bit buffer. Destroys X. Preserves A. Requires Y=0.
2023-09-02 18:30:15 +00:00
; Carry is always set on entry, Z always clear on exit
2017-01-17 18:19:19 +00:00
; Alternately, use .getbt2 to preserve X and destroy A
2017-01-02 19:33:52 +00:00
.getbts tax
2017-01-17 18:19:19 +00:00
.getbt2 lda (pSrc),y
rol
sta bits
2017-01-02 19:14:59 +00:00
txa
2023-09-02 18:30:15 +00:00
inc pSrc
beq .src3A
2017-01-15 23:19:22 +00:00
rts
2017-01-17 18:19:19 +00:00
.src3A inc pSrc+1
2023-09-02 18:30:15 +00:00
rts
2017-01-17 18:19:19 +00:00
} ; end of zone
!ifdef PASS2 {
;!warn "decomp spare: ", $E000 - *
2017-01-15 23:19:22 +00:00
!if * > $E000 {
!warn "Decomp grew too large."
}
} else { ;PASS2
!set PASS2=1
}