! apLib decruncher for SuperH-2 (Sega 32X / Saturn)
!
! Based on the M68000 version by MML 2010
! Size optimized (164 bytes) by Franck "hitchhikr" Charlet. 
!
! SH2 version (210 bytes) by Mic 2010

	.section .text
	.align 1
	
	.global		_aplib_decrunch
	.global		aplib_decrunch_end

! In: r4 = compressed data, r5 = destination
!
_aplib_decrunch:
	mov.l	r8,@-r15
	sts.l	pr,@-r15

    	mov	#1,r6		! Initialize bits counter
copy_byte:
	mov.b	@r4+,r1
	mov.b	r1,@r5
	add	#1,r5
next_sequence_init:
	mov	#0,r7		! Initialize LWM
next_sequence:
	bsr   	get_bit		! if bit sequence is %0..., then copy next byte
	nop
	bf	copy_byte
	bsr	get_bit
	nop
	bf	code_pair	! if bit sequence is %10..., then is a code pair
	bsr	get_bit
	mov	#0,r0
	bf	short_match	! if bit sequence is %110..., then is a short match
	
       ! The sequence is %111..., the next 4 bits are the offset (0-15)
	bsr	get_bit
        mov	r5,r1
	bsr	get_bit
	addc	r0,r0
	bsr	get_bit
	addc	r0,r0
	bsr	get_bit
	addc	r0,r0
	addc	r0,r0
	
	tst	r0,r0
	bt	write_byte	! if offset == 0, then write 0x00
	
        ! If offset != 0, then write the byte on destination - offset
        sub	r0,r1
        mov.b	@r1,r0
write_byte:
        mov.b	r0,@r5
        bra	next_sequence_init
        add	#1,r5

! Code pair %10...
code_pair:     
	bsr	decode_gamma
	nop
	mov	r2,r0
	dt	r0
	dt	r0
	bf	normal_code_pair
	tst	r7,r7
	bf	normal_code_pair
	bsr	decode_gamma
	mov	r8,r0		! offset = old_offset
	bra	copy_code_pair
	nop
normal_code_pair:
	add	r7,r0
	dt	r0
	mov.b	@r4+,r1
	shll8	r0
	extu.b	r1,r1
	bsr	decode_gamma
	or	r1,r0
	mov	#0x7D,r1
	shll8	r1
	cmp/hs	r1,r0
	bf	compare_1280
	add	#1,r2
compare_1280:
	mov	#5,r1
	shll8	r1
	cmp/hs	r1,r0
	bf	compare_128
	bra	continue_short_match
	add	#1,r2
compare_128:
	mov	#0x7F,r1
	cmp/hi	r1,r0
	bt	continue_short_match
	bra	continue_short_match
	add	#2,r2

! get_bit: Get bits from the crunched data (r3) and insert the most significant bit in the carry flag.
get_bit: 
	dt	r6
	bf	still_bits_left
	mov	#8,r6
	mov.b	@r4+,r3
	shll16	r3
	shll8	r3
still_bits_left:
	rts
	shll	r3		
	
! decode_gamma: Decode values from the crunched data using gamma code
decode_gamma:
	sts	pr,r1		! Save return address
	mov   	#1,r2
get_more_gamma:
	bsr   	get_bit
	nop
	bsr	get_bit
	addc	r2,r2
	bt	get_more_gamma
	jmp	@r1		! Return
	nop
	
! Short match %110...
short_match:  
	mov	#1,r2
	mov.b	@r4+,r0		! Get offset (offset is 7 bits + 1 bit to mark if copy 2 or 3 bytes) 
	extu.b	r0,r0
	shlr	r0
	addc	r2,r2		! r2 becomes either 2 or 3
	tst	r0,r0
	bt	end_decrunch
continue_short_match:
	mov	r0,r8		! old_offset = offset
copy_code_pair:   
	mov	r5,r1
	sub	r0,r1
loop_do_copy:
	mov.b	@r1+,r0
	mov.b	r0,@r5
	dt	r2
	bf/s	loop_do_copy
	add	#1,r5
	
        bra   	next_sequence   ! Process next sequence
	mov	#1,r7		! LWM = 1
	
end_decrunch:
	lds.l	@r15+,pr
	mov.l	@r15+,r8	
	rts
	nop

aplib_decrunch_end:
