456 lines
9.8 KiB
NASM
456 lines
9.8 KiB
NASM
|
||
;*
|
||
;*
|
||
;* PUCRUNCH unpacker for GB
|
||
;* Modeled after Pasi Ojala's C64 code.
|
||
;*
|
||
;* Written in RGBDS
|
||
;*
|
||
;* V1.0 - Ported to GB by Jeff Frohwein, started 22-Jul-99
|
||
;* V1.1 - Various optimizations, 23-Jul-99
|
||
;* V1.2 - Even more optimizations, 23-Jul-99
|
||
;* V1.3 - Fixed a bug in the code. 256 byte copy didn't work. 24-Feb-00
|
||
;*
|
||
;* Note: If you unpack to VRAM than the screen needs to be
|
||
;* turned off because no checks for VRAM available are made.
|
||
|
||
; Pucrunch file format
|
||
|
||
;;; db INPOS low (endAddr + overlap - size) & 0xff
|
||
;;; db INPOS high (endAddr + overlap - size) >> 8
|
||
;;; db 'p'
|
||
;;; db 'u'
|
||
;;; db (endAddr - 0x100) & 0xff
|
||
;;; db (endAddr - 0x100) >> 8
|
||
; db escape>>(8-escBits)
|
||
;;; db (start & 0xff) (OUTPOS low)
|
||
;;; db (start >> 8) (OUTPOS high)
|
||
; db escBits
|
||
; db maxGamma + 1
|
||
; db (1<<maxGamma); /* Short/Long RLE */
|
||
; db extraLZPosBits;
|
||
;;; db (exec & 0xff)
|
||
;;; db (exec >> 8)
|
||
; db rleUsed (31) ;needed
|
||
; ds rleUsed
|
||
; ....data....
|
||
|
||
PUSHS
|
||
|
||
SECTION "Pucrunch Vars",BSS
|
||
|
||
;bitstr DB
|
||
escPu DB
|
||
;InPtr DW
|
||
OutPtr DW
|
||
;regx DB
|
||
;regy DB
|
||
lzpos DW
|
||
EscBits DB
|
||
Esc8Bits DB
|
||
MaxGamma DB
|
||
Max1Gamma DB
|
||
Max2Gamma DB
|
||
Max8Gamma DB
|
||
ExtraBits DB
|
||
tablePu DS 31
|
||
|
||
|
||
SECTION "Pucrunch High Vars",HRAM
|
||
|
||
regy DB
|
||
|
||
POPS
|
||
|
||
; HL = InPtr
|
||
; D = bitstr
|
||
; E = X
|
||
; BC = temps
|
||
|
||
; ****** Unpack pucrunch data ******
|
||
; Entry: HL = Source packed data
|
||
; DE = Destination for unpacked data
|
||
|
||
Unpack:
|
||
ld16r OutPtr,de
|
||
|
||
; Read the file header & setup variables
|
||
|
||
ld bc,6
|
||
add hl,bc
|
||
|
||
ld a,[hl+]
|
||
ld [escPu],a
|
||
|
||
inc hl
|
||
inc hl
|
||
|
||
ld a,[hl+]
|
||
ld [EscBits],a
|
||
ld b,a
|
||
|
||
ld a,8
|
||
sub b
|
||
ld [Esc8Bits],a
|
||
|
||
ld a,[hl+]
|
||
ld [MaxGamma],a
|
||
dec a
|
||
ld b,a
|
||
ld a,8
|
||
sub b
|
||
ld [Max8Gamma],a
|
||
|
||
ld a,[hl+]
|
||
ld [Max1Gamma],a
|
||
add a
|
||
dec a
|
||
ld [Max2Gamma],a
|
||
|
||
ld a,[hl+]
|
||
ld [ExtraBits],a
|
||
|
||
inc hl
|
||
inc hl
|
||
|
||
ld a,[hl+]
|
||
ld b,a
|
||
|
||
ld de,tablePu
|
||
|
||
; Copy the RLE table (maximum of 31 bytes) to RAM
|
||
|
||
inc b
|
||
srl b
|
||
jr nc,.orleloop
|
||
|
||
.rleloop:
|
||
ld a,[hl+]
|
||
ld [de],a
|
||
inc de
|
||
|
||
.orleloop:
|
||
ld a,[hl+]
|
||
ld [de],a
|
||
inc de
|
||
|
||
dec b
|
||
jr nz,.rleloop
|
||
|
||
|
||
|
||
ld d,$80
|
||
|
||
jr .main
|
||
|
||
|
||
.newesc:
|
||
ld b,a
|
||
|
||
ld a,[escPu]
|
||
ld [regy],a
|
||
|
||
ld a,[EscBits]
|
||
ld e,a
|
||
|
||
ld a,b
|
||
|
||
inc e
|
||
|
||
call .getchk
|
||
|
||
ld [escPu],a
|
||
|
||
ld a,[regy]
|
||
|
||
; Fall through and get the rest of the bits.
|
||
|
||
.noesc:
|
||
ld b,a
|
||
|
||
ld a,[Esc8Bits]
|
||
ld e,a
|
||
|
||
ld a,b
|
||
|
||
inc e
|
||
|
||
call .getchk
|
||
|
||
; Write out the escaped/normal byte
|
||
|
||
ld16 bc,OutPtr
|
||
ld [bc],a
|
||
inc bc
|
||
ld16r OutPtr,bc
|
||
|
||
; Fall through and check the escape bits again
|
||
|
||
.main:
|
||
ld a,[EscBits]
|
||
ld e,a
|
||
|
||
xor a ; A = 0
|
||
ld [regy],a
|
||
|
||
inc e
|
||
|
||
call .getchk ; X=2 -> X=0
|
||
|
||
ld b,a
|
||
ld a,[escPu]
|
||
cp b
|
||
ld a,b
|
||
|
||
jr nz,.noesc ; Not the escape code -> get the rest of the byte
|
||
|
||
; Fall through to packed code
|
||
|
||
call .getval ; X=0 -> X=0
|
||
|
||
ld [lzpos],a ; xstore - save the length for a later time
|
||
|
||
srl a ; cmp #1 ; LEN == 2 ? (A is never 0)
|
||
jp nz,.lz77 ; LEN != 2 -> LZ77
|
||
|
||
call .get1bit ; X=0 -> X=0
|
||
|
||
srl a ; bit -> C, A = 0
|
||
|
||
jp nc,.lz77_2 ; A=0 -> LZPOS+1 LZ77, len=2
|
||
|
||
; e..e01
|
||
call .get1bit ; X=0 -> X=0
|
||
srl a ; bit -> C, A = 0
|
||
jp nc,.newesc ; e..e010 New Escape
|
||
|
||
; e..e011 Short/Long RLE
|
||
ld a,[regy] ; Y is 1 bigger than MSB loops
|
||
inc a
|
||
ld [regy],a
|
||
|
||
call .getval ; Y is 1, get len, X=0 -> X=0
|
||
ld [lzpos],a ; xstore - Save length LSB
|
||
|
||
ld c,a
|
||
|
||
ld a,[Max1Gamma]
|
||
ld b,a
|
||
|
||
ld a,c
|
||
|
||
cp b ; ** PARAMETER 63-64 -> C set, 64-64 -> C clear..
|
||
|
||
jr c,.chrcode ; short RLE, get bytecode
|
||
|
||
; Otherwise it's long RLE
|
||
.longrle:
|
||
ld b,a
|
||
ld a,[Max8Gamma]
|
||
ld e,a ; ** PARAMETER 111111xxxxxx
|
||
ld a,b
|
||
|
||
call .getbits ; get 3/2/1 more bits to get a full byte, X=2 -> X=0
|
||
ld [lzpos],a ; xstore - Save length LSB
|
||
|
||
call .getval ; length MSB, X=0 -> X=0
|
||
|
||
ld [regy],a ; Y is 1 bigger than MSB loops
|
||
|
||
.chrcode:
|
||
call .getval ; Byte Code, X=0 -> X=0
|
||
|
||
ld e,a
|
||
|
||
ld c,(tablePu-1)%256
|
||
add c
|
||
ld c,a
|
||
ld a,(tablePu-1)/256
|
||
adc 0
|
||
ld b,a
|
||
|
||
ld a,e
|
||
cp 32 ; 31-32 -> C set, 32-32 -> C clear..
|
||
ld a,[bc]
|
||
jr c,.less32 ; 1..31
|
||
|
||
; Not ranks 1..31, -> 11111<31>xxxxx (32..64), get byte..
|
||
|
||
ld a,e ; get back the value (5 valid bits)
|
||
|
||
ld e,3
|
||
|
||
call .getbits ; get 3 more bits to get a full byte, X=3 -> X=0
|
||
|
||
.less32:
|
||
push hl
|
||
push af
|
||
|
||
ld a,[lzpos]
|
||
ld e,a ; xstore - get length LSB
|
||
|
||
ld b,e
|
||
inc b ; adjust for cpx#$ff;bne -> bne
|
||
|
||
ld a,[regy]
|
||
ld c,a
|
||
|
||
ld16r hl,OutPtr
|
||
|
||
pop af
|
||
|
||
.dorle:
|
||
ld [hl+],a
|
||
|
||
dec b
|
||
jr nz,.dorle ; xstore 0..255 -> 1..256
|
||
|
||
dec c
|
||
jr nz,.dorle ; Y was 1 bigger than wanted originally
|
||
|
||
ld16r OutPtr,hl
|
||
|
||
pop hl
|
||
jp .main
|
||
|
||
.lz77:
|
||
call .getval ; X=0 -> X=0
|
||
|
||
ld b,a
|
||
|
||
ld a,[Max2Gamma]
|
||
cp b ; end of file ?
|
||
ret z ; yes, exit
|
||
|
||
ld a,[ExtraBits] ; ** PARAMETER (more bits to get)
|
||
ld e,a
|
||
|
||
ld a,b
|
||
|
||
dec a ; subtract 1 (1..126 -> 0..125)
|
||
|
||
inc e
|
||
|
||
call .getchk ;f ; clears Carry, X=0 -> X=0
|
||
|
||
.lz77_2:
|
||
ld [lzpos+1],a ; offset MSB
|
||
|
||
ld e,8
|
||
|
||
call .getbits ; clears Carry, X=8 -> X=0
|
||
|
||
; Note: Already eor:ed in the compressor..
|
||
ld b,a
|
||
|
||
ld a,[lzpos]
|
||
ld e,a ; xstore - LZLEN (read before it's overwritten)
|
||
|
||
ld a,[OutPtr]
|
||
add b ; -offset -1 + curpos (C is clear)
|
||
ld [lzpos],a
|
||
|
||
ld a,[lzpos+1]
|
||
ld b,a
|
||
|
||
ld a,[OutPtr+1]
|
||
ccf
|
||
sbc b
|
||
ld [lzpos+1],a ; copy X+1 number of chars from LZPOS to OUTPOS
|
||
|
||
inc e ; adjust for cpx#$ff;bne -> bne
|
||
|
||
; Write decompressed bytes out to RAM
|
||
ld b,e
|
||
|
||
push de
|
||
push hl
|
||
|
||
ld16r hl,lzpos
|
||
ld16r de,OutPtr
|
||
|
||
ld a,b
|
||
or a ; Is it zero?
|
||
jr z,.zero ; yes
|
||
|
||
inc b
|
||
srl b
|
||
jr nc,.olzloop
|
||
|
||
.lzloop:
|
||
ld a,[hl+] ; Note: Must be copied forward
|
||
ld [de],a
|
||
inc de
|
||
.olzloop:
|
||
ld a,[hl+] ; Note: Must be copied forward
|
||
ld [de],a
|
||
inc de
|
||
|
||
dec b
|
||
jr nz,.lzloop ; X loops, (256,1..255)
|
||
|
||
ld16r OutPtr,de
|
||
|
||
pop hl
|
||
pop de
|
||
jp .main
|
||
|
||
.zero:
|
||
ld b,128
|
||
jr .lzloop
|
||
|
||
; getval : Gets a 'static huffman coded' value
|
||
; ** Scratches X, returns the value in A **
|
||
.getval: ; X must be 0 when called!
|
||
ld a,1
|
||
ld e,a
|
||
.loop0:
|
||
sla d
|
||
|
||
jr nz,.loop1
|
||
|
||
ld d,[hl]
|
||
inc hl
|
||
|
||
rl d ; Shift in C=1 (last bit marker)
|
||
; bitstr initial value = $80 == empty
|
||
.loop1:
|
||
jr nc,.getchk ; got 0-bit
|
||
|
||
inc e
|
||
|
||
ld b,a ; save a
|
||
|
||
ld a,[MaxGamma]
|
||
cp e
|
||
|
||
ld a,b ; restore a
|
||
|
||
jr nz,.loop0
|
||
|
||
jr .getchk
|
||
|
||
|
||
; getbits: Gets X bits from the stream
|
||
; ** Scratches X, returns the value in A **
|
||
|
||
.get1bit:
|
||
inc e
|
||
.getbits:
|
||
sla d
|
||
|
||
jr nz,.loop3
|
||
|
||
ld d,[hl]
|
||
inc hl
|
||
|
||
rl d ; Shift in C=1 (last bit marker)
|
||
; bitstr initial value = $80 == empty
|
||
.loop3:
|
||
rla
|
||
.getchk:
|
||
dec e
|
||
|
||
jr nz,.getbits
|
||
or a ; clear carry flag
|
||
ret |