ys2-intro/loader/tools/pucrunch/sa_uncrunch.asm
2025-11-13 19:07:39 +03:00

292 lines
6 KiB
NASM
Raw Blame History

; 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
LZPOS EQU $9e ; 2 ZeroPage temporaries
bitstr EQU $fb ; 1 temporary (does not need to be ZP)
ORG $c000
; 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
sta 1
#endif
#if IRQLOAD
;jsr initloader
#else
; Setup read pointer
sty INPOS
stx INPOS+1
#endif
#if SHORT
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 9$
sec ; error
jmp eof2
9$ jsr getbyt ; 'u'
cmp #117
beq 8$
sec ; error
jmp eof2
8$ 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
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
0$ beq 1$ ; Y == 0 ?
jsr getbyt
sta table,x
inx
dey
bne 0$
1$ ; setup bit store - $80 means empty
lda #$80
sta bitstr
jmp main
getbyt jsr getnew
lda bitstr
ror
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 ; cmp #1 ; LEN == 2 ? (A is never 0)
bne lz77 ; LEN != 2 -> LZ77
;tya ; A = 0
jsr get1bit ; X = 0
lsr ; bit -> C, A = 0
bcc lz77_2 ; A=0 -> LZPOS+1
;***FALL THRU***
; e..e01
jsr get1bit ; X = 0
lsr ; 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 table-1,x ; Saves one jump if done here (loses one txa)
cpx #16 ; 32 ; 31-32 -> C clear, 32-32 -> C set..
bcc 1$ ; 1..31, we got the right byte from the table
; Ranks 32..64 (11111<31>xxxxx), get byte..
txa ; get back the value (5 valid bits)
ldx #4 ;3
jsr getbits ; get 3 more bits to get a full byte, X = 0
1$ 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
eof clc
eof2 lda #$37
sta 1
cli
#endif
#if IRQLOAD
;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
;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 0$
inc INPOS+1
#endif
0$ sec
rol ; 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 1$
jsr getnew
1$ 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 1$
jsr getnew
1$ rol ;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 0$
inc OUTPOS+1 ; ZP
0$ rts
table dc.b 0,0,0,0,0,0,0
dc.b 0,0,0,0,0,0,0,0
;dc.b 0,0,0,0,0,0,0,0
;dc.b 0,0,0,0,0,0,0,0