ys2-intro/loader/src/decompress/ncdecomp.s
2025-11-13 19:07:39 +03:00

344 lines
4.2 KiB
ArmAsm
Executable file

;
; NuCrunch 1.0
; Christopher Jam
; May 2018
; with slight modifications by Krill
;
decompress = decrunch
decompsrc = read+1
NC_BLOCK_INTERFACE = 1
.macro getByte1
jsr get_byte
.endmacro
.macro getBit1
.local nomore
asl zbs1
bne nomore
getByte1
sec
rol
sta zbs1
nomore:
.endmacro
; get head of a pair of bits from the bitpair stream
; (must getBit2t precisely once before invoking again)
.macro getBit2h
.local nomore
asl zbs2
bne nomore
getByte1
sec
rol
sta zbs2
nomore:
.endmacro
.if NC_BLOCK_INTERFACE
; same, but preserving A
.macro getBit2hpa
.local nomore
asl zbs2
bne nomore
pha
getByte1
sec
rol
sta zbs2
pla
nomore:
.endmacro
.else
; same, but preserving A/ trashing X.
.macro getBit2hpa
.local nomore
asl zbs2
bne nomore
tax
getByte1
sec
rol
sta zbs2
txa
nomore:
.endmacro
.endif
; get tail of a pair of bits from the bitpair stream
.macro getBit2t
asl zbs2
.endmacro
; get head of a quad of bits from the quad stream
; (must getBit4t precisely three times before invoking again)
.macro getBit4h
.local nomore
asl zbs4
bne nomore
getByte1
sec
rol
sta zbs4
nomore:
.endmacro
; get tail of a quad of bits from the quad stream
.macro getBit4t
asl zbs4
.endmacro
; note, trashes X. Also, carry is clear when done
.macro getExpGoulombTail
.local ndone
ndone:
getBit2hpa
rol
getBit2t
bcs ndone
.endmacro
.macro getExpGoulombTail_odd_aligned
.local ndone
ndone:
getBit2t
rol
getBit2hpa
bcs ndone
.endmacro
.ifdef NUCRUNCH_ALIGN_FOR_SPEED
.byte <-$64-*,0 ; place decode_copy on a page boundary
.endif
decrunch_zpa=DECOMPVARS ;5 bytes required
zbs1 = decrunch_zpa+$00 ; 1 byte
zbs2 = decrunch_zpa+$01 ; 1 byte
zbs4 = decrunch_zpa+$02 ; 1 byte
zpc = decrunch_zpa+$03 ; 2 bytes
zpd = decdestlo
offsetm1 = zpc ; these are aliased, as never need both
decrunch:
; ldy #0
sty zbs1
sty zbs2
sty zbs4
decrunch_next_group:
.if NC_BLOCK_INTERFACE
jsr read_init
lda loadaddrhi
sta literal_read+2
ldx loadaddrlo
.endif
next_segment:
jsr get_byte
.if LOADCOMPD_TO
clc
adc loadaddroffslo
php
.endif
storedadrl:
sta zpd+0
jsr get_byte
.if LOADCOMPD_TO
plp
adc loadaddroffshi
.endif
storedadrh:
sta zpd+1
decode_literal:
; get count [ExpGoulomb0+1] in x
.if NC_BLOCK_INTERFACE
getBit1
lda#1
bcc ret1
getExpGoulombTail
ret1:
sta literal_len + 1
.else
ldx#1
getBit1
bcc ret1
lda#1
getExpGoulombTail
tax
ret1:
.endif
literal_loop:
.if NC_BLOCK_INTERFACE
literal_read:
lda $ff00,x
inx
bne *+5
jsr read_inc
.else
decompgetbyte:
jsr getcmem
.endif
sta (zpd),y
iny
.if NC_BLOCK_INTERFACE
literal_len:
cpy #0
.else
dex
.endif
bne literal_loop
clc
tya
adc zpd
sta zpd
bcc *+4
inc zpd+1
ldy#0
; literal is always followed by copy
decode_copy:
getBit2h
bcc short_offset
lda#1
getExpGoulombTail_odd_aligned
adc#255
sta offsetm1+1
getByte1
sta offsetm1
jmp got_high
short_offset:
lda#0
sta offsetm1+1
;ExpGoulomb k=3
getBit4h
lda#1
bcc no_tail
getExpGoulombTail_odd_aligned
no_tail:
adc#255
getBit4t
rol
getBit4t
rol
getBit4t
rol
sta offsetm1
got_high:
.if NC_BLOCK_INTERFACE
lda#1
getBit2t
bcc length_two
getExpGoulombTail
cmp#255
beq end_of_segment ; copy length of 256 marks end of segment
length_two:
sta copy_len+1
.else
ldx#1
getBit2t
bcc length_two
lda#1
getExpGoulombTail
tax
cpx#255
beq end_of_segment ; copy length of 256 marks end of segment
length_two:
.endif
; note carry is clear at this point; good as we want to subtract (offsetm1+1)
lda zpd
sbc offsetm1
sta zpc
lda zpd+1
sbc offsetm1+1
sta zpc+1
lda (zpc),y
sta (zpd),y
copy_loop:
iny
lda (zpc),y
sta (zpd),y
.if NC_BLOCK_INTERFACE
copy_len:
cpy #0
.else
dex
.endif
bne copy_loop
tya
; carry will be set from SBC above
adc zpd
sta zpd
bcc *+4
inc zpd+1
.if NC_BLOCK_INTERFACE
POLLBLOCK
.endif
ldy#0
getBit1
bcs jmp_decode_copy
jmp decode_literal
jmp_decode_copy:
jmp decode_copy
get_byte:
.if NC_BLOCK_INTERFACE
read:
lda $ff00,x
inx
beq read_inc
rts
read_inc:
inc literal_read+2
inc read+2
read_init:
pha
tya
pha
GETBLOCK read+2
pla
tay
pla
ldx#0
end_of_segment:
rts
.else
decompgetbyte1:
jmp getcmem
.endif
.if NC_BLOCK_INTERFACE
.else
end_of_file:
rts
end_of_segment:
lda offsetm1
cmp#0
beq end_of_file
jmp next_segment
.endif
decrunch_end: