;RNC2 pro-unpacker.

		include	..\spec_psx\tomb.inc

		global	unpack
		global	IPROF_Init
		global	IPROF_Clear
		global	IPROF_Start
		global	IPROF_Stop
		global	S_MemSet
		global	S_MemCpy
		global	S_LongMemCpy
		global	GabMemoryCardHeader
;##		global	memcpy
;##		global	memset

		xref	gp_start_address			;GP register address (start of .sbss section for handling vars off (GP)
		xref	SetRCnt
		xref	StartRCnt
		xref	StopRCnt

input	equr	a0
output	equr	a1

cflag	equr	t0
bitbuf	equr	t1
bit24	equr	t2
temp	equr	t3
len 	equr	t4
pos 	equr	t5
temp2	equr	t6
bit31	equr	t7
nine	equr	a2
temp3	equr	a3

GetBitA macro
		srl 	cflag,bitbuf,31
		endm

GetBitB macro
		sll 	bitbuf,bitbuf,1
		endm

GetBit	macro
		GetBitA
		GetBitB
		endm

ReLoadA macro
		lbu 	bitbuf,0(input)
		addiu	input,input,1
		srl 	cflag,bitbuf,7
		sll 	bitbuf,bitbuf,25
		endm

ReLoadB macro
		or		bitbuf,bitbuf,bit24
		endm

ReLoad	macro
		ReLoadA
		ReLoadB
		endm

GetRawA macro
		lbu 	temp,0(input)
		addiu	input,input,1
		sb		temp,0(output)
		endm

GetRawB macro
		addiu	output,output,1
		endm

GetRaw	macro
		GetRawA
		GetRawB
		endm

b		macro
		beq 	r0,r0,\1
		endm

ChkRel	macro
		beq 	bitbuf,bit31,\1
		endm

unpack	addu	v0,a1,r0		;keep output for calulating length
		lui 	bit24,$0100
		lui 	bit31,$8000
		addiu	nine,r0,9
;;;;	addiu	a0,a0,18		;don't skip the RNC2 header, because it is now removed
		ReLoad					;*** discard 1 ***
;		GetBitA 				;*** discard 2 ***
		b		xLoop
		GetBitB 				;*** discard 2 ***

Fetch0	ReLoadA
		b		Back0
		ReLoadB

Fetch1	ReLoadA
		b		Back1
		ReLoadB

Fetch2	ReLoadA
		b		Back2
		ReLoadB

Fetch3	ReLoadA
		b		Back3
		ReLoadB

Fetch4	ReLoadA
		b		Back4
		ReLoadB

Fetch5	ReLoadA
		b		Back5
		ReLoadB

Fetch6	ReLoadA
		b		Back6
		ReLoadB

Fetch7	ReLoadA
		b		Back7
		ReLoadB

Raw 	addiu	len,r0,3
x4Bits	GetBitA
		ChkRel	Fetch0
		GetBitB
Back0	sll 	pos,pos,1
		or		pos,pos,cflag
		bne 	len,r0,x4Bits
		addiu	len,len,-1
		addiu	len,pos,3		;bug in original ARM code!
		sll 	len,len,2
		addu	len,input,len
Raw2	lwr 	temp,0(input)
		lwl 	temp,3(input)
		addiu	input,input,4
		swr 	temp,0(output)
		swl 	temp,3(output)
		bne 	input,len,Raw2
		addiu	output,output,4
		b		xLoopB
		GetBitA

GetLen	GetBitA
GetLenB ChkRel	Fetch1
		GetBitB
Back1	sll 	len,len,1
		or		len,len,cflag
		GetBitA
		ChkRel	Fetch2
		GetBitB
Back2	beq 	cflag,r0,CopyB
		GetBitA
		addiu	len,len,-1
		ChkRel	Fetch3
		GetBitB
Back3	sll 	len,len,1
		or		len,len,cflag
		beq 	len,nine,Raw
		nop 					;bummer

Copy	GetBitA
CopyB	ChkRel	Fetch4
		GetBitB
Back4	beq 	cflag,r0,BDisp2
		GetBitA
		ChkRel	Fetch5
		GetBitB
Back5	sll 	pos,pos,1
		or		pos,pos,cflag
		GetBitA
		ChkRel	Fetch6
		GetBitB
Back6	bne 	cflag,r0,BigDisp
		nop 					;bummer
		bne 	pos,r0,BDisp
		nop 					;bummer
		addiu	pos,pos,1
Another GetBitA
AnothB	ChkRel	Fetch7
		GetBitB
Back7	sll 	pos,pos,1
		or		pos,pos,cflag

BDisp	sll 	pos,pos,8
BDisp2	lbu 	temp,0(input)
		addiu	input,input,1
		or		pos,pos,temp
		sub 	temp,output,pos
		addiu	temp,temp,-1
		andi	temp2,len,1
		beq 	temp2,r0,BDisp3
		srl 	len,len,1
		lbu 	temp2,0(temp)
		addiu	temp,temp,1
		sb		temp2,0(output)
		addiu	output,output,1
BDisp3	sll 	len,len,1
		bne 	pos,r0,BDisp5
		addu	len,output,len
		lbu 	pos,0(temp)
BDisp4	addiu	output,output,2
		sb		pos,-2(output)
		bne 	output,len,BDisp4
		sb		pos,-1(output)
		b		xLoopB
		GetBitA
BDisp5	lbu 	temp2,0(temp)
		lbu 	temp3,1(temp)
		sb		temp2,0(output)
		sb		temp3,1(output)
		addiu	output,output,2
		bne 	output,len,BDisp5
		addiu	temp,temp,2
		b		xLoopB
		GetBitA

GetBits ReLoadA
		bne 	cflag,r0,String
		ReLoadB
xByte	GetRaw
xLoop	GetBitA
xLoopB	bne 	cflag,r0,Chkz
		GetBitB
		GetRaw
		GetBitA
		beq 	cflag,r0,xByte
		GetBitB
Chkz	beq 	bitbuf,r0,GetBits
String	addiu	len,r0,2		;check this
		addiu	pos,r0,0
		GetBitA
		ChkRel	Fetch8
		GetBitB
Back8	beq 	cflag,r0,GetLenB
		GetBitA
		ChkRel	Fetch9
		GetBitB
Back9	beq 	cflag,r0,BDisp2
		nop 					;bummer
		addiu	len,len,1
		GetBitA
		ChkRel	Fetch10
		GetBitB
Back10	beq 	cflag,r0,Copy
		nop 					;bummer
		lbu 	len,0(input)
		addiu	input,input,1
		beq 	len,r0,Finish
		GetBitA 				;too cool by far
		b		CopyB
		add 	len,len,8

BigDisp GetBitA
		ChkRel	Fetch11
		GetBitB
Back11	sll 	pos,pos,1
		or		pos,pos,cflag
		ori 	pos,pos,4
		GetBitA
		ChkRel	Fetch12
		GetBitB
Back12	bne 	cflag,r0,BDisp
		nop 					;bummer
		b		AnothB
		GetBitA

Fetch8	ReLoadA
		b		Back8
		ReLoadB

Fetch9	ReLoadA
		b		Back9
		ReLoadB

Fetch10 ReLoadA
		b		Back10
		ReLoadB

Fetch11 ReLoadA
		b		Back11
		ReLoadB

Fetch12 ReLoadA
		bne 	cflag,r0,BDisp
		ReLoadB
		b		AnothB
		GetBitA

Finish	GetBitA
		bne 	bitbuf,bit31,ChkEnd
		GetBitB
		ReLoad
ChkEnd	bne 	cflag,r0,xLoopB
		GetBitA 		;won't hurt
		jr		ra
		sub 	v0,output,v0	;how cool?

;*** instruction profiler stuff ***

		if		1

IPROF_SPEED		equ	500		;RCnt target
IPROF_RCNT		equ	0		;RCnt to use
IPROF_INTBIT	equ	$10		;Interrupt bit in $1070... $10,$20,$40,$01
IPROF_BUFFER	equ	$400000	;Profile data goes here
IPROF_PATCHLOC	equ	$0a00	;Where the main patch goes

IPROF_Patch
		mfc0	k0,cause
		beq		r0,r0,*+((IPROF_PATCHLOC-$0080)-4)
		andi	k0,$043c

IPROF_Patch2
		xori	k0,$0400
		bnz		k0,.old
		nop
		sw		v0,$0090(r0)
		sw		k1,$0094(r0)
		lui		k1,$1f80
		lw		v0,$1070(k1)
		lw		k0,$1074(k1)
		andi	v0,IPROF_INTBIT
		bz		v0,.old2
		andi	k0,IPROF_INTBIT
		bz		k0,.old2
		mfc0	k0,cause
		mfc0	v0,epc
		srl		k0,31				;get delay slot flag
		sll		k0,2				;*4
		addu	v0,k0				;form actual exception addr
		sll		v0,3
		srl		v0,3				;mask seg bits
		srl		k0,v0,25			;25 bits = 2Megs; see if any other bits are set (ie out of range)
		bnz		k0,.out				;if out of range (ie ROM) hit offset 0 in buffer (shows up as "System Code")
		li		k0,IPROF_BUFFER		;addr of profile data buffer
		addu	k0,v0				;make profile buffer addr
.out	lw		v0,(k0)				;get count for this addr
		nop
		inc		v0					;increment count
		sw		v0,(k0)				;stash count back in profile buffer
		mfc0	k0,epc
		li		v0,~IPROF_INTBIT
		sw		v0,$1070(k1)
		lw		v0,(k0)				;get instruction
		nop
		srl		v0,25				;get opcode/CO bits from instruction
		subiu	v0,$25				;$25 means cop2+CO, ie a GTE operation
		bnz		v0,.notgte			;skip inc.w if not a GTE op
		nop
		inc.w	k0					;skip the GTE op
.notgte	lw		v0,$0090(r0)		;restore v0
		lw		k1,$0094(r0)
		nop
		addu	r0,v0,k1
		jr		k0					;return from exception
		rfe							;restore interrupt enable & kernel/user mode
.old2	lw		v0,$0090(r0)
		lw		k1,$0094(r0)
.old
IPROF_Patch2_End

IPROF_Init
		lui		k1,$1f80
		mac.la	v0,IPROF_Patch2
		li		t0,IPROF_Patch2_End-IPROF_Patch2+IPROF_PATCHLOC
		li		v1,IPROF_PATCHLOC
.loop	lw		at,(v0)
		inc.w	v0
		inc.w	v1
		bne		v1,t0,.loop
		sw		at,-4(v1)
		lw		t0,$80(r0)
		lw		t1,$84(r0)
		lw		t2,$88(r0)
		lw		t3,$8c(r0)
		sw		t0,$00(v1)
		sw		t1,$04(v1)
		sw		t2,$08(v1)
		sw		t3,$0c(v1)
		mac.la	v0,IPROF_Patch
		lw		t0,$00(v0)
		lw		t1,$04(v0)
		lw		t2,$08(v0)
		sw		t0,$80(r0)
		sw		t1,$84(r0)
		sw		t2,$88(r0)
		sw		r0,$8c(r0)
		mac.li	a0,$f2000000+IPROF_RCNT
		li		a1,IPROF_SPEED
		j		SetRCnt
		li		a2,$1000

IPROF_Clear
		li		a0,IPROF_BUFFER
		li		a1,IPROF_BUFFER+$00200000
.loop	inc.w	a0
		bne		a0,a1,.loop
		sw		r0,-4(a0)
		jr		ra
		nop

IPROF_Start
		lui		a0,$f200
		j		StartRCnt
		or		a0,IPROF_RCNT

IPROF_Stop
		lui		a0,$f200
		j		StopRCnt
		or		a0,IPROF_RCNT
		endif

		if		0						;currently a wierd bug exists

; OptimiseOTagR (for reverse OTs only !!!) by Dude
; a0: Address of OT
; a1: Number of OT entries
;
; returns number of entries in OT skipped

	global	OptimiseOTagR

OptimiseOTagR
	sll 	a0,8   			; and ot address with 00ffffff
	srl 	a0,8
	sll 	a1,2
	dec.w	a1
	addu	a1,a0  			; calc start address (remember OT is reverse)
	addiu	v1,a0,4			; extra for loop2 terminate stress
	clr 	at

	lw  	v0,(a1)			; get an OT entry
.loop1	dec.w	a1						; address next entry
	bne 	v0,a1,.next 			; skip if it pointed out of the OT
	addiu	a3,a1,4 				; else remember where the first grim entry was

.loop2	lw		v0,(a1) 				; get next OT entry
	beq 	a1,v1,.exit2			; run out of OT -> exit the loop
	dec.w	a1						; address next entry
	beq 	v0,a1,.loop2			; loop if it's still pointing to next OT entry
	inc 	at						; keep a handy skip counter instead of doing a nop!!!
.exit2	sw		v0,(a3) 				; store handily loaded pointer into last kewl OT pos

.next	bne 	a1,a0,.loop1			; loop until end of OT
	lw		v0,(a1) 				; (getting next OT entry in delay slot :)
	ret
	move	v0,at
	endif

		opt		at+

;void	S_MemSet( void *dest, unsigned char value, int length );

; DEL_memset slot in replacement for the libs version (because that was so bleakly slow)
;
;
; r4 = address
; r5 = byte to fill with (gets made into a long)
; r6 = number of bytes to fill
;

memset
S_MemSet
		beq r6,r0,.exit 				;length == 0?
		sll r15,r5,8					;r15 = (fillbyte<<8)
		mac.ble r6,3,.just_fill_as_bytes;length <= 3 ??
		or r5,r5,r15					;fillbyte+=(fillbyte<<8)
		sll r15,r5,16					;fillword=fillword<<16
		or r5,r5,r15					;r5 = fillong... :)

		and r15,r4,3					;r15 = address&3
		beq r15,r0,.fill_longs			;on an even boundary ??
		or r14,r0,4 					;r14 = 3
		subu r15,r14,r15				;r15 = 4-(address-(address&3))
		subu r6,r6,r15					;length = length-(address&3)

.bloop	sb r5,(r4)						;fill byte...
		add r15,r15,-1					;loop counter-=1
		bne r15,r0,.bloop				;loop fill bytes...
		add r4,r4,1 					;destination buffer += 1


.fill_longs
		sra r15,r6,2					;r15 = number of longs to fill
		beq r15,r0,.cont				;zero longs ??
		and r6,r6,3 					;r6 = (length&3) for filling anything at the end...

.lloop	sw r5,(r4)
		add r15,r15,-1					;loop counter-=1
		bne r15,r0,.lloop				;loop fill bytes...
		add r4,r4,4 					;destination buffer += 1

.cont	beq r6,r0,.exit
		nop

;fill final R6 bytes...
.just_fill_as_bytes
		sb r5,(r4)						;fill byte...
		add r6,r6,-1					;loop counter-=1
		bne r6,r0,.just_fill_as_bytes	;loop fill bytes...
		add r4,r4,1 					;destination buffer += 1

.exit	jr		ra						;exit.
		nop 							;






		opt m-



;ok, I checked the code... S_LongMemCpy only seems to be called with a length of 12 LONGS... :)
;but, what the hey... lets make it function properly...
;
;
; r4 = dest
; r5 = source
; r6 = number of LONGS to copy...
;

S_LongMemCpy
		blez	r6,.exit				;length <= 0 ??
		srl 	r2,r6,2 				;r2 = length/4

		beq 	r2,r0,.slowloop 		;is there enough data to use the fast loop (less than 4 longs) ??
		andi	r3,r6,3 				;r3 = length&3

; copy 4 longs at a time (for speed)
.fastloop
		lw		r8,(r5) 				;r8 = source long
		lw		r9,4(r5)				;r9 = source long
		lw		r10,8(r5)				;r10 = source long
		lw		r11,12(r5)				;r11 = source long
		addiu	r5,r5,16				;source++
		addiu	r2,r2,-1				;length--
		sw		r8,(r4) 				;stash long in dest
		sw		r9,4(r4)				;stash long in dest
		sw		r10,8(r4)				;stash long in dest
		sw		r11,12(r4)				;stash long in dest
		bgtz	r2,.fastloop			;length > 0 ??
		addiu	r4,r4,16				;dest++

		beq 	r3,r0,.exit 			;anything else left to copy slowly?
		nop

.slowloop
		lw		r8,(r5) 				;r8 = source long
		addiu	r5,r5,4 				;source++
		addiu	r3,r3,-1				;length--
		sw		r8,(r4) 				;stash long in dest
		bgtz	r3,.slowloop			;length > 0 ??
		addiu	r4,r4,4 				;dest++

.exit	jr		ra						;exit me...
		nop


; original slow version...

;S_LongMemCpy_asm
;		blez	r6,.exit				;length <= 0 ??
;		nop
;.loop	lw		r2,(r5) 				;r2 = source long
;		addiu	r5,r5,4 				;source++
;		addiu	r6,r6,-1				;length--
;		sw		r2,(r4) 				;stash long in dest
;		bgtz	r6,.loop				;length > 0 ??
;		addiu	r4,r4,4 				;dest++
;.exit	jr		ra						;exit me...
;		nop










;
; r4 = dest
; r5 = source
; r6 = number of BYTES to copy...
;

memcpy
S_MemCpy
		blez	r6,.exit				;length <= 0 ??
;		nop 							;<< not needed... because no-one will call this with a length of 0!!
.loop	lbu 	r2,(r5) 				;r2 = source byte
		addiu	r5,r5,1 				;source++
		addiu	r6,r6,-1				;length--
		sb		r2,(r4) 				;stash byte in dest
		bgtz	r6,.loop				;length > 0 ??
		addiu	r4,r4,1 				;dest++
.exit	jr		ra						;exit me...
		nop

		opt m+

;----------------------------

		cnop	0,4

GabMemoryCardHeader
		db		'S','C'
		db		$11
		db		2
		db		$82,$73 ;T		1
		db		$82,$8f ;o		2
		db		$82,$8d ;m		3
		db		$82,$82 ;b		4
		db		$81,$40 ;space		5
		db		$82,$71 ;R		6
		db		$82,$81 ;a		7
		db		$82,$89 ;i		8
		db		$82,$84 ;d		9
		db		$82,$85 ;e		10
		db		$82,$92 ;r		11
		db		$81,$40	;space		12
		db		$82,$68	;I		13
		db		$82,$68	;I		14
		db		$82,$68	;I		15
		dh		0	;		16
		dch 	32-16,0
		dcb 	28,0
;;; 	incbin	..\specific\memicon.bin
;;;		incbin	..\spec_psx\memicon.bin
		incbin	..\spec_psx\card.pal
		incbin	..\spec_psx\card.pic

		cnop	0,4

;;;		include c:\dev\psx\disasm.mip
