llasm.s 4.31 KB
#include "regdef.h"

/* long long __ll_mul (long long a, long long b) */

#ifdef _MIPSEL
#	define RLSW v0
#	define RMSW v1
#	define ALSW a0
#	define AMSW a1
#	define BLSW a2
#	define BMSW a3
#else /* _MIPSEB */
#	define RMSW v0
#	define RLSW v1
#	define AMSW a0
#	define ALSW a1
#	define BMSW a2
#	define BLSW a3
#endif

.text

/* note that result of AMSW * BMSW overflows 64bits, so it is ignored. */

.globl __ll_mul
.ent __ll_mul
__ll_mul:
	.frame	sp, 0, ra
	multu	ALSW, BLSW
	mflo	RLSW
	mfhi	RMSW
	multu	AMSW, BLSW
	mflo	t0
	addu	RMSW, t0
	multu	ALSW, BMSW
	mflo	t0
	addu	RMSW, t0
	j	ra
.end __ll_mul


/* __ull_divrem (unsigned long long *quotient, *remainder, dividend, divisor) */

#	define MSH 0
#	define LSH 2
#	define MQUO 0(a0)
#	define LQUO 4(a0)
#	define MREM 0(a1)
#	define LREM 4(a1)
#	define MDEN a2
#	define LDEN a3
#	define MSOR 16(sp)
#	define LSOR 20(sp)

/* ulldivrem (unsigned long long *quotient, unsigned long long *remainder, 
 *		unsigned long long dividend, unsigned long long divisor); */
/* unsigned division */
/* assume that dividend is 64bit positive value;
 * divisor is 16bit positive value. */
.globl __ull_divrem_6416
.ent __ull_divrem_6416
__ull_divrem_6416:
	.frame	sp, 0, ra
	move	t0, LDEN	/* dividend */
	move	t1, MDEN
	lw	t2, LSOR	/* divisor */
	lw	t3, MSOR
	divu	zero, t0, t2	/* early start for first case */
	/* test if both dividend and divisor are 32-bit values */
	sra	t4, t0, 31
	bnez	t3, 3f	/* divisor not 32-bit */
	/* divisor is 32-bit */
	bnez	t1, 1f	/* dividend not 32-bit */
	/* simply use 32-bit divide instruction */
	mflo	v0
	mfhi	t4
	sw	v0, LQUO
	sw	zero, MQUO
	sw	t4, LREM
	sw	zero, MREM
	j	ra

	/* divisor 32-bit, dividend not */
1:	srl	t4, t2, 16
	bne	t4, 0, 3f

	/* dividing 64-bit positive value by 16-bit unsigned value */
#ifdef _MIPSEL
	sll	v0, MDEN, 16
#else
	move	v0, MDEN
#endif
	srl	v0, v0, 16	/* get 16-bit MSH value from MDEN */
	divu	zero, v0, t2
	mflo	v1
	mfhi	v0
	sh	v1, MSH+MQUO
	sll	v0, 16
#ifdef _MIPSEB
	sll	t0, MDEN, 16
#else
	move	t0, MDEN
#endif
	srl	t0, t0, 16	/* get 16-bit LSH value from MDEN */
	or	v0, t0
	divu	zero, v0, t2
	mflo	v1
	mfhi	v0
	sh	v1, LSH+MQUO
	sll	v0, 16
#ifdef _MIPSEL
	sll	t0, LDEN, 16
#else
	move	t0, LDEN
#endif
	srl	t0, t0, 16	/* get 16-bit MSH value from LDEN */
	or	v0, t0
	divu	zero, v0, t2
	mflo	v1
	mfhi	v0
	sh	v1, MSH+LQUO
	sll	v0, 16
#ifdef _MIPSEB
	sll	t0, LDEN, 16
#else
	move	t0, LDEN
#endif
	srl	t0, t0, 16	/* get 16-bit LSH value from LDEN */
	or	v0, t0
	divu	zero, v0, t2
	mflo	v1
	mfhi	v0
	sh	v1, LSH+LQUO
	sw	zero, MREM
	sw	v0, LREM
	j	ra

	/* if dividend < divisor then quo = 0, rem = dividend */
3:	lw	t0, MSOR
	bgtu	MDEN, t0, 36f
	bltu	MDEN, t0, 32f
	/* MDEN == MSOR */
	lw	t0, LSOR
	bgeu	LDEN, t0, 36f
32:	sw	zero, LQUO
	sw	zero, MQUO
	sw	LDEN, LREM
	sw	MDEN, MREM
	j	ra

	/* dividend or divisor too big; have to do division the hard way */
36:	break	0
.end __ull_divrem_6416

/* ulldivrem (unsigned long long *quotient, unsigned long long *remainder, 
 *		unsigned long long dividend, unsigned long long divisor); */
/* unsigned division */
/* assume that dividend and divisor both fit in 53 bits,
 * so do double fp divide. */
.globl __ull_divrem_5353
.ent __ull_divrem_5353
__ull_divrem_5353:
	.frame	sp, 0, ra
	move	t0, LDEN	/* dividend */
	move	t1, MDEN
	lw	t2, LSOR	/* divisor */
	lw	t3, MSOR

2:	li.d	$f8, 4294967296.0
	cfc1	v1, $31
	li	t5, 1
	ctc1	t5, $31

	mtc1	t0, $f0
	mtc1	t1, $f2
	cvt.d.w	$f0
	cvt.d.w	$f2
	bgez	t0, 22f
	add.d	$f0, $f8
22:	mul.d	$f2, $f8
	add.d	$f0, $f2

	mtc1	t2, $f4
	mtc1	t3, $f6
	cvt.d.w	$f4
	cvt.d.w	$f6
	bgez	t2, 24f
	add.d	$f4, $f8
24:	mul.d	$f6, $f8
	add.d	$f4, $f6
	cfc1	t9, $31
	and	t9, 4
	bne	t9, 0, 3f

	div.d	$f2, $f0, $f4
	li.d	$f6, 4503599627370496.0
	mfc1	t9, $f3
	bgez	t9, 26f
	neg.d	$f6
26:	add.d	$f2, $f6
	mfc1	t4, $f2
	mfc1	t5, $f3
	and	t5, 0x000fffff

	multu	t4, t2
	mflo	t6
	mfhi	t7
	multu	t4, t3
	mflo	t8
	addu	t7, t8
	multu	t5, t2
	mflo	t8
	addu	t7, t8

	sltu	t9, t0, t6
	subu	t6, t0, t6
	subu	t7, t1, t7
	subu	t7, t9

	sw	t4, LQUO
	sw	t5, MQUO
	sw	t6, LREM
	sw	t7, MREM

	ctc1	v1, $31
	j	ra

	/* if dividend < divisor then quo = 0, rem = dividend */
3:	lw	t0, MSOR
	bgtu	MDEN, t0, 36f
	bltu	MDEN, t0, 32f
	/* MDEN == MSOR */
	lw	t0, LSOR
	bgeu	LDEN, t0, 36f
32:	sw	zero, LQUO
	sw	zero, MQUO
	sw	LDEN, LREM
	sw	MDEN, MREM
	j	ra

	/* dividend or divisor too big; have to do division the hard way */
36:	break	0
.end __ull_divrem_5353