; #######################################################################################################################################

; PackFire 1.2e - (tiny depacker) by Neural
; HuC6280 version by Mic 
;
; Assembles with wla-dx
;
; Example (decrunching packed_data into RAM at $2200):
;
;	lda		#<packed_data
;	sta		<PACKFIRE_SRC
;	lda		#>packed_data
;	sta		<PACKFIRE_SRC+1
;	lda		#$00
;	sta		<PACKFIRE_DEST
;	lda		#$22
;	sta		<PACKFIRE_DEST+1
;	jsr		unpackfire_tiny
;
; Depacker footprint: 291 bytes ROM, 28 bytes RAM (zp)

; #######################################################################################################################################

.DEFINE PACKFIRE_ZP_BASE 	$2010


; Zeropage variables
.EQU PACKFIRE_TII	PACKFIRE_ZP_BASE+$00 ;\
.EQU PACKFIRE_SRC2	PACKFIRE_ZP_BASE+$01 ; |
.EQU PACKFIRE_DEST	PACKFIRE_ZP_BASE+$03 ; | tii SRC2,DEST,OFFS2
.EQU PACKFIRE_OFFS2	PACKFIRE_ZP_BASE+$05 ;/
.EQU PACKFIRE_JMP	PACKFIRE_ZP_BASE+$07
.EQU PACKFIRE_LTBL	PACKFIRE_ZP_BASE+$0A
.EQU PACKFIRE_CNT	PACKFIRE_ZP_BASE+$0D
.EQU PACKFIRE_LEN	PACKFIRE_ZP_BASE+$0E
.EQU PACKFIRE_OFFS	PACKFIRE_ZP_BASE+$0F
.EQU PACKFIRE_SRC	PACKFIRE_ZP_BASE+$11
.EQU PACKFIRE_DIST	PACKFIRE_ZP_BASE+$13
.EQU PACKFIRE_TEMP	PACKFIRE_ZP_BASE+$15
.EQU PACKFIRE_TEMP2	PACKFIRE_ZP_BASE+$17
.EQU PACKFIRE_BITS	PACKFIRE_ZP_BASE+$19
.EQU PACKFIRE_ORIGSRC PACKFIRE_ZP_BASE+$1A


; #######################################################################################################################################

; Increase a 16-bit zeropage variable
.macro pf_inc16_zp 
	inc		<\1		
	bne		+		
	inc		<\1+1	
 	+:
 .endm ; 6 bytes

.macro pf_inc_src
	iny
	bne 	+
	inc 	<PACKFIRE_SRC+1
	+:
 .endm  ;5 bytes
 

; Decrease a 16-bit zeropage variable
.macro pf_dec16_zp 
	lda		<\1		
	bne		+		
	dec		<\1+1	
 	+:
 	dec		<\1		
 .endm ; 8 bytes


.macro pf_mov16_zp 
	lda 	<\2
	sta 	<\1
	lda 	<\2+1
	sta 	<\1+1
 .endm ; 8 bytes


.macro pf_add16_zp
	clc
	ldx 	#<\1
	set
	adc 	<\2
	inx
	set
	adc 	<\2+1
 .endm ; 10 bytes
 
 
; #######################################################################################################################################


; In:
; PACKFIRE_SRC = source address
; PACKFIRE_DEST = dest address
;
unpackfire_tiny:
	; Setup code in zeropage RAM
	lda		#$73				; Opcode for 'tii'
	sta		<PACKFIRE_TII
	tii		_upt_jump,PACKFIRE_JMP,6
	
	lda		<PACKFIRE_SRC
	sta		<PACKFIRE_ORIGSRC
	clc
	adc		#26					; Skip the header
	sta		<PACKFIRE_SRC
	lda		<PACKFIRE_SRC+1
	sta		<PACKFIRE_ORIGSRC+1		
	adc		#0
	sta		<PACKFIRE_SRC+1

	cly
	bsr		_upt_read_bits
_upt_lit_copy:
	lda		(<PACKFIRE_SRC),y
	sta		(<PACKFIRE_DEST)
	pf_inc_src
	pf_inc16_zp	PACKFIRE_DEST
_upt_main_loop:
	bsr		_upt_get_bit
	bcs		_upt_lit_copy
	lda		#$FF
	sta		<PACKFIRE_OFFS
	sta 	<PACKFIRE_OFFS+1
_upt_get_index:
	pf_inc16_zp	PACKFIRE_OFFS
	bsr		_upt_get_bit
	bcc		_upt_get_index
	lda		<PACKFIRE_OFFS
	cmp		#$10
	bne		+
	rts
+:
	bsr		_upt_get_pair
	pf_mov16_zp PACKFIRE_OFFS2,PACKFIRE_OFFS
	lda		<PACKFIRE_OFFS+1
	bne		+
	lda		<PACKFIRE_OFFS
	cmp		#3
	bcc		_upt_in_range
+:
	stz		<PACKFIRE_OFFS
	stz		<PACKFIRE_OFFS+1
_upt_in_range:
	ldx		<PACKFIRE_OFFS
	lda		<PACKFIRE_LTBL,x
	sta		<PACKFIRE_LEN
	lda.w 	_upt_table_dist,x
	sta		<PACKFIRE_DIST
	stz 	<PACKFIRE_DIST+1
	jsr		_upt_get_bits
	bsr		_upt_get_pair
	lda 	<PACKFIRE_DEST
	sec
	sbc 	<PACKFIRE_OFFS
	sta 	<PACKFIRE_SRC2
	lda 	<PACKFIRE_DEST+1
	sbc 	<PACKFIRE_OFFS+1
	sta 	<PACKFIRE_SRC2+1
	jmp 	PACKFIRE_TII		; Jump to code in zeropage RAM. It will jump back to the line below
_upt_after_copy:
	; DEST += OFFS2
	pf_add16_zp PACKFIRE_DEST,PACKFIRE_OFFS2
	bra		_upt_main_loop
_upt_read_bits:
	lda		(<PACKFIRE_SRC),y
	sta		<PACKFIRE_BITS
	pf_inc_src
	rts
_upt_get_bit:
	asl		<PACKFIRE_BITS
	bne		_upt_byte_done
	bsr		_upt_read_bits
	rol		<PACKFIRE_BITS
_upt_byte_done:
	rts
_upt_table_dist: .db 16,48,32
_upt_get_pair:
	stz		<PACKFIRE_CNT
_upt_calc_len_dist:
	lda		<PACKFIRE_CNT
	and		#$0F
	sta		<PACKFIRE_DIST
  	stz		<PACKFIRE_DIST+1	
	bne		_upt_node
	lda		#1
	sta		<PACKFIRE_TEMP2
	stz		<PACKFIRE_TEMP2+1
_upt_node:
	lda		<PACKFIRE_CNT
	lsr		a
	phy
	tay
	lda		(<PACKFIRE_ORIGSRC),y	; A = src[CNT >> 1]
	sta		<PACKFIRE_LEN
	ply
	lda		#1
	sta		<PACKFIRE_TEMP
	stz		<PACKFIRE_TEMP+1
	and		<PACKFIRE_DIST
	beq		_upt_nibble
	lda		<PACKFIRE_LEN
	lsr		a
	lsr		a
	lsr		a
	lsr		a
	sta		<PACKFIRE_LEN
_upt_nibble:
	pf_mov16_zp	PACKFIRE_DIST,PACKFIRE_TEMP2
	lda		<PACKFIRE_LEN
	and		#$0F
	sta		<PACKFIRE_LEN
-:
	beq		+
	asl		<PACKFIRE_TEMP
	rol		<PACKFIRE_TEMP+1
	dea
	bra		-
+:
	; TEMP2 += TEMP; CNT++; OFFS--
	pf_add16_zp PACKFIRE_TEMP2,PACKFIRE_TEMP
	inc 	<PACKFIRE_CNT
	pf_dec16_zp	PACKFIRE_OFFS
	lda		<PACKFIRE_OFFS+1
	bpl		_upt_calc_len_dist
_upt_get_bits:
	stz		<PACKFIRE_OFFS
	stz		<PACKFIRE_OFFS+1
_upt_getting_bits:
	dec		<PACKFIRE_LEN
	bpl		_upt_cont_get_bit
	pf_add16_zp PACKFIRE_OFFS,PACKFIRE_DIST
	rts
_upt_cont_get_bit:
	bsr		_upt_get_bit
	rol		<PACKFIRE_OFFS
	rol		<PACKFIRE_OFFS+1
	bra		_upt_getting_bits
_upt_jump:
	jmp		_upt_after_copy
_upt_table_len:  .db  4, 2, 4
