mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
364 lines
8.9 KiB
364 lines
8.9 KiB
/*
|
|
* |-----------------------------------------------------------|
|
|
* | Copyright (c) 1991 MIPS Computer Systems, Inc. |
|
|
* | All Rights Reserved |
|
|
* |-----------------------------------------------------------|
|
|
* | Restricted Rights Legend |
|
|
* | Use, duplication, or disclosure by the Government is |
|
|
* | subject to restrictions as set forth in |
|
|
* | subparagraph (c)(1)(ii) of the Rights in Technical |
|
|
* | Data and Computer Software Clause of DFARS 52.227-7013. |
|
|
* | MIPS Computer Systems, Inc. |
|
|
* | 950 DeGuigne Drive |
|
|
* | Sunnyvale, CA 94086 |
|
|
* |-----------------------------------------------------------|
|
|
*/
|
|
/* $Header: llcvt.s,v 3010.2 91/12/10 13:24:31 murphy Exp $ */
|
|
|
|
#include <ksmips.h>
|
|
|
|
#ifdef _MIPSEL
|
|
# define PLSW a0
|
|
# define PMSW a1
|
|
# define RLSW v0
|
|
# define RMSW v1
|
|
#else /* _MIPSEB */
|
|
# define PMSW a0
|
|
# define PLSW a1
|
|
# define RMSW v0
|
|
# define RLSW v1
|
|
#endif
|
|
|
|
/* Convert from 64-bit signed integer to double precision. */
|
|
/* double ll_to_d(ll) */
|
|
|
|
.globl __ll_to_d
|
|
.ent __ll_to_d
|
|
__ll_to_d:
|
|
.frame sp, 0, ra
|
|
mtc1 PMSW, $f0
|
|
mtc1 PLSW, $f2
|
|
move t0, PLSW
|
|
li.d $f8, 4294967296.0 /* 2^32 */
|
|
cvt.d.w $f0
|
|
cvt.d.w $f2
|
|
mul.d $f0, $f8
|
|
bgez t0, 12f
|
|
/* sign bit of LSW was set */
|
|
add.d $f2, $f8 /* correct LSW conversion */
|
|
12: add.d $f0, $f2 /* add low part to high */
|
|
j ra
|
|
.end __ll_to_d
|
|
|
|
/* Convert from 64-bit unsigned integer to double precision. */
|
|
/* double ull_to_d(ll) */
|
|
|
|
.globl __ull_to_d
|
|
.ent __ull_to_d
|
|
__ull_to_d:
|
|
.frame sp, 0, ra
|
|
mtc1 PMSW, $f0
|
|
mtc1 PLSW, $f2
|
|
move t0, PLSW
|
|
move t1, PMSW
|
|
li.d $f8, 4294967296.0 /* 2^32 */
|
|
cvt.d.w $f0
|
|
cvt.d.w $f2
|
|
bgez t1, 12f
|
|
/* sign bit of MSW was set */
|
|
add.d $f0, $f8 /* correct MSW conversion */
|
|
12: mul.d $f0, $f8
|
|
bgez t0, 14f
|
|
/* sign bit of LSW was set */
|
|
add.d $f2, $f8 /* correct LSW conversion */
|
|
14: add.d $f0, $f2 /* add low part to high */
|
|
j ra
|
|
.end __ull_to_d
|
|
|
|
/* Convert from 64-bit signed integer to single precision. */
|
|
/* float ll_to_f(ll) */
|
|
|
|
.globl __ll_to_f
|
|
.ent __ll_to_f
|
|
__ll_to_f:
|
|
.frame sp, 0, ra
|
|
cfc1 t4, $31 /* save FCSR */
|
|
ctc1 $0, $31 /* set safe FCSR */
|
|
mtc1 PMSW, $f2
|
|
mtc1 PLSW, $f4
|
|
move t0, PLSW
|
|
li.d $f8, 4294967296.0 /* 2^32 */
|
|
cvt.d.w $f2
|
|
cvt.d.w $f4
|
|
mul.d $f2, $f8 /* shift up MSW value */
|
|
bgez t0, 12f
|
|
/* sign bit of LSW was set */
|
|
add.d $f4, $f8 /* correct LSW convert */
|
|
12: add.d $f0, $f2, $f4 /* add low part to high */
|
|
cfc1 t1, $31 /* check for inexact */
|
|
and t1, 4
|
|
bne t1, 0, 14f
|
|
/* conversion to double was exact */
|
|
ctc1 t4, $31
|
|
cvt.s.d $f0
|
|
j ra
|
|
14: /* conversion to double was not exact, so cvt.s.d would be double round */
|
|
li t0, 1 /* mode = round-to-0 */
|
|
ctc1 t0, $31
|
|
cvt.s.d $f0, $f2 /* move 8 bits from high to low double */
|
|
cvt.d.s $f0
|
|
sub.d $f6, $f2, $f0
|
|
add.d $f4, $f6
|
|
mfc1 t2, $f1 /* add value that pushes high 24 bits */
|
|
srl t2, 20 /* to low end of double */
|
|
addu t2, (53-24)
|
|
sll t2, 20
|
|
mtc1 t2, $f9
|
|
mtc1 $0, $f8
|
|
ctc1 t4, $31 /* restore FCSR */
|
|
add.d $f0, $f8 /* add bias */
|
|
add.d $f0, $f4 /* add low part with round to 24
|
|
bits of precision */
|
|
sub.d $f0, $f8 /* remove bias */
|
|
cvt.s.d $f0
|
|
j ra
|
|
.end __ll_to_f
|
|
|
|
/* Convert from 64-bit unsigned integer to single precision. */
|
|
/* float ull_to_f(ll) */
|
|
|
|
.globl __ull_to_f
|
|
.ent __ull_to_f
|
|
__ull_to_f:
|
|
.frame sp, 0, ra
|
|
cfc1 t4, $31 /* save FCSR */
|
|
ctc1 $0, $31 /* set safe FCSR */
|
|
mtc1 PMSW, $f2
|
|
mtc1 PLSW, $f4
|
|
move t0, PLSW
|
|
move t1, PMSW
|
|
li.d $f8, 4294967296.0 /* 2^32 */
|
|
cvt.d.w $f2
|
|
cvt.d.w $f4
|
|
bgez t1, 12f
|
|
/* sign bit of MSW was set */
|
|
add.d $f2, $f8 /* correct MSW convert */
|
|
12: mul.d $f2, $f8 /* shift up MSW value */
|
|
bgez t0, 14f
|
|
/* sign bit of LSW was set */
|
|
add.d $f4, $f8 /* correct LSW convert */
|
|
14: add.d $f0, $f2, $f4 /* add low part to high */
|
|
cfc1 t1, $31 /* check for inexact */
|
|
and t1, 4
|
|
bne t1, 0, 14f
|
|
/* conversion to double was exact */
|
|
ctc1 t4, $31
|
|
cvt.s.d $f0
|
|
j ra
|
|
14: /* conversion to double was not exact, so cvt.s.d would be double round */
|
|
li t0, 1 /* mode = round-to-0 */
|
|
ctc1 t0, $31
|
|
cvt.s.d $f0, $f2 /* move 8 bits from high to low double */
|
|
cvt.d.s $f0
|
|
sub.d $f6, $f2, $f0
|
|
add.d $f4, $f6
|
|
mfc1 t2, $f1 /* add value that pushes high 24 bits */
|
|
srl t2, 20 /* to low end of double */
|
|
addu t2, (53-24)
|
|
sll t2, 20
|
|
mtc1 t2, $f9
|
|
mtc1 $0, $f8
|
|
ctc1 t4, $31 /* restore FCSR */
|
|
add.d $f0, $f8 /* add bias */
|
|
add.d $f0, $f4 /* add low part with round to 24
|
|
bits of precision */
|
|
sub.d $f0, $f8 /* remove bias */
|
|
cvt.s.d $f0
|
|
j ra
|
|
.end __ull_to_f
|
|
|
|
/* Convert from double precision to 64-bit integer. */
|
|
/* This is a common routine for signed and unsigned case;
|
|
* the only difference is the max value, which is passed in $f4. */
|
|
/* C rules require truncating the value */
|
|
/* longlong dtoll (double); */
|
|
.globl __dtoll
|
|
.ent __dtoll
|
|
__dtoll:
|
|
.frame sp, 0, ra
|
|
cfc1 t6, $31
|
|
li t7, 1 /* round to zero (truncate) */
|
|
ctc1 t7, $31
|
|
mfc1 t8, $f13
|
|
li.d $f2, 4.5035996273704960e+15 /* 2^52 */
|
|
bltz t8, 10f
|
|
|
|
/* x >= 0 */
|
|
c.ult.d $f12, $f2
|
|
bc1f 20f
|
|
|
|
/* 0 <= x < 2^52 -- needs rounding */
|
|
/* x + 2^52 may be = 2^53 after rounding -- this still works */
|
|
add.d $f0, $f12, $f2 /* round */
|
|
mfc1 RLSW, $f0
|
|
mfc1 RMSW, $f1
|
|
subu RMSW, ((52+1023)<<20)
|
|
b 50f
|
|
|
|
10: /* x < 0 */
|
|
neg.d $f2
|
|
c.ult.d $f2, $f12
|
|
bc1f 30f
|
|
|
|
/* -2^52 < x < 0 -- needs rounding */
|
|
/* x - 2^52 may be = -2^53 after rounding -- this still works */
|
|
add.d $f0, $f12, $f2 /* round */
|
|
mfc1 RLSW, $f0
|
|
mfc1 RMSW, $f1
|
|
subu RMSW, ((52+1023+2048)<<20)
|
|
/* double word negate */
|
|
sltu t3, RLSW, 1
|
|
negu RLSW
|
|
not RMSW
|
|
addu RMSW, t3
|
|
b 50f
|
|
|
|
20: /* x >= 2^52 or NaN */
|
|
/* compare against $f4, which is either 2^63-1 or 2^64-1 */
|
|
mfc1 RLSW, $f12
|
|
mfc1 t1, $f13
|
|
c.ult.d $f12, $f4
|
|
bc1f 40f
|
|
|
|
/* 2^52 <= x < 2^63/4 */
|
|
li t2, (1<<20) /* hidden bit in high word */
|
|
subu t3, t2, 1 /* mask for high word */
|
|
and RMSW, t1, t3 /* mask out exponent */
|
|
or RMSW, t2 /* add back hidden bit */
|
|
srl t0, t1, 20 /* shift = exponent - (52+bias) */
|
|
subu t0, 1023+52 /* ... */
|
|
negu t4, t0 /* high |= low >> (32-shift) */
|
|
srl t5, RLSW, t4 /* ... */
|
|
sll RMSW, t0 /* high <<= shift */
|
|
sll RLSW, t0 /* low <<= shift */
|
|
beq t0, 0, 50f /* if shift = 0, that's all */
|
|
or RMSW, t5 /* else add bits shifted out of low */
|
|
b 50f
|
|
|
|
30: /* x <= -2^52 or NaN */
|
|
|
|
li.d $f2, -9.2233720368547758e+18 /* -2^63 */
|
|
mfc1 RLSW, $f12
|
|
mfc1 t1, $f13
|
|
c.ule.d $f2, $f12
|
|
bc1f 40f
|
|
|
|
/* -2^63 <= x <= -2^52 */
|
|
li t2, (1<<20) /* hidden bit in high word */
|
|
subu t3, t2, 1 /* mask for high word */
|
|
and RMSW, t1, t3 /* mask out exponent */
|
|
or RMSW, t2 /* add back hidden bit */
|
|
srl t0, t1, 20 /* shift = exponent - (52+bias) */
|
|
subu t0, 52+1023+2048 /* ... */
|
|
negu t4, t0 /* high |= low >> (32-shift) */
|
|
srl t5, RLSW, t4 /* ... */
|
|
sll RMSW, t0 /* high <<= shift */
|
|
sll RLSW, t0 /* low <<= shift */
|
|
beq t0, 0, 32f /* if shift = 0, that's all */
|
|
or RMSW, t5 /* else add bits shifted out of low */
|
|
32: /* double word negate */
|
|
sltu t3, RLSW, 1
|
|
negu RLSW
|
|
not RMSW
|
|
addu RMSW, t3
|
|
b 50f
|
|
|
|
40: /* x is NaN or x < -2^63 or x >= 2^63/4 */
|
|
/* raise Invalid */
|
|
li RMSW, 0x7fffffff /* signed case */
|
|
li RLSW, 0xffffffff
|
|
li.d $f2, 9.223372036854775807e+18 /* 2^63-1 */
|
|
c.ueq.d $f2, $f4
|
|
bc1t 42f
|
|
li RMSW, 0xffffffff /* unsigned case */
|
|
42:
|
|
cfc1 t0, $31
|
|
or t0, ((1<<12)|(1<<2))
|
|
ctc1 t0, $31
|
|
b 50f
|
|
50:
|
|
cfc1 t7, $31
|
|
and t7, -4
|
|
or t6, t7
|
|
ctc1 t6, $31
|
|
j ra
|
|
.end __dtoll
|
|
|
|
/* Convert from double precision to 64-bit signed integer. */
|
|
/* C rules require truncating the value */
|
|
/* longlong d_to_ll (double); */
|
|
.globl __d_to_ll
|
|
.ent __d_to_ll
|
|
__d_to_ll:
|
|
subu sp, 32
|
|
sw ra, 28(sp)
|
|
.mask 0x80000000, -4
|
|
.frame sp, 32, ra
|
|
li.d $f4, 9.223372036854775807e+18 /* 2^63-1 */
|
|
jal __dtoll
|
|
/* use v0,v1 that are already set */
|
|
lw ra, 28(sp)
|
|
addu sp, 32
|
|
j ra
|
|
.end __d_to_ll
|
|
|
|
/* longlong f_to_ll (float) */
|
|
.globl __f_to_ll
|
|
.ent __f_to_ll
|
|
__f_to_ll:
|
|
subu sp, 32
|
|
sw ra, 28(sp)
|
|
.mask 0x80000000, -4
|
|
.frame sp, 32, ra
|
|
cvt.d.s $f12, $f12
|
|
jal __d_to_ll
|
|
/* use v0,v1 that are already set */
|
|
lw ra, 28(sp)
|
|
addu sp, 32
|
|
j ra
|
|
.end __f_to_ll
|
|
|
|
/* Convert from double precision to 64-bit unsigned integer. */
|
|
/* C rules require truncating the value */
|
|
/* ulonglong d_to_ull (double); */
|
|
.globl __d_to_ull
|
|
.ent __d_to_ull
|
|
__d_to_ull:
|
|
subu sp, 32
|
|
sw ra, 28(sp)
|
|
.mask 0x80000000, -4
|
|
.frame sp, 32, ra
|
|
li.d $f4, 1.8446744073709551615e+19 /* 2^64-1 */
|
|
jal __dtoll
|
|
/* use v0,v1 that are already set */
|
|
lw ra, 28(sp)
|
|
addu sp, 32
|
|
j ra
|
|
.end __d_to_ull
|
|
|
|
/* ulonglong f_to_ull (float) */
|
|
.globl __f_to_ull
|
|
.ent __f_to_ull
|
|
__f_to_ull:
|
|
subu sp, 32
|
|
sw ra, 28(sp)
|
|
.mask 0x80000000, -4
|
|
.frame sp, 32, ra
|
|
cvt.d.s $f12, $f12
|
|
jal __d_to_ull
|
|
/* use v0,v1 that are already set */
|
|
lw ra, 28(sp)
|
|
addu sp, 32
|
|
j ra
|
|
.end __f_to_ull
|
|
|