/* $OpenBSD: fp.S,v 1.7 2004/11/02 18:54:45 pefo Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)fp.s 8.1 (Berkeley) 6/10/93 * $Id: fp.S,v 1.7 2004/11/02 18:54:45 pefo Exp $ */ /* * Standard header stuff. */ #include #include #include #include #include "assym.h" #define SEXP_INF 0xff #define DEXP_INF 0x7ff #define SEXP_BIAS 127 #define DEXP_BIAS 1023 #define SEXP_MIN -126 #define DEXP_MIN -1022 #define SEXP_MAX 127 #define DEXP_MAX 1023 #define WEXP_MAX 30 /* maximum unbiased exponent for int */ #define WEXP_MIN -1 /* minimum unbiased exponent for int */ #define SFRAC_BITS 23 #define DFRAC_BITS 52 #define SIMPL_ONE 0x00800000 #define DIMPL_ONE 0x0010000000000000 #define SLEAD_ZEROS 63 - 55 #define DLEAD_ZEROS 63 - 52 #define STICKYBIT 1 #define GUARDBIT 0x0000000080000000 #define DGUARDBIT 0x8000000000000000 #define SSIGNAL_NAN 0x00400000 #define DSIGNAL_NAN 0x00080000 #define SQUIET_NAN 0x003fffff #define DQUIET_NAN 0x0007ffffffffffff #define INT_MIN 0x80000000 #define INT_MAX 0x7fffffff #define COND_UNORDERED 0x1 #define COND_EQUAL 0x2 #define COND_LESS 0x4 #define COND_SIGNAL 0x8 /*---------------------------------------------------------------------------- * * MipsEmulateFP -- * * Emulate unimplemented floating point operations. * This routine should only be called by MipsFPInterrupt() * and only if this is a COP1 instruction. * * MipsEmulateFP(instr) * unsigned instr; * * Results: * None. * * Side effects: * Floating point registers are modified according to instruction. * *---------------------------------------------------------------------------- */ NON_LEAF(MipsEmulateFP, FRAMESZ(CF_SZ), ra) PTR_SUB sp, sp, FRAMESZ(CF_SZ) PTR_S ra, CF_RA_OFFS(sp) srl v0, a0, 21 # get FMT field and v0, v0, 0x1f # mask FMT field dla a3, func_s beq v0, 0x10, 1f dla a3, func_d beq v0, 0x11, 1f dla a3, func_w beq v0, 0x14, 1f dla a3, func_l beq v0, 0x15, 1f b ill # illegal format 1: and v1, a0, 0x3f # mask FUNC field sll v1, v1, 3 # align for table lookup daddu v1, a3 cfc1 a1, FPC_CSR # get exception register ld a3, (v1) # switch on FUNC & FMT and a1, a1, ~FPC_EXCEPTION_UNIMPL # clear exception ctc1 a1, FPC_CSR j a3 .rdata func_s: .dword add_s # 0 .dword sub_s # 1 .dword mul_s # 2 .dword div_s # 3 .dword ill # 4 .dword abs_s # 5 .dword mov_s # 6 .dword neg_s # 7 .dword ill # 8 .dword ill # 9 .dword ill # 10 .dword ill # 11 .dword round_w_s # 12 .dword trunc_w_s # 13 .dword ceil_w_s # 14 .dword floor_w_s # 15 .dword ill # 16 .dword ill # 17 .dword ill # 18 .dword ill # 19 .dword ill # 20 .dword ill # 21 .dword ill # 22 .dword ill # 23 .dword ill # 24 .dword ill # 25 .dword ill # 26 .dword ill # 27 .dword ill # 28 .dword ill # 29 .dword ill # 30 .dword ill # 31 .dword ill # 32 .dword cvt_d_s # 33 .dword ill # 34 .dword ill # 35 .dword cvt_w_s # 36 .dword ill # 37 .dword ill # 38 .dword ill # 39 .dword ill # 40 .dword ill # 41 .dword ill # 42 .dword ill # 43 .dword ill # 44 .dword ill # 45 .dword ill # 46 .dword ill # 47 .dword cmp_s # 48 .dword cmp_s # 49 .dword cmp_s # 50 .dword cmp_s # 51 .dword cmp_s # 52 .dword cmp_s # 53 .dword cmp_s # 54 .dword cmp_s # 55 .dword cmp_s # 56 .dword cmp_s # 57 .dword cmp_s # 58 .dword cmp_s # 59 .dword cmp_s # 60 .dword cmp_s # 61 .dword cmp_s # 62 .dword cmp_s # 63 func_d: .dword add_d # 0 .dword sub_d # 1 .dword mul_d # 2 .dword div_d # 3 .dword ill # 4 .dword abs_d # 5 .dword mov_d # 6 .dword neg_d # 7 .dword ill # 8 .dword ill # 9 .dword ill # 10 .dword ill # 11 .dword round_w_d # 12 .dword trunc_w_d # 13 .dword ceil_w_d # 14 .dword floor_w_d # 15 .dword ill # 16 .dword ill # 17 .dword ill # 18 .dword ill # 19 .dword ill # 20 .dword ill # 21 .dword ill # 22 .dword ill # 23 .dword ill # 24 .dword ill # 25 .dword ill # 26 .dword ill # 27 .dword ill # 28 .dword ill # 29 .dword ill # 30 .dword ill # 31 .dword cvt_s_d # 32 .dword ill # 33 .dword ill # 34 .dword ill # 35 .dword cvt_w_d # 36 .dword ill # 37 .dword ill # 38 .dword ill # 39 .dword ill # 40 .dword ill # 41 .dword ill # 42 .dword ill # 43 .dword ill # 44 .dword ill # 45 .dword ill # 46 .dword ill # 47 .dword cmp_d # 48 .dword cmp_d # 49 .dword cmp_d # 50 .dword cmp_d # 51 .dword cmp_d # 52 .dword cmp_d # 53 .dword cmp_d # 54 .dword cmp_d # 55 .dword cmp_d # 56 .dword cmp_d # 57 .dword cmp_d # 58 .dword cmp_d # 59 .dword cmp_d # 60 .dword cmp_d # 61 .dword cmp_d # 62 .dword cmp_d # 63 func_w: .dword ill # 0 .dword ill # 1 .dword ill # 2 .dword ill # 3 .dword ill # 4 .dword ill # 5 .dword ill # 6 .dword ill # 7 .dword ill # 8 .dword ill # 9 .dword ill # 10 .dword ill # 11 .dword ill # 12 .dword ill # 13 .dword ill # 14 .dword ill # 15 .dword ill # 16 .dword ill # 17 .dword ill # 18 .dword ill # 19 .dword ill # 20 .dword ill # 21 .dword ill # 22 .dword ill # 23 .dword ill # 24 .dword ill # 25 .dword ill # 26 .dword ill # 27 .dword ill # 28 .dword ill # 29 .dword ill # 30 .dword ill # 31 .dword cvt_s_w # 32 .dword cvt_d_w # 33 .dword ill # 34 .dword ill # 35 .dword ill # 36 .dword ill # 37 .dword ill # 38 .dword ill # 39 .dword ill # 40 .dword ill # 41 .dword ill # 42 .dword ill # 43 .dword ill # 44 .dword ill # 45 .dword ill # 46 .dword ill # 47 .dword ill # 48 .dword ill # 49 .dword ill # 50 .dword ill # 51 .dword ill # 52 .dword ill # 53 .dword ill # 54 .dword ill # 55 .dword ill # 56 .dword ill # 57 .dword ill # 58 .dword ill # 59 .dword ill # 60 .dword ill # 61 .dword ill # 62 .dword ill # 63 func_l: .dword ill # 0 .dword ill # 1 .dword ill # 2 .dword ill # 3 .dword ill # 4 .dword ill # 5 .dword ill # 6 .dword ill # 7 .dword ill # 8 .dword ill # 9 .dword ill # 10 .dword ill # 11 .dword ill # 12 .dword ill # 13 .dword ill # 14 .dword ill # 15 .dword ill # 16 .dword ill # 17 .dword ill # 18 .dword ill # 19 .dword ill # 20 .dword ill # 21 .dword ill # 22 .dword ill # 23 .dword ill # 24 .dword ill # 25 .dword ill # 26 .dword ill # 27 .dword ill # 28 .dword ill # 29 .dword ill # 30 .dword ill # 31 .dword cvt_s_l # 32 .dword cvt_d_l # 33 .dword ill # 34 .dword ill # 35 .dword ill # 36 .dword ill # 37 .dword ill # 38 .dword ill # 39 .dword ill # 40 .dword ill # 41 .dword ill # 42 .dword ill # 43 .dword ill # 44 .dword ill # 45 .dword ill # 46 .dword ill # 47 .dword ill # 48 .dword ill # 49 .dword ill # 50 .dword ill # 51 .dword ill # 52 .dword ill # 53 .dword ill # 54 .dword ill # 55 .dword ill # 56 .dword ill # 57 .dword ill # 58 .dword ill # 59 .dword ill # 60 .dword ill # 61 .dword ill # 62 .dword ill # 63 .text /* * Single precision subtract. */ sub_s: jal get_ft_fs_s xor ta0, 1 # negate FT sign bit b add_sub_s /* * Single precision add. */ add_s: jal get_ft_fs_s add_sub_s: bne t1, SEXP_INF, 1f # is FS an infinity? bne ta1, SEXP_INF, result_fs_s # if FT is not inf, result=FS bne t2, zero, result_fs_s # if FS is NAN, result is FS bne ta2, zero, result_ft_s # if FT is NAN, result is FT bne t0, ta0, invalid_s # both infinities same sign? b result_fs_s # result is in FS 1: beq ta1, SEXP_INF, result_ft_s # if FT is inf, result=FT bne t1, zero, 4f # is FS a denormalized num? beq t2, zero, 3f # is FS zero? bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_s # FT is zero, result=FS jal renorm_fs_s jal renorm_ft_s b 5f 2: jal renorm_fs_s subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit b 5f 3: bne ta1, zero, result_ft_s # if FT != 0, result=FT bne ta2, zero, result_ft_s and v0, a1, FPC_ROUNDING_BITS # get rounding mode bne v0, FPC_ROUND_RM, 1f # round to -infinity? or t0, t0, ta0 # compute result sign b result_fs_s 1: and t0, ta0 # compute result sign b result_fs_s 4: bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_s # FT is zero, result=FS subu t1, SEXP_BIAS # unbias FS exponent or t2, SIMPL_ONE # set implied one bit jal renorm_ft_s b 5f 2: subu t1, SEXP_BIAS # unbias FS exponent or t2, SIMPL_ONE # set implied one bit subu ta1, SEXP_BIAS # unbias FT exponent or ta2, SIMPL_ONE # set implied one bit /* * Perform the addition. */ 5: move t8, zero # no shifted bits (sticky reg) beq t1, ta1, 4f # exp equal, no shift needed subu v0, t1, ta1 # v0 = difference of exponents move v1, v0 # v1 = abs(difference) bge v0, zero, 1f negu v1 1: ble v1, SFRAC_BITS+2, 2f # is difference too great? li t8, STICKYBIT # set the sticky bit bge v0, zero, 1f # check which exp is larger move t1, ta1 # result exp is FTs move t2, zero # FSs fraction shifted is zero b 4f 1: move ta2, zero # FTs fraction shifted is zero b 4f 2: li t9, 32 # compute 32 - abs(exp diff) subu t9, t9, v1 bgt v0, zero, 3f # if FS > FT, shift FTs frac move t1, ta1 # FT > FS, result exp is FTs sll t8, t2, t9 # save bits shifted out srl t2, t2, v1 # shift FSs fraction b 4f 3: sll t8, ta2, t9 # save bits shifted out srl ta2, ta2, v1 # shift FTs fraction 4: bne t0, ta0, 1f # if signs differ, subtract addu t2, t2, ta2 # add fractions b norm_s 1: blt t2, ta2, 3f # subtract larger from smaller bne t2, ta2, 2f # if same, result=0 move t1, zero # result=0 move t2, zero and v0, a1, FPC_ROUNDING_BITS # get rounding mode bne v0, FPC_ROUND_RM, 1f # round to -infinity? or t0, t0, ta0 # compute result sign b result_fs_s 1: and t0, t0, ta0 # compute result sign b result_fs_s 2: sltu t9, zero, t8 # compute t2:zero - ta2:t8 subu t8, zero, t8 subu t2, t2, ta2 # subtract fractions subu t2, t2, t9 # subtract barrow b norm_s 3: move t0, ta0 # sign of result = FTs sltu t9, zero, t8 # compute ta2:zero - t2:t8 subu t8, zero, t8 subu t2, ta2, t2 # subtract fractions subu t2, t2, t9 # subtract barrow b norm_s /* * Double precision subtract. */ sub_d: jal get_ft_fs_d xor ta0, ta0, 1 # negate sign bit b add_sub_d /* * Double precision add. */ add_d: jal get_ft_fs_d add_sub_d: bne t1, DEXP_INF, 1f # is FS an infinity? bne ta1, DEXP_INF, result_fs_d # if FT is not inf, result=FS bne t2, zero, result_fs_d # if FS is NAN, result is FS bne ta2, zero, result_ft_d # if FT is NAN, result is FT bne t0, ta0, invalid_d # both infinities same sign? b result_fs_d # result is in FS 1: beq ta1, DEXP_INF, result_ft_d # if FT is inf, result=FT bne t1, zero, 4f # is FS a denormalized num? beq t2, zero, 3f # is FS zero? bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_d # FT is zero, result=FS jal renorm_fs_d jal renorm_ft_d b 5f 2: jal renorm_fs_d subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit b 5f 3: bne ta1, zero, result_ft_d # if FT != 0, result=FT bne ta2, zero, result_ft_d and v0, a1, FPC_ROUNDING_BITS # get rounding mode bne v0, FPC_ROUND_RM, 1f # round to -infinity? or t0, t0, ta0 # compute result sign b result_fs_d 1: and t0, t0, ta0 # compute result sign b result_fs_d 4: bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_d # FT is zero, result=FS subu t1, t1, DEXP_BIAS # unbias FS exponent or t2, t2, DIMPL_ONE # set implied one bit jal renorm_ft_d b 5f 2: subu t1, t1, DEXP_BIAS # unbias FS exponent or t2, t2, DIMPL_ONE # set implied one bit subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit /* * Perform the addition. */ 5: move t8, zero # no shifted bits (sticky reg) beq t1, ta1, 4f # no shift needed subu v0, t1, ta1 # v0 = difference of exponents move v1, v0 # v1 = abs(difference) bge v0, zero, 1f negu v1 1: ble v1, DFRAC_BITS+2, 2f # is difference too great? li t8, STICKYBIT # set the sticky bit bge v0, zero, 1f # check which exp is larger move t1, ta1 # result exp is FTs move t2, zero # FSs fraction shifted is zero b 4f 1: move ta2, zero # FTs fraction shifted is zero b 4f 2: li t9, 64 subu t9, t9, v1 bge v0, zero, 3f # if FS > FT, shift FTs frac move t1, ta1 # FT > FS, result exp is FTs dsll t8, t2, t9 # save bits shifted out dsrl t2, t2, v1 b 4f 3: dsll t8, ta2, t9 # save bits shifted out dsrl ta2, ta2, v1 4: bne t0, ta0, 1f # if signs differ, subtract daddu t2, ta2 # add fractions b norm_d 1: blt t2, ta2, 3f # subtract larger from smaller bne t2, ta2, 2f move t1, zero # result=0 move t2, zero and v0, a1, FPC_ROUNDING_BITS # get rounding mode bne v0, FPC_ROUND_RM, 1f # round to -infinity? or t0, t0, ta0 # compute result sign b result_fs_d 1: and t0, t0, ta0 # compute result sign b result_fs_d 2: sltu t9, zero, t8 # compute t2:zero - ta2:t8 dsubu t8, zero, t8 dsubu t2, t2, ta2 # subtract fractions dsubu t2, t2, t9 # subtract barrow b norm_d 3: move t0, ta0 # sign of result = FTs sltu t9, zero, t8 dsubu t2, ta2, t2 # subtract fractions dsubu t2, t2, t9 # subtract barrow b norm_d /* * Single precision multiply. */ mul_s: jal get_ft_fs_s xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, SEXP_INF, 2f # is FS an infinity? bne t2, zero, result_fs_s # if FS is a NAN, result=FS bne ta1, SEXP_INF, 1f # FS is inf, is FT an infinity? bne ta2, zero, result_ft_s # if FT is a NAN, result=FT b result_fs_s # result is infinity 1: bne ta1, zero, result_fs_s # inf * zero? if no, result=FS bne ta2, zero, result_fs_s b invalid_s # infinity * zero is invalid 2: bne ta1, SEXP_INF, 1f # FS != inf, is FT an infinity? bne t1, zero, result_ft_s # zero * inf? if no, result=FT bne t2, zero, result_ft_s bne ta2, zero, result_ft_s # if FT is a NAN, result=FT b invalid_s # zero * infinity is invalid 1: bne t1, zero, 1f # is FS zero? beq t2, zero, result_fs_s # result is zero jal renorm_fs_s b 2f 1: subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit 2: bne ta1, zero, 1f # is FT zero? beq ta2, zero, result_ft_s # result is zero jal renorm_ft_s b 2f 1: subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit 2: addu t1, t1, ta1 # compute result exponent addu t1, t1, 9 # account for binary point multu t2, ta2 # multiply fractions mflo t8 mfhi t2 b norm_s /* * Double precision multiply. */ mul_d: jal get_ft_fs_d xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, DEXP_INF, 2f # is FS an infinity? bne t2, zero, result_fs_d # if FS is a NAN, result=FS bne ta1, DEXP_INF, 1f # FS is inf, is FT an infinity? bne ta2, zero, result_ft_d # if FT is a NAN, result=FT b result_fs_d # result is infinity 1: bne ta1, zero, result_fs_d # inf * zero? if no, result=FS bne ta2, zero, result_fs_d b invalid_d # infinity * zero is invalid 2: bne ta1, DEXP_INF, 1f # FS != inf, is FT an infinity? bne t1, zero, result_ft_d # zero * inf? if no, result=FT bne t2, zero, result_ft_d # if FS is a NAN, result=FS bne ta2, zero, result_ft_d # if FT is a NAN, result=FT b invalid_d # zero * infinity is invalid 1: bne t1, zero, 2f # is FS zero? beq t2, zero, result_fs_d # result is zero jal renorm_fs_d b 3f 2: subu t1, t1, DEXP_BIAS # unbias FS exponent or t2, t2, DIMPL_ONE # set implied one bit 3: bne ta1, zero, 2f # is FT zero? beq ta2, zero, result_ft_d # result is zero jal renorm_ft_d b 3f 2: subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit 3: addu t1, t1, ta1 # compute result exponent addu t1, t1, 12 # ??? dmultu t2, ta2 # multiply fractions mflo t8 mfhi t2 b norm_d /* * Single precision divide. */ div_s: jal get_ft_fs_s xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, result_fs_s # if FS is NAN, result is FS bne ta1, SEXP_INF, result_fs_s # is FT an infinity? bne ta2, zero, result_ft_s # if FT is NAN, result is FT b invalid_s # infinity/infinity is invalid 1: bne ta1, SEXP_INF, 1f # is FT an infinity? bne ta2, zero, result_ft_s # if FT is NAN, result is FT move t1, zero # x / infinity is zero move t2, zero b result_fs_s 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f bne ta1, zero, result_fs_s # FS=zero, is FT zero? beq ta2, zero, invalid_s # 0 / 0 b result_fs_s # result = zero 1: jal renorm_fs_s b 3f 2: subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit 3: bne ta1, zero, 2f # is FT zero? bne ta2, zero, 1f or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 and v0, a1, FPC_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions li t1, SEXP_INF # result is infinity move t2, zero b result_fs_s 1: jal renorm_ft_s b 3f 2: subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit 3: subu t1, t1, ta1 # compute exponent subu t1, t1, 3 # compensate for result position li v0, SFRAC_BITS+3 # number of bits to divide move t8, t2 # init dividend move t2, zero # init result 1: bltu t8, ta2, 3f # is dividend >= divisor? 2: subu t8, t8, ta2 # subtract divisor from dividend or t2, t2, 1 # remember that we did bne t8, zero, 3f # if not done, continue sll t2, t2, v0 # shift result to final position b norm_s 3: sll t8, t8, 1 # shift dividend sll t2, t2, 1 # shift result subu v0, v0, 1 # are we done? bne v0, zero, 1b # no, continue b norm_s /* * Double precision divide. */ div_d: jal get_ft_fs_d xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, result_fs_d # if FS is NAN, result is FS bne ta1, DEXP_INF, result_fs_d # is FT an infinity? bne ta2, zero, result_ft_d # if FT is NAN, result is FT b invalid_d # infinity/infinity is invalid 1: bne ta1, DEXP_INF, 1f # is FT an infinity? bne ta2, zero, result_ft_d # if FT is NAN, result is FT move t1, zero # x / infinity is zero move t2, zero b result_fs_d 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f bne ta1, zero, result_fs_d # FS=zero, is FT zero? beq ta2, zero, invalid_d # 0 / 0 b result_fs_d # result = zero 1: jal renorm_fs_d b 3f 2: subu t1, t1, DEXP_BIAS # unbias FS exponent or t2, t2, DIMPL_ONE # set implied one bit 3: bne ta1, zero, 2f # is FT zero? bne ta2, zero, 1f or a1, a1, FPC_EXCEPTION_DIV0 | FPC_STICKY_DIV0 and v0, a1, FPC_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # Save exceptions li t1, DEXP_INF # result is infinity move t2, zero b result_fs_d 1: jal renorm_ft_d b 3f 2: subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit 3: subu t1, t1, ta1 # compute exponent subu t1, t1, 3 # compensate for result position li v0, DFRAC_BITS+3 # number of bits to divide move t8, t2 # init dividend move t2, zero # init result 1: bltu t8, ta2, 3f # is dividend >= divisor? 2: dsubu t8, t8, ta2 # subtract divisor from dividend or t2, t2, 1 # remember that we did bne t8, zero, 3f # if not done, continue dsll t2, t2, v0 # shift upper part b norm_d 3: dsll t8, t8, 1 # shift dividend dsll t2, t2, 1 # shift result subu v0, v0, 1 # are we done? bne v0, zero, 1b # no, continue b norm_d /* * Single precision absolute value. */ abs_s: jal get_fs_s move t0, zero # set sign positive b result_fs_s /* * Double precision absolute value. */ abs_d: jal get_fs_d move t0, zero # set sign positive b result_fs_d /* * Single precision move. */ mov_s: jal get_fs_s b result_fs_s /* * Double precision move. */ mov_d: jal get_fs_d b result_fs_d /* * Single precision negate. */ neg_s: jal get_fs_s xor t0, t0, 1 # reverse sign b result_fs_s /* * Double precision negate. */ neg_d: jal get_fs_d xor t0, t0, 1 # reverse sign b result_fs_d /* * Convert double to single. */ cvt_s_d: jal get_fs_d bne t1, DEXP_INF, 1f # is FS an infinity? li t1, SEXP_INF # convert to single dsll t2, t2, 3 # convert D fraction to S b result_fs_s 1: bne t1, zero, 2f # is FS zero? beq t2, zero, result_fs_s # result=0 jal renorm_fs_d subu t1, t1, 3 # correct exp for shift below b 3f 2: subu t1, t1, DEXP_BIAS # unbias exponent or t2, t2, DIMPL_ONE # add implied one bit 3: dsll t2, t2, 3 # convert D fraction to S b norm_noshift_s /* * Convert long integer to single. */ cvt_s_l: jal get_fs_long b cvt_s_int /* * Convert integer to single. */ cvt_s_w: jal get_fs_int cvt_s_int: bne t2, zero, 1f # check for zero move t1, zero b result_fs_s /* * Find out how many leading zero bits are in t2 and put in t9. */ 1: move v0, t2 move t9, zero dsrl v1, v0, 32 bne v1, zero, 1f addu t9, 32 dsll v0, 32 1: dsrl v1, v0, 16 bne v1, zero, 1f addu t9, 16 dsll v0, 16 1: dsrl v1, v0, 24 bne v1, zero, 1f addu t9, 8 dsll v0, 8 1: dsrl v1, v0, 28 bne v1, zero, 1f addu t9, 4 dsll v0, 4 1: dsrl v1, v0, 30 bne v1, zero, 1f addu t9, 2 dsll v0, 2 1: dsrl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2 the correct number of bits. */ 1: subu t9, SLEAD_ZEROS # dont count leading zeros li t1, 23+32 # init exponent subu t1, t1, t9 # compute exponent beq t9, zero, 1f li v0, 32 blt t9, zero, 2f # if shift < 0, shift right subu v0, v0, t9 sll t2, t2, t9 # shift left 1: add t1, t1, SEXP_BIAS # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit b result_fs_s 2: negu t9 # shift right by t9 subu v0, v0, t9 sll t8, t2, v0 # save bits shifted out srl t2, t2, t9 b norm_noshift_s /* * Convert single to double. */ cvt_d_s: jal get_fs_s dsll t2, 32 bne t1, SEXP_INF, 1f # is FS an infinity? li t1, DEXP_INF # convert to double b result_fs_d 1: bne t1, zero, 2f # is FS denormalized or zero? beq t2, zero, result_fs_d # is FS zero? jal renorm_fs_s move t8, zero b norm_d 2: addu t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly dsrl t2, t2, 3 b result_fs_d /* * Convert long integer to double. */ cvt_d_l: jal get_fs_long b cvt_d_int /* * Convert integer to double. */ cvt_d_w: jal get_fs_int cvt_d_int: bne t2, zero, 1f # check for zero move t1, zero # result=0 b result_fs_d /* * Find out how many leading zero bits are in t2 and put in t9. */ 1: move v0, t2 move t9, zero dsrl v1, v0, 32 bne v1, zero, 1f addu t9, 32 dsll v0, 32 1: dsrl v1, v0, 16 bne v1, zero, 1f addu t9, 16 dsll v0, 16 1: dsrl v1, v0, 24 bne v1, zero, 1f addu t9, 8 dsll v0, 8 1: dsrl v1, v0, 28 bne v1, zero, 1f addu t9, 4 dsll v0, 4 1: dsrl v1, v0, 30 bne v1, zero, 1f addu t9, 2 dsll v0, 2 1: dsrl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count leading zeros li t1, DEXP_BIAS + 20 # init exponent subu t1, t1, t9 # compute exponent beq t9, zero, 1f li v0, 64 blt t9, zero, 2f # if shift < 0, shift right subu v0, v0, t9 dsll t2, t2, t9 # shift left 1: and t2, t2, ~DIMPL_ONE # clear implied one bit b result_fs_d 2: negu t9 # shift right by t9 subu v0, v0, t9 dsrl t2, t2, t9 and t2, t2, ~DIMPL_ONE # clear implied one bit b result_fs_d /* * Convert single to integer with specific rounding. */ round_w_s: li t3, FPC_ROUND_RN b do_cvt_w_s trunc_w_s: li t3, FPC_ROUND_RZ b do_cvt_w_s ceil_w_s: li t3, FPC_ROUND_RP b do_cvt_w_s floor_w_s: li t3, FPC_ROUND_RM b do_cvt_w_s /* * Convert single to integer. */ cvt_w_s: and t3, a1, FPC_ROUNDING_BITS # get rounding mode do_cvt_w_s: jal get_fs_s bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, invalid_w # invalid conversion 1: bne t1, zero, 1f # is FS zero? beq t2, zero, result_fs_w # result is zero move t2, zero # result is an inexact zero b inexact_w 1: subu t1, t1, SEXP_BIAS # unbias exponent or t2, t2, SIMPL_ONE # add implied one bit dsll t2, t2, 32 - 3 # convert S fraction to D b cvt_w /* * Convert single to integer with specific rounding. */ round_w_d: li t3, FPC_ROUND_RN b do_cvt_w_d trunc_w_d: li t3, FPC_ROUND_RZ b do_cvt_w_d ceil_w_d: li t3, FPC_ROUND_RP b do_cvt_w_d floor_w_d: li t3, FPC_ROUND_RM b do_cvt_w_d /* * Convert double to integer. */ cvt_w_d: and t3, a1, FPC_ROUNDING_BITS # get rounding mode do_cvt_w_d: jal get_fs_d bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, invalid_w # invalid conversion 1: bne t1, zero, 2f # is FS zero? beq t2, zero, result_fs_w # result is zero move t2, zero # result is an inexact zero b inexact_w 2: subu t1, t1, DEXP_BIAS # unbias exponent or t2, t2, DIMPL_ONE # add implied one bit cvt_w: blt t1, WEXP_MIN, underflow_w # is exponent too small? li v0, WEXP_MAX+1 bgt t1, v0, overflow_w # is exponent too large? bne t1, v0, 1f # special check for INT_MIN beq t0, zero, overflow_w # if positive, overflow bne t2, DIMPL_ONE, overflow_w li t2, INT_MIN # result is INT_MIN b result_fs_w 1: subu v0, t1, 20 # compute amount to shift beq v0, zero, 2f # is shift needed? li v1, 64 blt v0, zero, 1f # if shift < 0, shift right subu v1, v1, v0 # shift left dsll t2, t2, v0 b 2f 1: negu v0 # shift right by v0 subu v1, v1, v0 dsll t8, t2, v1 # save bits shifted out sltu t8, zero, t8 # dont lose any ones dsrl t2, t2, v0 /* * round (t0 is sign, t2:63-32 is integer part, t2:31-0 is fractional part). */ 2: beq t3, FPC_ROUND_RN, 3f # round to nearest beq t3, FPC_ROUND_RZ, 5f # round to zero (truncate) beq t3, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, 5f # if sign is positive, truncate b 2f 1: bne t0, zero, 5f # if sign is negative, truncate 2: daddu t2, t2, GUARDBIT # add in fractional blt t2, zero, overflow_w # overflow? b 5f 3: daddu t2, t2, GUARDBIT # add in fractional blt t2, zero, overflow_w # overflow? 4: bne v0, zero, 5f # if rounded remainder is zero and t2, 0xfffffffe00000000 # clear LSB (round to nearest) 5: beq t0, zero, 1f # result positive? negu t2 # convert to negative integer 1: dsll v0, 32 # save fraction dsrl t2, 32 # shift out fractional part beq v0, zero, result_fs_w # is result exact? /* * Handle inexact exception. */ inexact_w: or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions b result_fs_w /* * Conversions to integer which overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an invalid exception. */ overflow_w: or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW and v0, a1, FPC_ENABLE_OVERFLOW bne v0, zero, fpe_trap and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, inexact_w # inexact traps enabled? b invalid_w /* * Conversions to integer which underflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an invalid exception. */ underflow_w: or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW and v0, a1, FPC_ENABLE_UNDERFLOW bne v0, zero, fpe_trap and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, inexact_w # inexact traps enabled? b invalid_w /* * Compare single. */ cmp_s: jal get_cmp_s bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, unordered # FS is a NAN 1: bne ta1, SEXP_INF, 2f # is FT an infinity? bne ta2, zero, unordered # FT is a NAN 2: sll t1, t1, 23 # reassemble exp & frac or t1, t1, t2 sll ta1, ta1, 23 # reassemble exp & frac or ta1, ta1, ta2 beq t0, zero, 1f # is FS positive? negu t1 1: beq ta0, zero, 1f # is FT positive? negu ta1 1: li v0, COND_LESS blt t1, ta1, test_cond # is FS < FT? li v0, COND_EQUAL beq t1, ta1, test_cond # is FS == FT? move v0, zero # FS > FT b test_cond /* * Compare double. */ cmp_d: jal get_cmp_d bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, unordered # FS is a NAN 1: bne ta1, DEXP_INF, 2f # is FT an infinity? bne ta2, zero, unordered # FT is a NAN 2: dsll t1, t1, 52 # reassemble exp & frac or t1, t1, t2 dsll ta1, ta1, 52 # reassemble exp & frac or ta1, ta1, ta2 beq t0, zero, 1f # is FS positive? dnegu t1 # negate t1 1: beq ta0, zero, 1f # is FT positive? dnegu ta1 1: li v0, COND_LESS blt t1, ta1, test_cond # is FS(MSW) < FT(MSW)? li v0, COND_EQUAL beq t1, ta1, test_cond # is FS(LSW) == FT(LSW)? move v0, zero # FS > FT test_cond: and v0, v0, a0 # condition match instruction? set_cond: bne v0, zero, 1f and a1, a1, ~FPC_COND_BIT # clear condition bit b 2f 1: or a1, a1, FPC_COND_BIT # set condition bit 2: ctc1 a1, FPC_CSR # save condition bit b done unordered: and v0, a0, COND_UNORDERED # this cmp match unordered? bne v0, zero, 1f and a1, a1, ~FPC_COND_BIT # clear condition bit b 2f 1: or a1, a1, FPC_COND_BIT # set condition bit 2: and v0, a0, COND_SIGNAL beq v0, zero, 1f # is this a signaling cmp? or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID and v0, a1, FPC_ENABLE_INVALID bne v0, zero, fpe_trap 1: ctc1 a1, FPC_CSR # save condition bit b done /* * Determine the amount to shift the fraction in order to restore the * normalized position. After that, round and handle exceptions. */ norm_s: move v0, t2 move t9, zero # t9 = num of leading zeros bne t2, zero, 1f move v0, t8 addu t9, 32 1: srl v1, v0, 16 bne v1, zero, 1f addu t9, 16 sll v0, 16 1: srl v1, v0, 24 bne v1, zero, 1f addu t9, 8 sll v0, 8 1: srl v1, v0, 28 bne v1, zero, 1f addu t9, 4 sll v0, 4 1: srl v1, v0, 30 bne v1, zero, 1f addu t9, 2 sll v0, 2 1: srl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2,t8 the correct number of bits. */ 1: subu t9, t9, SLEAD_ZEROS # dont count leading zeros subu t1, t1, t9 # adjust the exponent beq t9, zero, norm_noshift_s li v1, 32 blt t9, zero, 1f # if shift < 0, shift right subu v1, v1, t9 sll t2, t2, t9 # shift t2,t8 left srl v0, t8, v1 # save bits shifted out or t2, t2, v0 sll t8, t8, t9 b norm_noshift_s 1: negu t9 # shift t2,t8 right by t9 subu v1, v1, t9 sll v0, t8, v1 # save bits shifted out sltu v0, zero, v0 # be sure to save any one bits srl t8, t8, t9 or t8, t8, v0 sll v0, t2, v1 # save bits shifted out or t8, t8, v0 srl t2, t2, t9 norm_noshift_s: move ta1, t1 # save unrounded exponent move ta2, t2 # save unrounded fraction and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, 5f # if sign is positive, truncate b 2f 1: bne t0, zero, 5f # if sign is negative, truncate 2: beq t8, zero, 5f # if exact, continue addu t2, t2, 1 # add rounding bit bne t2, SIMPL_ONE<<1, 5f # need to adjust exponent? addu t1, t1, 1 # adjust exponent srl t2, t2, 1 # renormalize fraction b 5f 3: li v0, GUARDBIT # load guard bit for rounding addu v0, v0, t8 # add remainder sltu v1, v0, t8 # compute carry out beq v1, zero, 4f # if no carry, continue addu t2, t2, 1 # add carry to result bne t2, SIMPL_ONE<<1, 4f # need to adjust exponent? addu t1, t1, 1 # adjust exponent srl t2, t2, 1 # renormalize fraction 4: bne v0, zero, 5f # if rounded remainder is zero and t2, t2, ~1 # clear LSB (round to nearest) 5: bgt t1, SEXP_MAX, overflow_s # overflow? blt t1, SEXP_MIN, underflow_s # underflow? bne t8, zero, inexact_s # is result inexact? addu t1, t1, SEXP_BIAS # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit b result_fs_s /* * Handle inexact exception. */ inexact_s: addu t1, t1, SEXP_BIAS # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit inexact_nobias_s: jal set_fd_s # save result or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_s: or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW and v0, a1, FPC_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 192 # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit jal set_fd_s # save result b fpe_trap 1: and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) beq v0, FPC_ROUND_RP, 2f # round to +infinity bne t0, zero, 3f 1: li t1, SEXP_MAX # result is max finite li t2, 0x007fffff b inexact_s 2: bne t0, zero, 1b 3: li t1, SEXP_MAX + 1 # result is infinity move t2, zero b inexact_s /* * In this implementation, "tininess" is detected "after rounding" and * "loss of accuracy" is detected as "an inexact result". */ underflow_s: and v0, a1, FPC_ENABLE_UNDERFLOW beq v0, zero, 1f /* * Underflow is enabled so compute the result and trap. */ addu t1, t1, 192 # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit jal set_fd_s # save result or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW b fpe_trap /* * Underflow is not enabled so compute the result, * signal inexact result (if it is) and trap (if enabled). */ 1: move t1, ta1 # get unrounded exponent move t2, ta2 # get unrounded fraction li t9, SEXP_MIN # compute shift amount subu t9, t9, t1 # shift t2,t8 right by t9 blt t9, SFRAC_BITS+2, 3f # shift all the bits out? move t1, zero # result is inexact zero move t2, zero or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW /* * Now round the zero result. * Only need to worry about rounding to +- infinity when the sign matches. */ and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, inexact_nobias_s # round to nearest beq v0, FPC_ROUND_RZ, inexact_nobias_s # round to zero beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, inexact_nobias_s # if sign is positive, truncate b 2f 1: bne t0, zero, inexact_nobias_s # if sign is negative, truncate 2: addu t2, t2, 1 # add rounding bit b inexact_nobias_s 3: li v1, 32 subu v1, v1, t9 sltu v0, zero, t8 # be sure to save any one bits sll t8, t2, v1 # save bits shifted out or t8, t8, v0 # include sticky bits srl t2, t2, t9 /* * Now round the denormalized result. */ and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, 5f # if sign is positive, truncate b 2f 1: bne t0, zero, 5f # if sign is negative, truncate 2: beq t8, zero, 5f # if exact, continue addu t2, t2, 1 # add rounding bit b 5f 3: li v0, GUARDBIT # load guard bit for rounding addu v0, v0, t8 # add remainder sltu v1, v0, t8 # compute carry out beq v1, zero, 4f # if no carry, continue addu t2, t2, 1 # add carry to result 4: bne v0, zero, 5f # if rounded remainder is zero and t2, t2, ~1 # clear LSB (round to nearest) 5: move t1, zero # denorm or zero exponent jal set_fd_s # save result beq t8, zero, done # check for exact result or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions b done /* * Determine the amount to shift the fraction in order to restore the * normalized position. After that, round and handle exceptions. */ norm_d: move v0, t2 move t9, zero # t9 = num of leading zeros dsrl v1, v0, 32 bne v1, zero, 1f addu t9, 32 dsll v0, 32 1: dsrl v1, v0, 16 bne v1, zero, 1f addu t9, 16 dsll v0, 16 1: dsrl v1, v0, 24 bne v1, zero, 1f addu t9, 8 dsll v0, 8 1: dsrl v1, v0, 28 bne v1, zero, 1f addu t9, 4 dsll v0, 4 1: dsrl v1, v0, 30 bne v1, zero, 1f addu t9, 2 dsll v0, 2 1: dsrl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2,t8 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count leading zeros subu t1, t1, t9 # adjust the exponent beq t9, zero, norm_noshift_d li v1, 64 blt t9, zero, 2f # if shift < 0, shift right subu v1, v1, t9 dsll t2, t2, t9 # shift left by t9 dsrl v0, t8, v1 # save bits shifted out or t2, t2, v0 dsll t8, t8, t9 b norm_noshift_d 2: negu t9 # shift right by t9 subu v1, v1, t9 # (known to be < 32 bits) dsll v0, t8, v1 # save bits shifted out sltu v0, zero, v0 # be sure to save any one bits dsrl t8, t8, t9 or t8, t8, v0 dsll v0, t2, v1 # save bits shifted out or t8, t8, v0 dsrl t2, t2, t9 norm_noshift_d: move ta1, t1 # save unrounded exponent move ta2, t2 # save unrounded fraction (MS) and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, 5f # if sign is positive, truncate b 2f 1: bne t0, zero, 5f # if sign is negative, truncate 2: beq t8, zero, 5f # if exact, continue daddu t2, t2, 1 # add rounding bit bne t2, DIMPL_ONE<<1, 5f # need to adjust exponent? addu t1, t1, 1 # adjust exponent dsrl t2, t2, 1 # renormalize fraction b 5f 3: dli v0, DGUARDBIT # load guard bit for rounding addu v0, v0, t8 # add remainder sltu v1, v0, t8 # compute carry out beq v1, zero, 4f # branch if no carry daddu t2, t2, 1 # add carry to result bne t2, DIMPL_ONE<<1, 4f # need to adjust exponent? addu t1, t1, 1 # adjust exponent srl t2, t2, 1 # renormalize fraction 4: bne v0, zero, 5f # if rounded remainder is zero and t2, t2, ~1 # clear LSB (round to nearest) 5: bgt t1, DEXP_MAX, overflow_d # overflow? blt t1, DEXP_MIN, underflow_d # underflow? bne t8, zero, inexact_d # is result inexact? addu t1, t1, DEXP_BIAS # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit b result_fs_d /* * Handle inexact exception. */ inexact_d: addu t1, t1, DEXP_BIAS # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit inexact_nobias_d: jal set_fd_d # save result or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_d: or a1, a1, FPC_EXCEPTION_OVERFLOW | FPC_STICKY_OVERFLOW and v0, a1, FPC_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 1536 # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit jal set_fd_d # save result b fpe_trap 1: and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 1f # round to zero (truncate) beq v0, FPC_ROUND_RP, 2f # round to +infinity bne t0, zero, 3f 1: li t1, DEXP_MAX # result is max finite dli t2, 0x000fffffffffffff b inexact_d 2: bne t0, zero, 1b 3: li t1, DEXP_MAX + 1 # result is infinity move t2, zero b inexact_d /* * In this implementation, "tininess" is detected "after rounding" and * "loss of accuracy" is detected as "an inexact result". */ underflow_d: and v0, a1, FPC_ENABLE_UNDERFLOW beq v0, zero, 1f /* * Underflow is enabled so compute the result and trap. */ addu t1, t1, 1536 # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit jal set_fd_d # save result or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW b fpe_trap /* * Underflow is not enabled so compute the result, * signal inexact result (if it is) and trap (if enabled). */ 1: move t1, ta1 # get unrounded exponent move t2, ta2 # get unrounded fraction (MS) li t9, DEXP_MIN # compute shift amount subu t9, t9, t1 # shift t2,t8 right by t9 blt t9, DFRAC_BITS+2, 3f # shift all the bits out? move t1, zero # result is inexact zero move t2, zero or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW /* * Now round the zero result. * Only need to worry about rounding to +- infinity when the sign matches. */ and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, inexact_nobias_d # round to nearest beq v0, FPC_ROUND_RZ, inexact_nobias_d # round to zero beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, inexact_nobias_d # if sign is positive, truncate b 2f 1: bne t0, zero, inexact_nobias_d # if sign is negative, truncate 2: daddu t2, t2, 1 # add rounding bit b inexact_nobias_d 3: li v1, 64 subu v1, v1, t9 sltu v0, zero, t8 # be sure to save any one bits dsll t8, t2, v1 # save bits shifted out or t8, t8, v0 # include sticky bits dsrl t2, t2, t9 /* * Now round the denormalized result. */ and v0, a1, FPC_ROUNDING_BITS # get rounding mode beq v0, FPC_ROUND_RN, 3f # round to nearest beq v0, FPC_ROUND_RZ, 5f # round to zero (truncate) beq v0, FPC_ROUND_RP, 1f # round to +infinity beq t0, zero, 5f # if sign is positive, truncate b 2f 1: bne t0, zero, 5f # if sign is negative, truncate 2: beq t8, zero, 5f # if exact, continue daddu t2, t2, 1 # add rounding bit b 5f 3: dli v0, DGUARDBIT # load guard bit for rounding daddu v0, v0, t8 # add remainder sltu v1, v0, t8 # compute carry out beq v1, zero, 4f # if no carry, continue daddu t2, t2, 1 # add carry 4: bne v0, zero, 5f # if rounded remainder is zero and t2, t2, ~1 # clear LSB (round to nearest) 5: move t1, zero # denorm or zero exponent jal set_fd_d # save result beq t8, zero, done # check for exact result or a1, a1, FPC_EXCEPTION_UNDERFLOW | FPC_STICKY_UNDERFLOW or a1, a1, FPC_EXCEPTION_INEXACT | FPC_STICKY_INEXACT and v0, a1, FPC_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is a quiet NAN. */ invalid_s: # trap invalid operation or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID and v0, a1, FPC_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions move t0, zero # result is a quiet NAN li t1, SEXP_INF li t2, SQUIET_NAN jal set_fd_s # save result (in t0,t1,t2) b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is a quiet NAN. */ invalid_d: # trap invalid operation or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID and v0, a1, FPC_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions move t0, zero # result is a quiet NAN li t1, DEXP_INF dli t2, DQUIET_NAN jal set_fd_d # save result (in t0,t1,t2) b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is INT_MAX or INT_MIN. */ invalid_w: # trap invalid operation or a1, a1, FPC_EXCEPTION_INVALID | FPC_STICKY_INVALID and v0, a1, FPC_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, FPC_CSR # save exceptions bne t0, zero, 1f li t2, INT_MAX # result is INT_MAX b result_fs_w 1: li t2, INT_MIN # result is INT_MIN b result_fs_w /* * Trap if the hardware should have handled this case. */ fpe_trap: move a2, a1 # code = FP CSR ctc1 a1, FPC_CSR # save exceptions li v0, 1 b done_err /* * Send an illegal instruction signal to the current process. */ ill: ctc1 a1, FPC_CSR # save exceptions move a2, a0 # code = FP instruction li v0, 1 b done_err result_ft_s: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 result_fs_s: # result is FS jal set_fd_s # save result (in t0,t1,t2) b done result_fs_w: jal set_fd_word # save result (in t2) b done result_ft_d: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 result_fs_d: # result is FS jal set_fd_d # save result (in t0,t1,t2) done: li v0, 0 done_err: PTR_L ra, CF_RA_OFFS(sp) PTR_ADD sp, sp, FRAMESZ(CF_SZ) j ra END(MipsEmulateFP) /*---------------------------------------------------------------------------- * get_fs_int -- * * Read (integer) the FS register (bits 15-11). * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t2 contains the fraction * *---------------------------------------------------------------------------- */ #define GET_FS_INT(n) \ .rdata; \ .dword get_fs_int_/**/n; \ .text; \ get_fs_int_/**/n: \ mfc1 t2, $/**/n; \ b get_fs_int_done LEAF(get_fs_int, 0) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, get_fs_int_tbl(a3) # switch on register number j a3 .rdata get_fs_int_tbl: .text GET_FS_INT(f0) GET_FS_INT(f1) GET_FS_INT(f2) GET_FS_INT(f3) GET_FS_INT(f4) GET_FS_INT(f5) GET_FS_INT(f6) GET_FS_INT(f7) GET_FS_INT(f8) GET_FS_INT(f9) GET_FS_INT(f10) GET_FS_INT(f11) GET_FS_INT(f12) GET_FS_INT(f13) GET_FS_INT(f14) GET_FS_INT(f15) GET_FS_INT(f16) GET_FS_INT(f17) GET_FS_INT(f18) GET_FS_INT(f19) GET_FS_INT(f20) GET_FS_INT(f21) GET_FS_INT(f22) GET_FS_INT(f23) GET_FS_INT(f24) GET_FS_INT(f25) GET_FS_INT(f26) GET_FS_INT(f27) GET_FS_INT(f28) GET_FS_INT(f29) GET_FS_INT(f30) GET_FS_INT(f31) get_fs_int_done: srl t0, t2, 31 # init the sign bit bge t2, zero, 1f negu t2 dsll t2, 33 dsrl t2, 33 1: j ra END(get_fs_int) /*---------------------------------------------------------------------------- * get_fs_long -- * * Read (long integer) the FS register (bits 15-11). * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t2 contains the fraction * *---------------------------------------------------------------------------- */ #define GET_FS_LONG(n) \ .rdata; \ .dword get_fs_long_/**/n; \ .text; \ get_fs_long_/**/n: \ dmfc1 t2, $/**/n; \ b get_fs_long_done LEAF(get_fs_long, 0) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, get_fs_long_tbl(a3) # switch on register number j a3 .rdata get_fs_long_tbl: .text GET_FS_LONG(f0) GET_FS_LONG(f1) GET_FS_LONG(f2) GET_FS_LONG(f3) GET_FS_LONG(f4) GET_FS_LONG(f5) GET_FS_LONG(f6) GET_FS_LONG(f7) GET_FS_LONG(f8) GET_FS_LONG(f9) GET_FS_LONG(f10) GET_FS_LONG(f11) GET_FS_LONG(f12) GET_FS_LONG(f13) GET_FS_LONG(f14) GET_FS_LONG(f15) GET_FS_LONG(f16) GET_FS_LONG(f17) GET_FS_LONG(f18) GET_FS_LONG(f19) GET_FS_LONG(f20) GET_FS_LONG(f21) GET_FS_LONG(f22) GET_FS_LONG(f23) GET_FS_LONG(f24) GET_FS_LONG(f25) GET_FS_LONG(f26) GET_FS_LONG(f27) GET_FS_LONG(f28) GET_FS_LONG(f29) GET_FS_LONG(f30) GET_FS_LONG(f31) get_fs_long_done: dsrl t0, t2, 63 # init the sign bit bge t2, zero, 1f dnegu t2 1: j ra END(get_fs_long) /*---------------------------------------------------------------------------- * get_ft_fs_s -- * * Read (single precision) the FT register (bits 20-16) and * the FS register (bits 15-11) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the FS sign * t1 contains the FS (biased) exponent * t2 contains the FS fraction * ta0 contains the FT sign * ta1 contains the FT (biased) exponent * ta2 contains the FT fraction * *---------------------------------------------------------------------------- */ #define GET_FT_S(n) \ .rdata; \ .dword get_ft_s_/**/n; \ .text; \ get_ft_s_/**/n: \ mfc1 ta0, $/**/n; \ b get_ft_s_done LEAF(get_ft_fs_s, 0) srl a3, a0, 16 - 3 # get FT field and a3, a3, 0x1f << 3 # mask FT field ld a3, get_ft_s_tbl(a3) # switch on register number j a3 .rdata get_ft_s_tbl: .text GET_FT_S(f0) GET_FT_S(f1) GET_FT_S(f2) GET_FT_S(f3) GET_FT_S(f4) GET_FT_S(f5) GET_FT_S(f6) GET_FT_S(f7) GET_FT_S(f8) GET_FT_S(f9) GET_FT_S(f10) GET_FT_S(f11) GET_FT_S(f12) GET_FT_S(f13) GET_FT_S(f14) GET_FT_S(f15) GET_FT_S(f16) GET_FT_S(f17) GET_FT_S(f18) GET_FT_S(f19) GET_FT_S(f20) GET_FT_S(f21) GET_FT_S(f22) GET_FT_S(f23) GET_FT_S(f24) GET_FT_S(f25) GET_FT_S(f26) GET_FT_S(f27) GET_FT_S(f28) GET_FT_S(f29) GET_FT_S(f30) GET_FT_S(f31) get_ft_s_done: srl ta1, ta0, 23 # get exponent and ta1, ta1, 0xFF and ta2, ta0, 0x7FFFFF # get fraction srl ta0, ta0, 31 # get sign bne ta1, SEXP_INF, 1f # is it a signaling NAN? and v0, ta2, SSIGNAL_NAN bne v0, zero, invalid_s 1: /* fall through to get FS */ /*---------------------------------------------------------------------------- * get_fs_s -- * * Read (single precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * *---------------------------------------------------------------------------- */ #define GET_FS_S(n) \ .rdata; \ .dword get_fs_s_/**/n; \ .text; \ get_fs_s_/**/n: \ mfc1 t0, $/**/n; \ b get_fs_s_done ALEAF(get_fs_s) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, get_fs_s_tbl(a3) # switch on register number j a3 .rdata get_fs_s_tbl: .text GET_FS_S(f0) GET_FS_S(f1) GET_FS_S(f2) GET_FS_S(f3) GET_FS_S(f4) GET_FS_S(f5) GET_FS_S(f6) GET_FS_S(f7) GET_FS_S(f8) GET_FS_S(f9) GET_FS_S(f10) GET_FS_S(f11) GET_FS_S(f12) GET_FS_S(f13) GET_FS_S(f14) GET_FS_S(f15) GET_FS_S(f16) GET_FS_S(f17) GET_FS_S(f18) GET_FS_S(f19) GET_FS_S(f20) GET_FS_S(f21) GET_FS_S(f22) GET_FS_S(f23) GET_FS_S(f24) GET_FS_S(f25) GET_FS_S(f26) GET_FS_S(f27) GET_FS_S(f28) GET_FS_S(f29) GET_FS_S(f30) GET_FS_S(f31) get_fs_s_done: srl t1, t0, 23 # get exponent and t1, t1, 0xFF and t2, t0, 0x7FFFFF # get fraction srl t0, t0, 31 # get sign bne t1, SEXP_INF, 1f # is it a signaling NAN? and v0, t2, SSIGNAL_NAN bne v0, zero, invalid_s 1: j ra END(get_ft_fs_s) /*---------------------------------------------------------------------------- * get_ft_fs_d -- * * Read (double precision) the FT register (bits 20-16) and * the FS register (bits 15-11) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the FS sign * t1 contains the FS (biased) exponent * t2 contains the FS fraction * ta0 contains the FT sign * ta1 contains the FT (biased) exponent * ta2 contains the FT fraction * *---------------------------------------------------------------------------- */ #define GET_FT_FS_D(n) \ .rdata; \ .dword get_ft_fs_d_/**/n; \ .text; \ get_ft_fs_d_/**/n: \ dmfc1 ta2, $/**/n; \ b get_ft_d_done LEAF(get_ft_fs_d, 0) srl a3, a0, 16 - 3 # get FT field and a3, a3, 0x1f << 3 # mask FT field ld a3, get_ft_d_tbl(a3) # switch on register number j a3 .rdata get_ft_d_tbl: .text GET_FT_FS_D(f0) GET_FT_FS_D(f1) GET_FT_FS_D(f2) GET_FT_FS_D(f3) GET_FT_FS_D(f4) GET_FT_FS_D(f5) GET_FT_FS_D(f6) GET_FT_FS_D(f7) GET_FT_FS_D(f8) GET_FT_FS_D(f9) GET_FT_FS_D(f10) GET_FT_FS_D(f11) GET_FT_FS_D(f12) GET_FT_FS_D(f13) GET_FT_FS_D(f14) GET_FT_FS_D(f15) GET_FT_FS_D(f16) GET_FT_FS_D(f17) GET_FT_FS_D(f18) GET_FT_FS_D(f19) GET_FT_FS_D(f20) GET_FT_FS_D(f21) GET_FT_FS_D(f22) GET_FT_FS_D(f23) GET_FT_FS_D(f24) GET_FT_FS_D(f25) GET_FT_FS_D(f26) GET_FT_FS_D(f27) GET_FT_FS_D(f28) GET_FT_FS_D(f29) GET_FT_FS_D(f30) GET_FT_FS_D(f31) get_ft_d_done: dsrl ta0, ta2, 63 # get sign dsrl ta1, ta2, 52 # get exponent and ta1, ta1, 0x7FF dsll ta2, 12 dsrl ta2, 12 # get fraction bne ta1, DEXP_INF, 1f # is it a signaling NAN? and v0, ta2, DSIGNAL_NAN bne v0, zero, invalid_d 1: /* fall through to get FS */ /*---------------------------------------------------------------------------- * get_fs_d -- * * Read (double precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * *---------------------------------------------------------------------------- */ #define GET_FS_D(n) \ .rdata; \ .dword get_fs_d_/**/n; \ .text; \ get_fs_d_/**/n: \ dmfc1 t2, $/**/n; \ b get_fs_d_done ALEAF(get_fs_d) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, get_fs_d_tbl(a3) # switch on register number j a3 .rdata get_fs_d_tbl: .text GET_FS_D(f0) GET_FS_D(f1) GET_FS_D(f2) GET_FS_D(f3) GET_FS_D(f4) GET_FS_D(f5) GET_FS_D(f6) GET_FS_D(f7) GET_FS_D(f8) GET_FS_D(f9) GET_FS_D(f10) GET_FS_D(f11) GET_FS_D(f12) GET_FS_D(f13) GET_FS_D(f14) GET_FS_D(f15) GET_FS_D(f16) GET_FS_D(f17) GET_FS_D(f18) GET_FS_D(f19) GET_FS_D(f20) GET_FS_D(f21) GET_FS_D(f22) GET_FS_D(f23) GET_FS_D(f24) GET_FS_D(f25) GET_FS_D(f26) GET_FS_D(f27) GET_FS_D(f28) GET_FS_D(f29) GET_FS_D(f30) GET_FS_D(f31) get_fs_d_done: dsrl t0, t2, 63 # get sign dsrl t1, t2, 52 # get exponent and t1, t1, 0x7FF dsll t2, 12 dsrl t2, 12 # get fraction bne t1, DEXP_INF, 1f # is it a signaling NAN? and v0, t2, DSIGNAL_NAN bne v0, zero, invalid_d 1: j ra END(get_ft_fs_d) /*---------------------------------------------------------------------------- * get_cmp_s -- * * Read (single precision) the FS register (bits 15-11) and * the FT register (bits 20-16) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * ta0 contains the sign * ta1 contains the (biased) exponent * ta2 contains the fraction * *---------------------------------------------------------------------------- */ #define CMP_FS_S(n) \ .rdata; \ .dword cmp_fs_s_/**/n; \ .text; \ cmp_fs_s_/**/n: \ mfc1 t0, $/**/n; \ b cmp_fs_s_done LEAF(get_cmp_s, 0) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, cmp_fs_s_tbl(a3) # switch on register number j a3 .rdata cmp_fs_s_tbl: .text CMP_FS_S(f0) CMP_FS_S(f1) CMP_FS_S(f2) CMP_FS_S(f3) CMP_FS_S(f4) CMP_FS_S(f5) CMP_FS_S(f6) CMP_FS_S(f7) CMP_FS_S(f8) CMP_FS_S(f9) CMP_FS_S(f10) CMP_FS_S(f11) CMP_FS_S(f12) CMP_FS_S(f13) CMP_FS_S(f14) CMP_FS_S(f15) CMP_FS_S(f16) CMP_FS_S(f17) CMP_FS_S(f18) CMP_FS_S(f19) CMP_FS_S(f20) CMP_FS_S(f21) CMP_FS_S(f22) CMP_FS_S(f23) CMP_FS_S(f24) CMP_FS_S(f25) CMP_FS_S(f26) CMP_FS_S(f27) CMP_FS_S(f28) CMP_FS_S(f29) CMP_FS_S(f30) CMP_FS_S(f31) cmp_fs_s_done: srl t1, t0, 23 # get exponent and t1, t1, 0xFF and t2, t0, 0x7FFFFF # get fraction srl t0, t0, 31 # get sign #define CMP_FT_S(n) \ .rdata; \ .dword cmp_ft_s_/**/n; \ .text; \ cmp_ft_s_/**/n: \ mfc1 ta0, $/**/n; \ b cmp_ft_s_done srl a3, a0, 16 - 3 # get FT field and a3, a3, 0x1f << 3 # mask FT field ld a3, cmp_ft_s_tbl(a3) # switch on register number j a3 .rdata cmp_ft_s_tbl: .text CMP_FT_S(f0) CMP_FT_S(f1) CMP_FT_S(f2) CMP_FT_S(f3) CMP_FT_S(f4) CMP_FT_S(f5) CMP_FT_S(f6) CMP_FT_S(f7) CMP_FT_S(f8) CMP_FT_S(f9) CMP_FT_S(f10) CMP_FT_S(f11) CMP_FT_S(f12) CMP_FT_S(f13) CMP_FT_S(f14) CMP_FT_S(f15) CMP_FT_S(f16) CMP_FT_S(f17) CMP_FT_S(f18) CMP_FT_S(f19) CMP_FT_S(f20) CMP_FT_S(f21) CMP_FT_S(f22) CMP_FT_S(f23) CMP_FT_S(f24) CMP_FT_S(f25) CMP_FT_S(f26) CMP_FT_S(f27) CMP_FT_S(f28) CMP_FT_S(f29) CMP_FT_S(f30) cmp_ft_s_done: srl ta1, ta0, 23 # get exponent and ta1, ta1, 0xFF and ta2, ta0, 0x7FFFFF # get fraction srl ta0, ta0, 31 # get sign j ra END(get_cmp_s) /*---------------------------------------------------------------------------- * get_cmp_d -- * * Read (double precision) the FS register (bits 15-11) and * the FT register (bits 20-16) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * ta0 contains the sign * ta1 contains the (biased) exponent * ta2 contains the fraction * *---------------------------------------------------------------------------- */ #define CMP_FS_D(n) \ .rdata; \ .dword cmp_fs_d_/**/n; \ .text; \ cmp_fs_d_/**/n: \ dmfc1 t2, $/**/n; \ b cmp_fs_d_done LEAF(get_cmp_d, 0) srl a3, a0, 11 - 3 # get FS field and a3, a3, 0x1f << 3 # mask FS field ld a3, cmp_fs_d_tbl(a3) # switch on register number j a3 .rdata cmp_fs_d_tbl: .text CMP_FS_D(f0) CMP_FS_D(f1) CMP_FS_D(f2) CMP_FS_D(f3) CMP_FS_D(f4) CMP_FS_D(f5) CMP_FS_D(f6) CMP_FS_D(f7) CMP_FS_D(f8) CMP_FS_D(f9) CMP_FS_D(f10) CMP_FS_D(f11) CMP_FS_D(f12) CMP_FS_D(f13) CMP_FS_D(f14) CMP_FS_D(f15) CMP_FS_D(f16) CMP_FS_D(f17) CMP_FS_D(f18) CMP_FS_D(f19) CMP_FS_D(f20) CMP_FS_D(f21) CMP_FS_D(f22) CMP_FS_D(f23) CMP_FS_D(f24) CMP_FS_D(f25) CMP_FS_D(f26) CMP_FS_D(f27) CMP_FS_D(f28) CMP_FS_D(f29) CMP_FS_D(f30) CMP_FS_D(f31) cmp_fs_d_done: dsrl t0, t2, 63 # get sign dsrl t1, t2, 52 # get exponent and t1, t1, 0x7FF dsll t2, 12 dsrl t2, 12 # get fraction #define CMP_FT_D(n) \ .rdata; \ .dword cmp_ft_d_/**/n; \ .text; \ cmp_ft_d_/**/n: \ dmfc1 ta2, $/**/n; \ b cmp_ft_d_done srl a3, a0, 16 - 3 # get FT field and a3, a3, 0x1f << 3 # mask FT field ld a3, cmp_ft_d_tbl(a3) # switch on register number j a3 .rdata cmp_ft_d_tbl: .text CMP_FT_D(f0) CMP_FT_D(f1) CMP_FT_D(f2) CMP_FT_D(f3) CMP_FT_D(f4) CMP_FT_D(f5) CMP_FT_D(f6) CMP_FT_D(f7) CMP_FT_D(f8) CMP_FT_D(f9) CMP_FT_D(f10) CMP_FT_D(f11) CMP_FT_D(f12) CMP_FT_D(f13) CMP_FT_D(f14) CMP_FT_D(f15) CMP_FT_D(f16) CMP_FT_D(f17) CMP_FT_D(f18) CMP_FT_D(f19) CMP_FT_D(f20) CMP_FT_D(f21) CMP_FT_D(f22) CMP_FT_D(f23) CMP_FT_D(f24) CMP_FT_D(f25) CMP_FT_D(f26) CMP_FT_D(f27) CMP_FT_D(f28) CMP_FT_D(f29) CMP_FT_D(f30) CMP_FT_D(f31) cmp_ft_d_done: dsrl ta0, ta2, 63 # get sign dsrl ta1, ta2, 52 # get exponent and ta1, ta1, 0x7FF dsll ta2, 12 dsrl ta2, 12 # get fraction j ra END(get_cmp_d) /*---------------------------------------------------------------------------- * set_fd_s -- * * Write (single precision) the FD register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * * set_fd_word -- * * Write (integer) the FD register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t2 contains the integer * *---------------------------------------------------------------------------- */ #define SET_FD_S(n) \ .rdata; \ .dword set_fd_s_/**/n; \ .text; \ set_fd_s_/**/n: \ mtc1 t2, $/**/n; \ j ra LEAF(set_fd_s, 0) sll t0, t0, 31 # position sign sll t1, t1, 23 # position exponent or t2, t2, t0 or t2, t2, t1 ALEAF(set_fd_word) srl a3, a0, 6 - 3 # get FD field and a3, a3, 0x1f << 3 # mask FT field ld a3, set_fd_s_tbl(a3) # switch on register number j a3 .rdata set_fd_s_tbl: .text SET_FD_S(f0) SET_FD_S(f1) SET_FD_S(f2) SET_FD_S(f3) SET_FD_S(f4) SET_FD_S(f5) SET_FD_S(f6) SET_FD_S(f7) SET_FD_S(f8) SET_FD_S(f9) SET_FD_S(f10) SET_FD_S(f11) SET_FD_S(f12) SET_FD_S(f13) SET_FD_S(f14) SET_FD_S(f15) SET_FD_S(f16) SET_FD_S(f17) SET_FD_S(f18) SET_FD_S(f19) SET_FD_S(f20) SET_FD_S(f21) SET_FD_S(f22) SET_FD_S(f23) SET_FD_S(f24) SET_FD_S(f25) SET_FD_S(f26) SET_FD_S(f27) SET_FD_S(f28) SET_FD_S(f29) SET_FD_S(f30) SET_FD_S(f31) END(set_fd_s) /*---------------------------------------------------------------------------- * set_fd_d -- * * Write (double precision) the FT register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * *---------------------------------------------------------------------------- */ #define SET_FD_D(n) \ .rdata; \ .dword set_fd_d_/**/n; \ .text; \ set_fd_d_/**/n: \ dmtc1 t0, $/**/n; \ j ra LEAF(set_fd_d, 0) dsll t0, 63 # set sign dsll t1, t1, 52 # set exponent or t0, t0, t1 or t0, t0, t2 # set fraction srl a3, a0, 6 - 3 # get FD field and a3, a3, 0x1f << 3 # mask FD field ld a3, set_fd_d_tbl(a3) # switch on register number j a3 .rdata set_fd_d_tbl: .text SET_FD_D(f0) SET_FD_D(f1) SET_FD_D(f2) SET_FD_D(f3) SET_FD_D(f4) SET_FD_D(f5) SET_FD_D(f6) SET_FD_D(f7) SET_FD_D(f8) SET_FD_D(f9) SET_FD_D(f10) SET_FD_D(f11) SET_FD_D(f12) SET_FD_D(f13) SET_FD_D(f14) SET_FD_D(f15) SET_FD_D(f16) SET_FD_D(f17) SET_FD_D(f18) SET_FD_D(f19) SET_FD_D(f20) SET_FD_D(f21) SET_FD_D(f22) SET_FD_D(f23) SET_FD_D(f24) SET_FD_D(f25) SET_FD_D(f26) SET_FD_D(f27) SET_FD_D(f28) SET_FD_D(f29) SET_FD_D(f30) SET_FD_D(f31) END(set_fd_d) /*---------------------------------------------------------------------------- * renorm_fs_s -- * * Results: * t1 unbiased exponent * t2 normalized fraction * *---------------------------------------------------------------------------- */ LEAF(renorm_fs_s, 0) /* * Find out how many leading zero bits are in t2 and put in t9. */ move v0, t2 move t9, zero srl v1, v0, 16 bne v1, zero, 1f addu t9, 16 sll v0, 16 1: srl v1, v0, 24 bne v1, zero, 1f addu t9, 8 sll v0, 8 1: srl v1, v0, 28 bne v1, zero, 1f addu t9, 4 sll v0, 4 1: srl v1, v0, 30 bne v1, zero, 1f addu t9, 2 sll v0, 2 1: srl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2 the correct number of bits. */ 1: subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros li t1, SEXP_MIN subu t1, t1, t9 # adjust exponent sll t2, t2, t9 j ra END(renorm_fs_s) /*---------------------------------------------------------------------------- * renorm_fs_d -- * * Results: * t1 unbiased exponent * t2 normalized fraction * *---------------------------------------------------------------------------- */ LEAF(renorm_fs_d, 0) /* * Find out how many leading zero bits are in t2 and put in t9. */ move v0, t2 move t9, zero dsrl v1, v0, 32 bne v1, zero, 1f addu t9, 32 dsll v0, 32 1: dsrl v1, v0, 16 bne v1, zero, 1f addu t9, 16 dsll v0, 16 1: dsrl v1, v0, 24 bne v1, zero, 1f addu t9, 8 dsll v0, 8 1: dsrl v1, v0, 28 bne v1, zero, 1f addu t9, 4 dsll v0, 4 1: dsrl v1, v0, 30 bne v1, zero, 1f addu t9, 2 dsll v0, 2 1: dsrl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros li t1, DEXP_MIN subu t1, t9 # adjust exponent dsll t2, t9 j ra END(renorm_fs_d) /*---------------------------------------------------------------------------- * renorm_ft_s -- * * Results: * ta1 unbiased exponent * ta2 normalized fraction * *---------------------------------------------------------------------------- */ LEAF(renorm_ft_s, 0) /* * Find out how many leading zero bits are in ta2 and put in t9. */ move v0, ta2 move t9, zero srl v1, v0, 16 bne v1, zero, 1f addu t9, 16 sll v0, 16 1: srl v1, v0, 24 bne v1, zero, 1f addu t9, 8 sll v0, 8 1: srl v1, v0, 28 bne v1, zero, 1f addu t9, 4 sll v0, 4 1: srl v1, v0, 30 bne v1, zero, 1f addu t9, 2 sll v0, 2 1: srl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift ta2 the correct number of bits. */ 1: subu t9, t9, SLEAD_ZEROS # dont count normal leading zeros li ta1, SEXP_MIN subu ta1, t9 # adjust exponent sll ta2, t9 j ra END(renorm_ft_s) /*---------------------------------------------------------------------------- * renorm_ft_d -- * * Results: * ta1 unbiased exponent * ta2 normalized fraction * *---------------------------------------------------------------------------- */ LEAF(renorm_ft_d, 0) /* * Find out how many leading zero bits are in ta2 and put in t9. */ move v0, ta2 move t9, zero dsrl v1, v0, 32 bne v1, zero, 1f addu t9, 32 dsll v0, 32 1: dsrl v1, v0, 16 bne v1, zero, 1f addu t9, 16 dsll v0, 16 1: dsrl v1, v0, 24 bne v1, zero, 1f addu t9, 8 dsll v0, 8 1: dsrl v1, v0, 28 bne v1, zero, 1f addu t9, 4 dsll v0, 4 1: dsrl v1, v0, 30 bne v1, zero, 1f addu t9, 2 dsll v0, 2 1: dsrl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift ta2 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros li ta1, DEXP_MIN subu ta1, t9 # adjust exponent dsll ta2, t9 j ra END(renorm_ft_d)