// Useful macros
#define	UPPER_HW(n)	( ( -(( ( (n) >> 16) & 0x0000FFFF) >= 0x00008000)*(1 + ((~(n)) >> 16) & 0x0000FFFF) ) | ((( ( (n) >> 16) & 0x0000FFFF) < 0x00008000)*( ((n) >> 16) & 0x0000FFFF) ) )
#define	LOWER_HW(n)	( -(( (n) & 0x0000FFFF) >= 0x00008000)*(1 + ~((n) & 0x0000FFFF) ) | ( ( (n) & 0x0000FFFF) < 0x00008000)*( (n) & 0x0000FFFF) )
#define	FUNC_ADDR(f)	( ((unsigned long*)f)[0] )
#define	FUNC_RTOC(f)	( ((unsigned long*)f)[1] )

// Extended mnemonics
#define	srwi(rt,ra,n)		rlwinm	rt,ra,32-n,n,31
#define	srwi_(rt,ra,n)		rlwinm.	rt,ra,32-n,n,31
#define	slwi(rt,ra,n)		rlwinm	rt,ra,n,0,31-n
#define	slwi_(rt,ra,n)		rlwinm.	rt,ra,n,0,31-n
#define	rrwinm(rt,ra,a,b,c)	rlwinm	rt,ra,32-a,b,c

// Macros for manipulating the condition register fields
#define	cr0_LT	0
#define	cr0_GT	1
#define	cr0_EQ	2
#define	cr0_SO	3
#define	cr1_LT	4
#define	cr1_GT	5
#define	cr1_EQ	6
#define	cr1_SO	7
#define	cr2_LT	8
#define	cr2_GT	9
#define	cr2_EQ	10
#define	cr2_SO	11
#define	cr3_LT	12
#define	cr3_GT	13
#define	cr3_EQ	14
#define	cr3_SO	15
#define	cr4_LT	16
#define	cr4_GT	17
#define	cr4_EQ	18
#define	cr4_SO	19
#define	cr5_LT	20
#define	cr5_GT	21
#define	cr5_EQ	22
#define	cr5_SO	23
#define	cr6_LT	24
#define	cr6_GT	25
#define	cr6_EQ	26
#define	cr6_SO	27
#define	cr7_LT	28
#define	cr7_GT	29
#define	cr7_EQ	30
#define	cr7_SO	31

// SPR registers
#define	RTCU_R		4	// For reading, only on 601
#define	RTCL_R		5	// For reading, only on 601
#define	DSISR		18
#define	DAR			19
#define	RTCU_W		20	// For writing, only on 601
#define	RTCL	_W		21	// For writing, only on 601
#define	DEC			22
#define	SDR1		25
#define	SRR0		26
#define	SRR1		27
#define	TBL_R		268	// For reading, not on 601
#define	TBU_R		269	// For reading, not on 601
#define	SPRG0		272
#define	SPRG1		273
#define	SPRG2		274
#define	SPRG3		275
#define	EAR			282
#define	TBL_W		284	// For writing, not on 601
#define	TBU_W		285	// For writing, not on 601
#define	PVR			287
#define	IBAT0U		528
#define	IBAT0L		529
#define	IBAT1U		530
#define	IBAT1L		531
#define	IBAT2U		532
#define	IBAT2L		533
#define	IBAT3U		534
#define	IBAT3L		535
#define	DBAT0U		536
#define	DBAT0L		537
#define	DBAT1U		538
#define	DBAT1L		539
#define	DBAT2U		540
#define	DBAT2L		541
#define	DBAT3U		542
#define	DBAT3L		543
#define	DABR		1013
#define	THRM1		1020
#define	THRM2		1021
#define	THRM3		1022

#define	mfpvr(rt)			mfspr	rt,PVR
#define	mtdbatu(bat,ra)	mtspr	(DBAT0U+2*bat),ra
#define	mfdbatu(rt,bat)		mfspr	rt,(DBAT0U+2*bat)
#define	mtdbatl(bat,ra)		mtspr	(DBAT0L+2*bat),ra
#define	mfdbatl(rt,bat)		mfspr	rt,(DBAT0L+2*bat)
#define	mtibatu(bat,ra)		mtspr	(IBAT0U+2*bat),ra
#define	mfibatu(rt,bat)		mfspr	rt,(IBAT0U+2*bat)
#define	mtibatl(bat,ra)		mtspr	(IBAT0L+2*bat),ra
#define	mfibatl(rt,bat)		mfspr	rt,(IBAT0L+2*bat)
#define	mfsdr1(rt)		mfspr	rt,SDR1
#define	mtsdr1(ra)		mtspr	SDR1,ra
#define	mtsprg(sprg,ra)	mtspr	(SPRG0+sprg),ra
#define	mfsprg(rt,sprg)	mfspr	rt,(SPRG0+sprg)
#define	mtcr(ra)			mtcrf	0xFF,ra
#define	mfsrr0(rt)		mfspr	rt,26
#define	mtsrr0(ra)		mtspr	26,ra
#define	mfsrr1(rt)		mfspr	rt,27
#define	mtsrr1(ra)		mtspr	27,ra
#define	mfsprg1(rt)		mfspr	rt,273
#define	mtsprg1(ra)		mtspr	273,ra
#define	mfsprg2(rt)		mfspr	rt,274
#define	mtsprg2(ra)		mtspr	274,ra
#define	mfdsisr(rt)		mfspr	rt,18
#define	mfdar(rt)			mfspr	rt,19
#define	mtiabr(ra)		mtspr	1010,ra
#define	mfiabr(rt)			mfspr	rt,1010
#define	mthid0(ra)		mtspr	1008,ra
#define	mfhid0(rt)		mfspr	rt,1008

inline asm unsigned long	_getSR(register unsigned long n) {slwi(r3,r3,28); mfsrin r3,r3; blr;}
inline asm void			_setSR(register unsigned long n,register unsigned long val) {slwi(r3,r3,28); isync; mtsrin r4,r3; isync; blr;}
inline asm unsigned long	_getSDR1(void) {mfsdr1(r3); blr;}
inline asm void			_setSDR1(register unsigned long n) {sync; mtsdr1(r3); sync; blr;}
inline asm void			_dcbf(register void* addr)
{
	sync;
	dcbf r0,r3;
	sync;
	blr;
}

inline asm void			_icbi(register void* addr)
{
	sync;
	icbi	r0,r3;
	sync;
	isync;
	blr;
}

inline asm void			_setDBAT0L(register unsigned long n) {mtdbatl(0,r3); blr;}
inline asm void			_setDBAT0U(register unsigned long n) {sync; mtdbatu(0,r3); sync; blr;}
inline asm unsigned long	_getDBAT0L(void) {mfdbatl(r3,0); blr;}
inline asm unsigned long	_getDBAT0U(void) {mfdbatu(r3,0); blr;}
inline asm void			_setDBAT1L(register unsigned long n) {mtdbatl(1,r3); blr;}
inline asm void			_setDBAT1U(register unsigned long n) {sync; mtdbatu(1,r3); sync; blr;}
inline asm unsigned long	_getDBAT1L(void) {mfdbatl(r3,1); blr;}
inline asm unsigned long	_getDBAT1U(void) {mfdbatu(r3,1); blr;}
inline asm void			_setDBAT2L(register unsigned long n) {mtdbatl(2,r3); blr;}
inline asm void			_setDBAT2U(register unsigned long n) {sync; mtdbatu(2,r3); sync; blr;}
inline asm unsigned long	_getDBAT2L(void) {mfdbatl(r3,2); blr;}
inline asm unsigned long	_getDBAT2U(void) {mfdbatu(r3,2); blr;}
inline asm void			_setDBAT3L(register unsigned long n) {mtdbatl(3,r3); blr;}
inline asm void			_setDBAT3U(register unsigned long n) {sync; mtdbatu(3,r3); sync; blr;}
inline asm unsigned long	_getDBAT3L(void) {mfdbatl(r3,3); blr;}
inline asm unsigned long	_getDBAT3U(void) {mfdbatu(r3,3); blr;}
inline asm unsigned long	_getPVR(void) {mfpvr(r3); blr;}
inline asm unsigned long	_getMSR(void) {mfmsr r3; blr;}
inline asm void			_setMSR(register unsigned long) {sync; mtmsr r3; isync; blr;}

inline asm void			_sc(void) {sc; blr;}

inline asm void*		_findStackBase(void)	// Find the highest address contained in this stack!
{
	mr		r4,sp;
loop:
	lwz		r4,0(r4);
	cmpwi	r4,0;
	beq		@out;
	mr		r3,r4;
	b		loop;
@out:
	blr;
}

void*				_getPC(void);			// Returns the Program Counter (the LR for this function call, actually)

inline asm void			_tlbie(register unsigned long logAddr)
{
	machine 603;
	
	sync;
	tlbie r3;
	sync;
	tlbsync;
	sync;
	
	blr;
}

inline asm unsigned long long	_getClock(void)
{
	mfpvr(r3);
	rlwinm	r3,r3,0,16,31;
	cmpwi	r3,1;
	beq-		@RTCTime;
@TBTime:
	mfspr	r3,TBU_R;
	mfspr	r4,TBL_R;
	mfspr	r5,TBU_R;
	cmpw	r3,r5;
	bne		@TBTime;
	blr;
@RTCTime:
	mfspr	r3,RTCU_R;
	mfspr	r4,RTCL_R;
	mfspr	r5,RTCU_R;
	cmpw	r3,r5;
	bne		@TBTime;
	blr;
}

#define SET_FLD(bit1,bit2,val)		( ((unsigned long)((unsigned long)val) << (31UL - (bit2))) & ( (unsigned long)((1UL << (32 - ((unsigned long)bit1))) - 1UL) & ~( (1UL << (31UL - ((unsigned long)bit2))) - 1UL)) )

#define ADDI(regt,regs,val)		(SET_FLD(0,5,14) | SET_FLD(6,10,regt) | SET_FLD(11,15,regs) | SET_FLD(16,31,val))
#define BLRL					(SET_FLD(0,5,19) | SET_FLD(6,10,20) | SET_FLD(21,30,16) | SET_FLD(31,31,1))
#define LWZ(regd,offset,rega)		(SET_FLD(0,5,32) | SET_FLD(6,10,regd) | SET_FLD(11,15,rega) | SET_FLD(16,31,offset))
#define MFSPR(reg,sprg)			(SET_FLD(0,5,31) | SET_FLD(6,10,reg) | SET_FLD(11,15,(sprg & 0x1F)) | SET_FLD(16,20,((sprg >> 5) & 0x1F)) | SET_FLD(21,30,339))
#define MTSPR(sprg,reg)			(SET_FLD(0,5,31) | SET_FLD(6,10,reg) | SET_FLD(11,15,(sprg & 0x1F)) | SET_FLD(16,20,((sprg >> 5) & 0x1F)) | SET_FLD(21,30,467))
#define MFLR(reg)				MFSPR(reg,8)
#define MFMSR(reg)				(SET_FLD(0,5,31) | SET_FLD(6,10,reg) | SET_FLD(21,30,83))
#define MTLR(reg)				MTSPR(8,reg)
#define MTMSR(reg)				(SET_FLD(0,5,31) | SET_FLD(6,10,reg) | SET_FLD(21,30,146))
#define ORI(regt,regs,val)		(SET_FLD(0,5,24) | SET_FLD(6,10,regt) | SET_FLD(11,15,regs) | SET_FLD(16,31,val))
#define RFI					(SET_FLD(0,5,19) | SET_FLD(21,30,50))
#define STWU(regs,offset,regt)	(SET_FLD(0,5,37) | SET_FLD(6,10,regs) | SET_FLD(11,15,regt) | SET_FLD(16,31,offset))
#define SYNC					(SET_FLD(0,5,31) | SET_FLD(21,30,598))