/* $NetBSD: fp.S,v 1.33 2007/10/17 19:55:37 garbled 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. 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. * * @(#)fp.s 8.1 (Berkeley) 6/10/93 */ #include <sys/cdefs.h> #include <mips/asm.h> #include <mips/cpu.h> #include <mips/trap.h> #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 0x00100000 #define SLEAD_ZEROS 31 - 23 #define DLEAD_ZEROS 31 - 20 #define STICKYBIT 1 #define GUARDBIT 0x80000000 #define SSIGNAL_NAN 0x00400000 #define DSIGNAL_NAN 0x00080000 #define SQUIET_NAN 0x003fffff #define DQUIET_NAN0 0x0007ffff #define DQUIET_NAN1 0xffffffff #define INT_MIN 0x80000000 #define INT_MAX 0x7fffffff #define COND_UNORDERED 0x1 #define COND_EQUAL 0x2 #define COND_LESS 0x4 #define COND_SIGNAL 0x8 #if SZREG == 8 #define SZREG_SHFT 3 #define SZREG_MASK 0x00f8 #else #define SZREG_SHFT 2 #define SZREG_MASK 0x007c #endif /* insns are reordered in the way as MIPS architecture imposes */ .set reorder /*---------------------------------------------------------------------------- * * MachEmulateFP -- * * Emulate unimplemented floating point operations. * This routine should only be called by MachFPInterrupt(). * * MachEmulateFP(instr, frame, cause) * u_int32_t instr; * struct frame *frame; * u_int32_t cause; * * Results: * None. * * Side effects: * Floating point registers are modified according to instruction. * *---------------------------------------------------------------------------- */ NESTED(MachEmulateFP, CALLFRAME_SIZ, ra) subu sp, sp, CALLFRAME_SIZ sw ra, CALLFRAME_RA(sp) sw a1, CALLFRAME_SIZ + 4(sp) sw a2, CALLFRAME_SIZ + 8(sp) /* * Decode the FMT field (bits 25-21) and FUNCTION field (bits 5-0). */ srl v0, a0, 21 - 2 # get FMT field andi v0, v0, 0x1F << 2 # mask FMT field #ifdef SOFTFLOAT lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process lw a3, fmt_tbl(v0) # switch on FUNC & FMT lw a2, U_PCB_FPREGS+FRAME_FSR(t0) #else cfc1 a2, MIPS_FPU_CSR # get exception register lw a3, fmt_tbl(v0) # switch on FUNC & FMT and a2, a2, ~MIPS_FPU_EXCEPTION_UNIMPL # clear exception ctc1 a2, MIPS_FPU_CSR #endif j a3 single_op: andi v0, a0, 0x3F # get FUNC field sll v0, v0, 2 lw v0, func_single_tbl(v0) j v0 double_op: andi v0, a0, 0x3F # get FUNC field sll v0, v0, 2 lw v0, func_double_tbl(v0) j v0 single_fixed_op: andi v0, a0, 0x3F # get FUNC field sll v0, v0, 2 lw v0, func_single_fixed_tbl(v0) j v0 long_fixed_op: andi v0, a0, 0x3F # get FUNC field sll v0, v0, 2 lw v0, func_long_fixed_tbl(v0) j v0 .rdata fmt_tbl: #ifdef SOFTFLOAT .word mfromc1 # sub 0 #else .word ill # sub 0 #endif .word ill # sub 1 #ifdef SOFTFLOAT .word cfromc1 # sub 2 #else .word ill # sub 2 #endif .word ill # sub 3 #ifdef SOFTFLOAT .word mtoc1 # sub 4 #else .word ill # sub 4 #endif .word ill # sub 5 #ifdef SOFTFLOAT .word ctoc1 # sub 6 #else .word ill # sub 6 #endif .word ill # sub 7 #ifdef SOFTFLOAT .word branchc1 # sub 8 #else .word ill # sub 8 #endif .word ill # sub 9 .word ill # sub 10 .word ill # sub 11 .word ill # sub 12 .word ill # sub 13 .word ill # sub 14 .word ill # sub 15 .word single_op # sub 16 .word double_op # sub 17 .word ill # sub 18 .word ill # sub 19 .word single_fixed_op # sub 20 .word long_fixed_op # sub 21 .word ill # sub 22 .word ill # sub 23 .word ill # sub 24 .word ill # sub 25 .word ill # sub 26 .word ill # sub 27 .word ill # sub 28 .word ill # sub 29 .word ill # sub 30 .word ill # sub 31 func_single_tbl: .word add_s # func 0 .word sub_s # func 1 .word mul_s # func 2 .word div_s # func 3 #ifdef MIPS3_PLUS .word sqrt_s # func 4 #else .word ill # func 4 #endif .word abs_s # func 5 .word mov_s # func 6 .word neg_s # func 7 .word ill # func 8 .word ill # func 9 .word ill # func 10 .word ill # func 11 #ifdef MIPS3_PLUS .word round_w_s # func 12 /* MIPS2 FP instructions */ .word trunc_w_s # func 13 .word ceil_w_s # func 14 .word floor_w_s # func 15 #else .word ill # func 12 .word ill # func 13 .word ill # func 14 .word ill # func 15 #endif .word ill # func 16 .word ill # func 17 .word ill # func 18 .word ill # func 19 .word ill # func 20 .word ill # func 21 .word ill # func 22 .word ill # func 23 .word ill # func 24 .word ill # func 25 .word ill # func 26 .word ill # func 27 .word ill # func 28 .word ill # func 29 .word ill # func 30 .word ill # func 31 .word ill # func 32 .word cvt_d_s # func 33 .word ill # func 34 .word ill # func 35 .word cvt_w_s # func 36 .word ill # func 37 .word ill # func 38 .word ill # func 39 .word ill # func 40 .word ill # func 41 .word ill # func 42 .word ill # func 43 .word ill # func 44 .word ill # func 45 .word ill # func 46 .word ill # func 47 .word cmp_s # func 48 .word cmp_s # func 49 .word cmp_s # func 50 .word cmp_s # func 51 .word cmp_s # func 52 .word cmp_s # func 53 .word cmp_s # func 54 .word cmp_s # func 55 .word cmp_s # func 56 .word cmp_s # func 57 .word cmp_s # func 58 .word cmp_s # func 59 .word cmp_s # func 60 .word cmp_s # func 61 .word cmp_s # func 62 .word cmp_s # func 63 func_double_tbl: .word add_d # func 0 .word sub_d # func 1 .word mul_d # func 2 .word div_d # func 3 #ifdef MIPS3_PLUS .word sqrt_d # func 4 #else .word ill # func 4 #endif .word abs_d # func 5 .word mov_d # func 6 .word neg_d # func 7 .word ill # func 8 .word ill # func 9 .word ill # func 10 .word ill # func 11 #ifdef MIPS3_PLUS .word round_w_d # func 12 /* MIPS2 FP instructions */ .word trunc_w_d # func 13 .word ceil_w_d # func 14 .word floor_w_d # func 15 #else .word ill # func 12 .word ill # func 13 .word ill # func 14 .word ill # func 15 #endif .word ill # func 16 .word ill # func 17 .word ill # func 18 .word ill # func 19 .word ill # func 20 .word ill # func 21 .word ill # func 22 .word ill # func 23 .word ill # func 24 .word ill # func 25 .word ill # func 26 .word ill # func 27 .word ill # func 28 .word ill # func 29 .word ill # func 30 .word ill # func 31 .word cvt_s_d # func 32 .word ill # func 33 .word ill # func 34 .word ill # func 35 .word cvt_w_d # func 36 .word ill # func 37 .word ill # func 38 .word ill # func 39 .word ill # func 40 .word ill # func 41 .word ill # func 42 .word ill # func 43 .word ill # func 44 .word ill # func 45 .word ill # func 46 .word ill # func 47 .word cmp_d # func 48 .word cmp_d # func 49 .word cmp_d # func 50 .word cmp_d # func 51 .word cmp_d # func 52 .word cmp_d # func 53 .word cmp_d # func 54 .word cmp_d # func 55 .word cmp_d # func 56 .word cmp_d # func 57 .word cmp_d # func 58 .word cmp_d # func 59 .word cmp_d # func 60 .word cmp_d # func 61 .word cmp_d # func 62 .word cmp_d # func 63 func_single_fixed_tbl: .word ill # func 0 .word ill # func 1 .word ill # func 2 .word ill # func 3 .word ill # func 4 .word ill # func 5 .word ill # func 6 .word ill # func 7 .word ill # func 8 .word ill # func 9 .word ill # func 10 .word ill # func 11 .word ill # func 12 .word ill # func 13 .word ill # func 14 .word ill # func 15 .word ill # func 16 .word ill # func 17 .word ill # func 18 .word ill # func 19 .word ill # func 20 .word ill # func 21 .word ill # func 22 .word ill # func 23 .word ill # func 24 .word ill # func 25 .word ill # func 26 .word ill # func 27 .word ill # func 28 .word ill # func 29 .word ill # func 30 .word ill # func 31 .word cvt_s_w # func 32 .word cvt_d_w # func 33 .word ill # func 34 .word ill # func 35 .word ill # func 36 .word ill # func 37 .word ill # func 38 .word ill # func 39 .word ill # func 40 .word ill # func 41 .word ill # func 42 .word ill # func 43 .word ill # func 44 .word ill # func 45 .word ill # func 46 .word ill # func 47 .word ill # func 48 .word ill # func 49 .word ill # func 50 .word ill # func 51 .word ill # func 52 .word ill # func 53 .word ill # func 54 .word ill # func 55 .word ill # func 56 .word ill # func 57 .word ill # func 58 .word ill # func 59 .word ill # func 60 .word ill # func 61 .word ill # func 62 .word ill # func 63 func_long_fixed_tbl: .word ill # func 0 .word ill # func 1 .word ill # func 2 .word ill # func 3 .word ill # func 4 .word ill # func 5 .word ill # func 6 .word ill # func 7 .word ill # func 8 .word ill # func 9 .word ill # func 10 .word ill # func 11 .word ill # func 12 .word ill # func 13 .word ill # func 14 .word ill # func 15 .word ill # func 16 .word ill # func 17 .word ill # func 18 .word ill # func 19 .word ill # func 20 .word ill # func 21 .word ill # func 22 .word ill # func 23 .word ill # func 24 .word ill # func 25 .word ill # func 26 .word ill # func 27 .word ill # func 28 .word ill # func 29 .word ill # func 30 .word ill # func 31 .word ill # func 32 .word ill # func 33 .word ill # func 34 .word ill # func 35 .word ill # func 36 .word ill # func 37 .word ill # func 38 .word ill # func 39 .word ill # func 40 .word ill # func 41 .word ill # func 42 .word ill # func 43 .word ill # func 44 .word ill # func 45 .word ill # func 46 .word ill # func 47 .word ill # func 48 .word ill # func 49 .word ill # func 50 .word ill # func 51 .word ill # func 52 .word ill # func 53 .word ill # func 54 .word ill # func 55 .word ill # func 56 .word ill # func 57 .word ill # func 58 .word ill # func 59 .word ill # func 60 .word ill # func 61 .word ill # func 62 .word ill # func 63 .text #ifdef SOFTFLOAT mfromc1: srl t1, a0, 11-2 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x007C addu t0, t0, t1 lw v0, U_PCB_FPREGS+FRAME_FP0(t0) srl t0, a0, 16-SZREG_SHFT andi t0, t0, SZREG_MASK addu t0, t0, a1 REG_PROLOGUE REG_S v0, FRAME_ZERO(t0) REG_EPILOGUE b done mtoc1: REG_PROLOGUE REG_S zero, FRAME_ZERO(a1) # ensure zero has value 0 srl t0, a0, 16-SZREG_SHFT andi t0, t0, SZREG_MASK addu v0, a1, t0 REG_L v0, FRAME_ZERO(v0) REG_EPILOGUE srl t1, a0, 11-2 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x007C addu t0, t0, t1 sw v0, U_PCB_FPREGS+FRAME_FP0(t0) b done cfromc1: srl t1, a0, 11 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x001F li t2, 0x1F move v0, zero bne t1, t2, cfinvalid lw v0, U_PCB_FPREGS+FRAME_FSR(t0) cfinvalid: srl t0, a0, 16-SZREG_SHFT andi t0, t0, SZREG_MASK addu t0, t0, a1 REG_PROLOGUE REG_S v0, FRAME_ZERO(t0) REG_EPILOGUE b done ctoc1: REG_PROLOGUE REG_S zero, FRAME_ZERO(a1) # ensure zero has value 0 REG_EPILOGUE srl t0, a0, 11 andi t0, t0, 0x001F li t1, 0x1F bne t0, t1, done srl t0, a0, 16-SZREG_SHFT andi t0, t0, SZREG_MASK addu v0, a1, t0 REG_PROLOGUE REG_L v0, FRAME_ZERO(v0) REG_EPILOGUE lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw v0, U_PCB_FPREGS+FRAME_FSR(t0) b done branchc1: srl v0, a0, 16-2 andi v0, v0, 0x007C lw v0, branchc1_tbl(v0) j v0 .rdata branchc1_tbl: .word bcfalse # br 0 .word bctrue # br 1 .word bcfalse_l # br 2 .word bctrue_l # br 3 .word ill # br 4 .word ill # br 5 .word ill # br 6 .word ill # br 7 .word ill # br 8 .word ill # br 9 .word ill # br 10 .word ill # br 11 .word ill # br 12 .word ill # br 13 .word ill # br 14 .word ill # br 15 .word ill # br 16 .word ill # br 17 .word ill # br 18 .word ill # br 19 .word ill # br 20 .word ill # br 21 .word ill # br 22 .word ill # br 23 .word ill # br 24 .word ill # br 25 .word ill # br 26 .word ill # br 27 .word ill # br 28 .word ill # br 29 .word ill # br 30 .word ill # br 31 .text bcfalse: li v0, MIPS_FPU_COND_BIT and v0, v0, a2 beq v0, zero, bcemul_branch b done bctrue: li v0, MIPS_FPU_COND_BIT and v0, v0, a2 bne v0, zero, bcemul_branch b done bcfalse_l: li v0, MIPS_FPU_COND_BIT and v0, v0, a2 beq v0, zero, bcemul_branch REG_PROLOGUE REG_L v0, FRAME_EPC(a1) addiu v0, v0, 4 REG_S v0, FRAME_EPC(a1) REG_EPILOGUE b done bctrue_l: li v0, MIPS_FPU_COND_BIT and v0, v0, a2 bne v0, zero, bcemul_branch REG_PROLOGUE REG_L v0, FRAME_EPC(a1) addiu v0, v0, 4 REG_S v0, FRAME_EPC(a1) REG_EPILOGUE b done bcemul_branch: /* Fetch delay slot instruction */ sw a1, CALLFRAME_SIZ + 4(sp) REG_PROLOGUE REG_L a0, FRAME_EPC(a1) REG_EPILOGUE addiu a0, a0, 4 jal _C_LABEL(fuiword) move a0, v0 lw a1, CALLFRAME_SIZ + 4(sp) lw a2, CALLFRAME_SIZ + 8(sp) /* Update cause */ li t0, MIPS_CR_BR_DELAY or a2, a2, t0 /* Free MachEmulateFP call frame */ lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j _C_LABEL(bcemul_delay_slot) #endif /* * Single precision subtract. */ sub_s: jal _C_LABEL(get_ft_fs_s) xor ta0, ta0, 1 # negate FT sign bit b add_sub_s /* * Single precision add. */ add_s: jal _C_LABEL(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 _C_LABEL(renorm_fs_s) jal _C_LABEL(renorm_ft_s) b 5f 2: jal _C_LABEL(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, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode bne v0, MIPS_FPU_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 4: bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_s # FT is zero, result=FS subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit jal _C_LABEL(renorm_ft_s) b 5f 2: subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_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, 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, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode bne v0, MIPS_FPU_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 _C_LABEL(get_ft_fs_d) xor ta0, ta0, 1 # negate sign bit b add_sub_d /* * Double precision add. */ add_d: jal _C_LABEL(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 t3, zero, result_fs_d bne ta2, zero, result_ft_d # if FT is NAN, result is FT bne ta3, zero, result_ft_d 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? bne t2, zero, 1f # is FS zero? beq t3, zero, 3f 1: bne ta1, zero, 2f # is FT a denormalized num? bne ta2, zero, 1f beq ta3, zero, result_fs_d # FT is zero, result=FS 1: jal _C_LABEL(renorm_fs_d) jal _C_LABEL(renorm_ft_d) b 5f 2: jal _C_LABEL(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 bne ta3, zero, result_ft_d and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode bne v0, MIPS_FPU_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? bne ta2, zero, 1f beq ta3, zero, result_fs_d # FT is zero, result=FS 1: subu t1, t1, DEXP_BIAS # unbias FS exponent or t2, t2, DIMPL_ONE # set implied one bit jal _C_LABEL(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 move t3, zero b 4f 1: move ta2, zero # FTs fraction shifted is zero move ta3, zero b 4f 2: li t9, 32 bge v0, zero, 3f # if FS > FT, shift FTs frac move t1, ta1 # FT > FS, result exp is FTs blt v1, t9, 1f # shift right by < 32? subu v1, v1, t9 subu t9, t9, v1 sll t8, t2, t9 # save bits shifted out sltu t9, zero, t3 # dont lose any one bits or t8, t8, t9 # save sticky bit srl t3, t2, v1 # shift FSs fraction move t2, zero b 4f 1: subu t9, t9, v1 sll t8, t3, t9 # save bits shifted out srl t3, t3, v1 # shift FSs fraction sll t9, t2, t9 # save bits shifted out of t2 or t3, t3, t9 # and put into t3 srl t2, t2, v1 b 4f 3: blt v1, t9, 1f # shift right by < 32? subu v1, v1, t9 subu t9, t9, v1 sll t8, ta2, t9 # save bits shifted out srl ta3, ta2, v1 # shift FTs fraction move ta2, zero b 4f 1: subu t9, t9, v1 sll t8, ta3, t9 # save bits shifted out srl ta3, ta3, v1 # shift FTs fraction sll t9, ta2, t9 # save bits shifted out of t2 or ta3, ta3, t9 # and put into t3 srl ta2, ta2, v1 4: bne t0, ta0, 1f # if signs differ, subtract addu t3, t3, ta3 # add fractions sltu t9, t3, ta3 # compute carry addu t2, t2, ta2 # add fractions addu t2, t2, t9 # add carry b norm_d 1: blt t2, ta2, 3f # subtract larger from smaller bne t2, ta2, 2f bltu t3, ta3, 3f bne t3, ta3, 2f # if same, result=0 move t1, zero # result=0 move t2, zero move t3, zero and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode bne v0, MIPS_FPU_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: beq t8, zero, 1f # compute t2:t3:zero - ta2:ta3:t8 subu t8, zero, t8 sltu v0, t3, 1 # compute barrow out subu t3, t3, 1 # subtract barrow subu t2, t2, v0 1: sltu v0, t3, ta3 subu t3, t3, ta3 # subtract fractions subu t2, t2, ta2 # subtract fractions subu t2, t2, v0 # subtract barrow b norm_d 3: move t0, ta0 # sign of result = FTs beq t8, zero, 1f # compute ta2:ta3:zero - t2:t3:t8 subu t8, zero, t8 sltu v0, ta3, 1 # compute barrow out subu ta3, ta3, 1 # subtract barrow subu ta2, ta2, v0 1: sltu v0, ta3, t3 subu t3, ta3, t3 # subtract fractions subu t2, ta2, t2 # subtract fractions subu t2, t2, v0 # subtract barrow b norm_d /* * Single precision multiply. */ mul_s: jal _C_LABEL(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 _C_LABEL(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 _C_LABEL(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 _C_LABEL(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 t3, zero, result_fs_d 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 bne ta3, zero, result_ft_d 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 bne ta3, 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 t3, zero, result_ft_d bne ta2, zero, result_ft_d # if FT is a NAN, result=FT bne ta3, zero, result_ft_d b invalid_d # zero * infinity is invalid 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f beq t3, zero, result_fs_d # result is zero 1: jal _C_LABEL(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 beq ta3, zero, result_ft_d # result is zero 1: jal _C_LABEL(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 # ??? multu t3, ta3 # multiply fractions (low * low) move ta0, t2 # free up t2,t3 for result move ta1, t3 mflo a3 # save low order bits mfhi t8 not v0, t8 multu ta0, ta3 # multiply FS(high) * FT(low) mflo v1 mfhi t3 # init low result sltu v0, v0, v1 # compute carry addu t8, v1 multu ta1, ta2 # multiply FS(low) * FT(high) addu t3, t3, v0 # add carry not v0, t8 mflo v1 mfhi t2 sltu v0, v0, v1 addu t8, v1 multu ta0, ta2 # multiply FS(high) * FT(high) addu t3, v0 not v1, t3 sltu v1, v1, t2 addu t3, t2 not v0, t3 mfhi t2 addu t2, v1 mflo v1 sltu v0, v0, v1 addu t2, v0 addu t3, v1 sltu a3, zero, a3 # reduce t8,a3 to just t8 or t8, a3 b norm_d /* * Single precision divide. */ div_s: jal _C_LABEL(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 _C_LABEL(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 a2, a2, MIPS_FPU_EXCEPTION_DIV0 | MIPS_FPU_STICKY_DIV0 and v0, a2, MIPS_FPU_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw t1, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(t1) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif li t1, SEXP_INF # result is infinity move t2, zero b result_fs_s 1: jal _C_LABEL(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 _C_LABEL(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 t3, zero, result_fs_d bne ta1, DEXP_INF, result_fs_d # is FT an infinity? bne ta2, zero, result_ft_d # if FT is NAN, result is FT bne ta3, zero, result_ft_d 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 bne ta3, zero, result_ft_d move t1, zero # x / infinity is zero move t2, zero move t3, zero b result_fs_d 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f bne t3, zero, 1f bne ta1, zero, result_fs_d # FS=zero, is FT zero? bne ta2, zero, result_fs_d beq ta3, zero, invalid_d # 0 / 0 b result_fs_d # result = zero 1: jal _C_LABEL(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 bne ta3, zero, 1f or a2, a2, MIPS_FPU_EXCEPTION_DIV0 | MIPS_FPU_STICKY_DIV0 and v0, a2, MIPS_FPU_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw t1, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(t1) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif li t1, DEXP_INF # result is infinity move t2, zero move t3, zero b result_fs_d 1: jal _C_LABEL(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 t9, t3 move t2, zero # init result move t3, zero 1: bltu t8, ta2, 3f # is dividend >= divisor? bne t8, ta2, 2f bltu t9, ta3, 3f 2: sltu v1, t9, ta3 # subtract divisor from dividend subu t9, t9, ta3 subu t8, t8, ta2 subu t8, t8, v1 or t3, t3, 1 # remember that we did bne t8, zero, 3f # if not done, continue bne t9, zero, 3f li v1, 32 # shift result to final position blt v0, v1, 2f # shift < 32 bits? subu v0, v0, v1 # shift by > 32 bits sll t2, t3, v0 # shift upper part move t3, zero b norm_d 2: subu v1, v1, v0 # shift by < 32 bits sll t2, t2, v0 # shift upper part srl t9, t3, v1 # save bits shifted out or t2, t2, t9 # and put into upper part sll t3, t3, v0 b norm_d 3: sll t8, t8, 1 # shift dividend srl v1, t9, 31 # save bit shifted out or t8, t8, v1 # and put into upper part sll t9, t9, 1 sll t2, t2, 1 # shift result srl v1, t3, 31 # save bit shifted out or t2, t2, v1 # and put into upper part sll t3, t3, 1 subu v0, v0, 1 # are we done? bne v0, zero, 1b # no, continue sltu v0, zero, t9 # be sure to save any one bits or t8, t8, v0 # from the lower remainder b norm_d #ifdef MIPS3_PLUS sqrt_s: jal _C_LABEL(get_fs_s) /* Take care of zero, negative, inf, and NaN special cases */ or v0, t1, t2 # sqrt(+-0) == +-0 beq v0, zero, result_fs_s # ... bne t0, zero, 1f # sqrt(-val) == sNaN bne t1, SEXP_INF, 2f # skip forward if not infinity b result_fs_s # sqrt(NaN,+inf) == itself 1: move t0, zero # result is a quiet NAN li t1, SEXP_INF # sqrt(-inf,-val) == sNaN li t2, SQUIET_NAN b result_fs_s 2: /* normalize FS if needed */ bne t1, zero, 2f jal _C_LABEL(renorm_fs_s) 2: and t2, t2, (SIMPL_ONE-1) # ix &= 0x007fffff; or t2, t2, SIMPL_ONE # ix |= 0x00800000; and v0, t1, 1 # if (m & 1) beq v0, zero, 1f # ... add t2, t2, t2 # ix += ix; 1: sra t1, t1, 1 # m = m / 2; /* generate sqrt(FS) bit by bit */ add t2, t2, t2 # ix += ix; move ta0, zero # q = 0; (result) li t8, SIMPL_ONE<<1 # r = 0x01000000; move ta2, zero # s = 0; 1: beq t8, zero, 3f # while (r != 0) { add t9, ta2, t8 # t = s + r; bgt t9, t2, 2f # if (t <= ix) add ta2, t9, t8 # s = t + r; sub t2, t2, t9 # ix -= t; add ta0, ta0, t8 # q += r; 2: add t2, t2, t2 # ix += ix; srl t8, t8, 1 # r >>= 1; b 1b # } 3: /* rounding -- all mips rounding modes use the same rounding here */ beq t2, zero, 1f # if (ix != 0) and v0, ta0, 1 # q += q&1; add ta0, ta0, v0 # ... /* calculate result */ 1: srl t2, ta0, 1 # ix = (q >> 1); add t1, t1, SEXP_BIAS # m += 127; (re-bias) li v1, SIMPL_ONE and v0, t2, v1 # keep extra exponent bit bne v0, zero, 1f # if it is there. sub t1, t1, 1 # ... 1: nor v1, v1, v1 # ~SIMP_ONE and t2, t2, v1 # ix &= ~SIMPL_ONE b result_fs_s # store result (already normal) sqrt_d: jal _C_LABEL(get_fs_d) /* Take care of zero, negative, inf, and NaN special cases */ or v0, t1, t2 # sqrt(+-0) == +- 0 or v0, v0, t3 # ... beq v0, zero, result_fs_d # ... bne t0, zero, 1f # sqrt(-val) == sNaN bne t1, DEXP_INF, 2f # skip forward if not infinity b result_fs_d # sqrt(NaN,+inf) == itself 1: move t0, zero # sqrt(-inf,-val) == sNaN li t1, DEXP_INF li t2, DQUIET_NAN0 li t3, DQUIET_NAN1 b result_fs_d 2: /* normalize FS if needed */ bne t1, zero, 2f jal _C_LABEL(renorm_fs_d) 2: and t2, t2, (DIMPL_ONE-1) # ix0 &= 0x000fffff or t2, t2, DIMPL_ONE # ix0 |= 0x00100000 and v0, t1, 1 # if (m & 1) beq v0, zero, 1f # ... add t2, t2, t2 # ix0 += ix0 srl v0, t3, 31 # ix0 += (ix1&sign)>>31) and v0, v0, 1 # ... add t2, t2, v0 # ... addu t3, t3, t3 # ix1 += ix1; 1: sra t1, t1, 1 # m = m / 2; /* generate sqrt(FS) bit by bit -- first upper */ addu t2, t2, t2 # ix0 += ix0; srl v0, t3, 31 # ix0 += (ix1&sign)>>31) and v0, v0, 1 # ... add t2, t2, v0 # ... addu t3, t3, t3 # ix1 += ix1; move ta0, zero # q = 0; (result) move ta1, zero # q1 = 0; (result) move ta2, zero # s0 = 0; move ta3, zero # s1 = 0; li t8, DIMPL_ONE<<1 # t = 0x00200000; 1: beq t8, zero, 3f # while (r != 0) { add t9, ta2, t8 # t = s0+r; bgt t9, t2, 2f # if (t <= ix0) add ta2, t9, t8 # s0 = t + r; sub t2, t2, t9 # ix0 -= t; add ta0, ta0, t8 # q += r; 2: add t2, t2, t2 # ix0 += ix0; srl v0, t3, 31 # ix0 += (ix1&sign)>>31) and v0, v0, 1 # ... add t2, t2, v0 # ... addu t3, t3, t3 # ix1 += ix1; srl t8, t8, 1 # r >>= 1; b 1b # } 3: /* then lower bits */ li t8, 1<<31 # r = sign; 1: beq t8, zero, 4f # while (r != 0) { addu v1, ta3, t8 # t1 = s1 + r; move t9, ta2 # t = s0; blt t9, t2, 2f # if ( (t<ix0) || bne t9, t2, 3f # ((t == ix0) && bgtu v1, t3, 3f # (t1 <= ix1))) 2: addu ta3, v1, t8 # s1 = t1 + r; srl v0, v1, 31 # if (((t1&sign)==sign) && and v0, v0, 1 # ... beq v0, zero, 2f # ... srl v0, ta3, 31 # (s1&sign) == 0) and v0, v0, 1 # ... bne v0, zero, 2f # ... add ta2, ta2, 1 # s0 += 1; 2: sub t2, t2, t9 # ix0 -= t; bgeu t3, v1, 2f # if (ix1 < t1) sub t2, t2, 1 # ix0 -= 1; 2: subu t3, t3, v1 # ix1 -= t1; addu ta1, ta1, t8 # q1 += r; 3: add t2, t2, t2 # ix0 += ix0; srl v0, t3, 31 # ix0 += (ix1&sign)>>31) and v0, v0, 1 # ... add t2, t2, v0 # ... addu t3, t3, t3 # ix1 += ix1; srl t8, t8, 1 # r >>= 1; b 1b # } 4: /* rounding -- all mips rounding modes use the same rounding here */ or v0, t2, t3 # if (ix0 | ix1) beq v0, zero, 2f # ... li v0, 0xffffffff # if (q1 == 0xffffffff) and v1, t2, v0 # ... bne v1, v0, 1f # ... move ta1, zero # q1 = 0; add ta0, ta0, 1 # q += 1; b 2f # else 1: and v0, ta1, 1 # q1 += q1 & 1; addu ta1, ta1, v0 # ... /* calculate result */ 2: srl t2, ta0, 1 # ix0 = q >> 1; srl t3, ta1, 1 # ix1 = q1 >> 1; and v0, ta0, 1 # if ((q & 1) == 1) beq v0, zero, 1f # ... or t3, (1<<31) # ix1 |= sign; 1: add t1, t1, DEXP_BIAS # m += 1023; li v1, DIMPL_ONE and v0, t2, v1 # keep extra exponent bit bne v0, zero, 1f # if it is there. sub t1, t1, 1 # ... 1: nor v1, v1, v1 # ~DIMPL_ONE and t2, t2, v1 # ix0 &= ~DIMPL_ONE b result_fs_d # store result (already normal) #endif /* MIPS3_PLUS */ /* * Single precision absolute value. */ abs_s: jal _C_LABEL(get_fs_s) move t0, zero # set sign positive b result_fs_s /* * Double precision absolute value. */ abs_d: jal _C_LABEL(get_fs_d) move t0, zero # set sign positive b result_fs_d /* * Single precision move. */ mov_s: jal _C_LABEL(get_fs_s) b result_fs_s /* * Double precision move. */ mov_d: jal _C_LABEL(get_fs_d) b result_fs_d /* * Single precision negate. */ neg_s: jal _C_LABEL(get_fs_s) xor t0, t0, 1 # reverse sign b result_fs_s /* * Double precision negate. */ neg_d: jal _C_LABEL(get_fs_d) xor t0, t0, 1 # reverse sign b result_fs_d /* * Single precision mips2 rounding. Explicit case of cvt_w_s. */ round_w_s: li v1,0 b _cvt_w_s trunc_w_s: li v1,1 b _cvt_w_s ceil_w_s: li v1,2 b _cvt_w_s floor_w_s: li v1,3 b _cvt_w_s /* * Double precision mips2 rounding. Explicit case of cvt_w_d. */ round_w_d: li v1,0 b _cvt_w_d trunc_w_d: li v1,1 b _cvt_w_d ceil_w_d: li v1,2 b _cvt_w_d floor_w_d: li v1,3 b _cvt_w_d /* * Convert double to single. */ cvt_s_d: jal _C_LABEL(get_fs_d) bne t1, DEXP_INF, 1f # is FS an infinity? li t1, SEXP_INF # convert to single sll t2, t2, 3 # convert D fraction to S srl t8, t3, 32 - 3 or t2, t2, t8 b result_fs_s 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f beq t3, zero, result_fs_s # result=0 1: jal _C_LABEL(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: sll t2, t2, 3 # convert D fraction to S srl t8, t3, 32 - 3 or t2, t2, t8 sll t8, t3, 3 b norm_noshift_s /* * Convert integer to single. */ cvt_s_w: jal _C_LABEL(get_fs_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 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 leading zeros li t1, 23 # 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 _C_LABEL(get_fs_s) move t3, zero 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 _C_LABEL(renorm_fs_s) move t8, zero b norm_d 2: addu t1, t1, DEXP_BIAS - SEXP_BIAS # bias exponent correctly sll t3, t2, 32 - 3 # convert S fraction to D srl t2, t2, 3 b result_fs_d /* * Convert integer to double. */ cvt_d_w: jal _C_LABEL(get_fs_int) bne t2, zero, 1f # check for zero move t1, zero # result=0 move t3, zero 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 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, 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, 32 blt t9, zero, 2f # if shift < 0, shift right subu v0, v0, t9 sll t2, t2, t9 # shift left 1: and t2, t2, ~DIMPL_ONE # clear implied one bit move t3, zero b result_fs_d 2: negu t9 # shift right by t9 subu v0, v0, t9 sll t3, t2, v0 srl t2, t2, t9 and t2, t2, ~DIMPL_ONE # clear implied one bit b result_fs_d /* * Convert single to integer. */ cvt_w_s: and v1, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode _cvt_w_s: jal _C_LABEL(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 sll t3, t2, 32 - 3 # convert S fraction to D srl t2, t2, 3 b cvt_w /* * Convert double to integer. */ cvt_w_d: and v1, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode _cvt_w_d: jal _C_LABEL(get_fs_d) bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, invalid_w # invalid conversion bne t3, zero, invalid_w # invalid conversion 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f beq t3, zero, result_fs_w # result is zero 1: 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: #if 0 blt t1, WEXP_MIN, underflow_w # is exponent too small? #else bge t1, WEXP_MIN, 3f # is exponent too small? beq v1, MIPS_FPU_ROUND_RP, 1f # round to +infinity beq v1, MIPS_FPU_ROUND_RM, 2f # round to -infinity move t2, zero b result_fs_w 1: xori t2, t0, 1 b result_fs_w 2: sll t2, t0, 31 sra t2, t2, 31 b result_fs_w 3: #endif 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 bne t3, zero, 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, 32 blt v0, zero, 1f # if shift < 0, shift right subu v1, v1, v0 # shift left sll t2, t2, v0 srl t9, t3, v1 # save bits shifted out of t3 or t2, t2, t9 # and put into t2 sll t3, t3, v0 # shift FSs fraction b 2f 1: negu v0 # shift right by v0 subu v1, v1, v0 sll t8, t3, v1 # save bits shifted out sltu t8, zero, t8 # dont lose any ones srl t3, t3, v0 # shift FSs fraction or t3, t3, t8 sll t9, t2, v1 # save bits shifted out of t2 or t3, t3, t9 # and put into t3 srl t2, t2, v0 /* * round result (t0 is sign, t2 is integer part, t3 is fractional part). */ 2: and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 5f # round to zero (truncate) beq v0, MIPS_FPU_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 t3, zero, 5f # if no fraction bits, continue addu t2, t2, 1 # add rounding bit blt t2, zero, overflow_w # overflow? b 5f 3: li v0, GUARDBIT # load guard bit for rounding addu v0, v0, t3 # add remainder sltu v1, v0, t3 # compute carry out beq v1, zero, 4f # if no carry, continue addu t2, t2, 1 # add carry to result blt t2, zero, overflow_w # overflow? 4: bne v0, zero, 5f # if rounded remainder is zero and t2, t2, ~1 # clear LSB (round to nearest) 5: beq t0, zero, 1f # result positive? negu t2 # convert to negative integer 1: beq t3, zero, result_fs_w # is result exact? /* * Handle inexact exception. */ inexact_w: or a2, a2, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif 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 a2, a2, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a2, MIPS_FPU_ENABLE_OVERFLOW bne v0, zero, fpe_trap and v0, a2, MIPS_FPU_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 a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW and v0, a2, MIPS_FPU_ENABLE_UNDERFLOW bne v0, zero, fpe_trap and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, inexact_w # inexact traps enabled? b invalid_w /* * Compare single. */ cmp_s: jal _C_LABEL(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 _C_LABEL(get_cmp_d) bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, unordered bne t3, zero, unordered # FS is a NAN 1: bne ta1, DEXP_INF, 2f # is FT an infinity? bne ta2, zero, unordered bne ta3, zero, unordered # FT is a NAN 2: sll t1, t1, 20 # reassemble exp & frac or t1, t1, t2 sll ta1, ta1, 20 # reassemble exp & frac or ta1, ta1, ta2 beq t0, zero, 1f # is FS positive? not t3 # negate t1,t3 not t1 addu t3, t3, 1 seq v0, t3, zero # compute carry addu t1, t1, v0 1: beq ta0, zero, 1f # is FT positive? not ta3 # negate ta1,ta3 not ta1 addu ta3, ta3, 1 seq v0, ta3, zero # compute carry addu ta1, ta1, v0 1: li v0, COND_LESS blt t1, ta1, test_cond # is FS(MSW) < FT(MSW)? move v0, zero bne t1, ta1, test_cond # is FS(MSW) > FT(MSW)? li v0, COND_LESS bltu t3, ta3, test_cond # is FS(LSW) < FT(LSW)? li v0, COND_EQUAL beq t3, ta3, 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 a2, a2, ~MIPS_FPU_COND_BIT # clear condition bit b 2f 1: or a2, a2, MIPS_FPU_COND_BIT # set condition bit 2: #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save condition bit #endif b done unordered: and v0, a0, COND_UNORDERED # this cmp match unordered? bne v0, zero, 1f and a2, a2, ~MIPS_FPU_COND_BIT # clear condition bit b 2f 1: or a2, a2, MIPS_FPU_COND_BIT # set condition bit 2: and v0, a0, COND_SIGNAL beq v0, zero, 1f # is this a signaling cmp? or a2, a2, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a2, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap 1: #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save condition bit #endif 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, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 5f # round to zero (truncate) beq v0, MIPS_FPU_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 _C_LABEL(set_fd_s) # save result or a2, a2, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_s: or a2, a2, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a2, MIPS_FPU_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 192 # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit jal _C_LABEL(set_fd_s) # save result b fpe_trap 1: and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 1f # round to zero (truncate) beq v0, MIPS_FPU_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, a2, MIPS_FPU_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 _C_LABEL(set_fd_s) # save result or a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_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 a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW /* * Now round the zero result. * Only need to worry about rounding to +- infinity when the sign matches. */ and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, inexact_nobias_s # round to nearest beq v0, MIPS_FPU_ROUND_RZ, inexact_nobias_s # round to zero beq v0, MIPS_FPU_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, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 5f # round to zero (truncate) beq v0, MIPS_FPU_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 _C_LABEL(set_fd_s) # save result beq t8, zero, done # check for exact result or a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW or a2, a2, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif 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 bne t2, zero, 1f move v0, t3 addu t9, 32 bne t3, 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,t3,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, 32 blt t9, zero, 2f # if shift < 0, shift right blt t9, v1, 1f # shift by < 32? subu t9, t9, v1 # shift by >= 32 subu v1, v1, t9 sll t2, t3, t9 # shift left by t9 srl v0, t8, v1 # save bits shifted out or t2, t2, v0 sll t3, t8, t9 move t8, zero b norm_noshift_d 1: subu v1, v1, t9 sll t2, t2, t9 # shift left by t9 srl v0, t3, v1 # save bits shifted out or t2, t2, v0 sll t3, t3, t9 srl v0, t8, v1 # save bits shifted out or t3, t3, v0 sll t8, t8, t9 b norm_noshift_d 2: negu t9 # shift right by t9 subu v1, v1, t9 # (known to be < 32 bits) 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, t3, v1 # save bits shifted out or t8, t8, v0 srl t3, t3, t9 sll v0, t2, v1 # save bits shifted out or t3, t3, v0 srl t2, t2, t9 norm_noshift_d: move ta1, t1 # save unrounded exponent move ta2, t2 # save unrounded fraction (MS) move ta3, t3 # save unrounded fraction (LS) and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 5f # round to zero (truncate) beq v0, MIPS_FPU_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 t3, t3, 1 # add rounding bit bne t3, zero, 5f # branch if no carry addu t2, t2, 1 # add carry bne t2, DIMPL_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 # branch if no carry addu t3, t3, 1 # add carry bne t3, zero, 4f # branch if no carry addu 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 t3, t3, ~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 _C_LABEL(set_fd_d) # save result or a2, a2, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_d: or a2, a2, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a2, MIPS_FPU_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 1536 # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit jal _C_LABEL(set_fd_d) # save result b fpe_trap 1: and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 1f # round to zero (truncate) beq v0, MIPS_FPU_ROUND_RP, 2f # round to +infinity bne t0, zero, 3f 1: li t1, DEXP_MAX # result is max finite li t2, 0x000fffff li t3, 0xffffffff b inexact_d 2: bne t0, zero, 1b 3: li t1, DEXP_MAX + 1 # result is infinity move t2, zero move t3, 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, a2, MIPS_FPU_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 _C_LABEL(set_fd_d) # save result or a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_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) move t3, ta3 # get unrounded fraction (LS) 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 move t3, zero or a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW /* * Now round the zero result. * Only need to worry about rounding to +- infinity when the sign matches. */ and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, inexact_nobias_d # round to nearest beq v0, MIPS_FPU_ROUND_RZ, inexact_nobias_d # round to zero beq v0, MIPS_FPU_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: addu t3, t3, 1 # add rounding bit b inexact_nobias_d 3: li v1, 32 blt t9, v1, 1f # shift by < 32? subu t9, t9, v1 # shift right by >= 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 t3, t2, t9 move t2, zero b 2f 1: subu v1, v1, t9 # shift right by t9 sltu v0, zero, t8 # be sure to save any one bits sll t8, t3, v1 # save bits shifted out or t8, t8, v0 # include sticky bits srl t3, t3, t9 sll v0, t2, v1 # save bits shifted out or t3, t3, v0 srl t2, t2, t9 /* * Now round the denormalized result. */ 2: and v0, a2, MIPS_FPU_ROUNDING_BITS # get rounding mode beq v0, MIPS_FPU_ROUND_RN, 3f # round to nearest beq v0, MIPS_FPU_ROUND_RZ, 5f # round to zero (truncate) beq v0, MIPS_FPU_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 t3, t3, 1 # add rounding bit bne t3, zero, 5f # if no carry, continue addu t2, t2, 1 # add carry 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 t3, t3, 1 # add rounding bit bne t3, zero, 4f # if no carry, continue addu t2, t2, 1 # add carry 4: bne v0, zero, 5f # if rounded remainder is zero and t3, t3, ~1 # clear LSB (round to nearest) 5: move t1, zero # denorm or zero exponent jal _C_LABEL(set_fd_d) # save result beq t8, zero, done # check for exact result or a2, a2, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW or a2, a2, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a2, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is a quiet NAN. */ invalid_s: # trap invalid operation or a2, a2, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a2, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif move t0, zero # result is a quiet NAN li t1, SEXP_INF li t2, SQUIET_NAN jal _C_LABEL(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 a2, a2, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a2, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif move t0, zero # result is a quiet NAN li t1, DEXP_INF li t2, DQUIET_NAN0 li t3, DQUIET_NAN1 jal _C_LABEL(set_fd_d) # save result (in t0,t1,t2,t3) 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 a2, a2, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a2, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif 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: #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else /* * ctc1 with fpe bits set causes FPE in kernel mode panic on 5231. */ sw a2, CALLFRAME_SIZ + 12(sp) lw a0, CPUVAR(FPCURLWP) jal _C_LABEL(savefpregs) # on RM5231 lw a2, CALLFRAME_SIZ + 12(sp) lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #endif lw a1, CALLFRAME_SIZ + 4(sp) # frame lw a2, CALLFRAME_SIZ + 8(sp) # cause lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j _C_LABEL(fpemul_sigfpe) /* * Send an illegal instruction signal to the current process. */ ill: #ifdef SOFTFLOAT lw v0, L_ADDR(MIPS_CURLWP) # get pcb of current process #nop sw a2, U_PCB_FPREGS+FRAME_FSR(v0) #else ctc1 a2, MIPS_FPU_CSR # save exceptions #endif lw a1, CALLFRAME_SIZ + 4(sp) # frame lw a2, CALLFRAME_SIZ + 8(sp) # cause lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j _C_LABEL(fpemul_sigill) result_ft_s: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 result_fs_s: # result is FS jal _C_LABEL(set_fd_s) # save result (in t0,t1,t2) b done result_fs_w: jal _C_LABEL(set_fd_word) # save result (in t2) b done result_ft_d: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 move t3, ta3 result_fs_d: # result is FS jal _C_LABEL(set_fd_d) # save result (in t0,t1,t2,t3) done: /* * Succeeded to emulate instruction with no error * so compute the next PC. */ lw t0, CALLFRAME_SIZ + 8(sp) REG_PROLOGUE REG_L v0, FRAME_EPC(a1) REG_EPILOGUE bgez t0, 1f # Check the branch delay bit. /* * The instruction is in the branch delay slot so the branch will have to * be emulated to get the resulting PC. */ sw a1, CALLFRAME_SIZ + 4(sp) move a0, a1 # 1st arg is p. to trapframe move a1, v0 # 2nd arg is instruction PC # 3rd arg is FP CSR move a3, zero # 4th arg is FALSE jal _C_LABEL(MachEmulateBranch) # compute PC after branch lw a1, CALLFRAME_SIZ + 4(sp) b 2f /* * This is not in the branch delay slot so calculate the resulting * PC (epc + 4) into v0. */ 1: addiu v0, v0, 4 # v0 = next pc 2: REG_PROLOGUE REG_S v0, FRAME_EPC(a1) # save new pc REG_EPILOGUE lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j ra END(MachEmulateFP) /*---------------------------------------------------------------------------- * get_fs_int -- * * Read (integer) the FS register (bits 15-11). * This is an internal routine used by MachEmulateFP only. * * Results: * t0 contains the sign * t2 contains the fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(get_fs_int) #ifdef SOFTFLOAT srl t2, a0, 11-2 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t2, t2, 0x0078 # Even regs only addu t0, t0, t2 lw t2, U_PCB_FPREGS+FRAME_FP0(t0) srl t0, t2, 31 # init the sign bit bge t2, zero, 1f negu t2 1: j ra #else srl a3, a0, 12 - 2 # get FS field (even regs only) and a3, a3, 0xF << 2 # mask FS field lw a3, get_fs_int_tbl(a3) # switch on register number j a3 .rdata get_fs_int_tbl: .word get_fs_int_f0 .word get_fs_int_f2 .word get_fs_int_f4 .word get_fs_int_f6 .word get_fs_int_f8 .word get_fs_int_f10 .word get_fs_int_f12 .word get_fs_int_f14 .word get_fs_int_f16 .word get_fs_int_f18 .word get_fs_int_f20 .word get_fs_int_f22 .word get_fs_int_f24 .word get_fs_int_f26 .word get_fs_int_f28 .word get_fs_int_f30 .text get_fs_int_f0: mfc1 t2, $f0 b get_fs_int_done get_fs_int_f2: mfc1 t2, $f2 b get_fs_int_done get_fs_int_f4: mfc1 t2, $f4 b get_fs_int_done get_fs_int_f6: mfc1 t2, $f6 b get_fs_int_done get_fs_int_f8: mfc1 t2, $f8 b get_fs_int_done get_fs_int_f10: mfc1 t2, $f10 b get_fs_int_done get_fs_int_f12: mfc1 t2, $f12 b get_fs_int_done get_fs_int_f14: mfc1 t2, $f14 b get_fs_int_done get_fs_int_f16: mfc1 t2, $f16 b get_fs_int_done get_fs_int_f18: mfc1 t2, $f18 b get_fs_int_done get_fs_int_f20: mfc1 t2, $f20 b get_fs_int_done get_fs_int_f22: mfc1 t2, $f22 b get_fs_int_done get_fs_int_f24: mfc1 t2, $f24 b get_fs_int_done get_fs_int_f26: mfc1 t2, $f26 b get_fs_int_done get_fs_int_f28: mfc1 t2, $f28 b get_fs_int_done get_fs_int_f30: mfc1 t2, $f30 get_fs_int_done: srl t0, t2, 31 # init the sign bit bge t2, zero, 1f negu t2 1: j ra #endif END(get_fs_int) /*---------------------------------------------------------------------------- * 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 MachEmulateFP 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 * *---------------------------------------------------------------------------- */ STATIC_LEAF(get_ft_fs_s) #ifdef SOFTFLOAT srl ta0, a0, 16-2 lw ta1, L_ADDR(MIPS_CURLWP) # get pcb of current process andi ta0, ta0, 0x0078 # Even regs only addu ta1, ta1, ta0 lw ta0, U_PCB_FPREGS+FRAME_FP0(ta1) 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 */ #else srl a3, a0, 17 - 2 # get FT field (even regs only) and a3, a3, 0xF << 2 # mask FT field lw a3, get_ft_s_tbl(a3) # switch on register number j a3 .rdata get_ft_s_tbl: .word get_ft_s_f0 .word get_ft_s_f2 .word get_ft_s_f4 .word get_ft_s_f6 .word get_ft_s_f8 .word get_ft_s_f10 .word get_ft_s_f12 .word get_ft_s_f14 .word get_ft_s_f16 .word get_ft_s_f18 .word get_ft_s_f20 .word get_ft_s_f22 .word get_ft_s_f24 .word get_ft_s_f26 .word get_ft_s_f28 .word get_ft_s_f30 .text get_ft_s_f0: mfc1 ta0, $f0 b get_ft_s_done get_ft_s_f2: mfc1 ta0, $f2 b get_ft_s_done get_ft_s_f4: mfc1 ta0, $f4 b get_ft_s_done get_ft_s_f6: mfc1 ta0, $f6 b get_ft_s_done get_ft_s_f8: mfc1 ta0, $f8 b get_ft_s_done get_ft_s_f10: mfc1 ta0, $f10 b get_ft_s_done get_ft_s_f12: mfc1 ta0, $f12 b get_ft_s_done get_ft_s_f14: mfc1 ta0, $f14 b get_ft_s_done get_ft_s_f16: mfc1 ta0, $f16 b get_ft_s_done get_ft_s_f18: mfc1 ta0, $f18 b get_ft_s_done get_ft_s_f20: mfc1 ta0, $f20 b get_ft_s_done get_ft_s_f22: mfc1 ta0, $f22 b get_ft_s_done get_ft_s_f24: mfc1 ta0, $f24 b get_ft_s_done get_ft_s_f26: mfc1 ta0, $f26 b get_ft_s_done get_ft_s_f28: mfc1 ta0, $f28 b get_ft_s_done get_ft_s_f30: mfc1 ta0, $f30 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 */ #endif /*---------------------------------------------------------------------------- * get_fs_s -- * * Read (single precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MachEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * *---------------------------------------------------------------------------- */ STATIC_XLEAF(get_fs_s) #ifdef SOFTFLOAT srl t0, a0, 11-2 lw t1, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t0, t0, 0x0078 # Even regs only addu t1, t1, t0 lw t0, U_PCB_FPREGS+FRAME_FP0(t1) 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 #else srl a3, a0, 12 - 2 # get FS field (even regs only) and a3, a3, 0xF << 2 # mask FS field lw a3, get_fs_s_tbl(a3) # switch on register number j a3 .rdata get_fs_s_tbl: .word get_fs_s_f0 .word get_fs_s_f2 .word get_fs_s_f4 .word get_fs_s_f6 .word get_fs_s_f8 .word get_fs_s_f10 .word get_fs_s_f12 .word get_fs_s_f14 .word get_fs_s_f16 .word get_fs_s_f18 .word get_fs_s_f20 .word get_fs_s_f22 .word get_fs_s_f24 .word get_fs_s_f26 .word get_fs_s_f28 .word get_fs_s_f30 .text get_fs_s_f0: mfc1 t0, $f0 b get_fs_s_done get_fs_s_f2: mfc1 t0, $f2 b get_fs_s_done get_fs_s_f4: mfc1 t0, $f4 b get_fs_s_done get_fs_s_f6: mfc1 t0, $f6 b get_fs_s_done get_fs_s_f8: mfc1 t0, $f8 b get_fs_s_done get_fs_s_f10: mfc1 t0, $f10 b get_fs_s_done get_fs_s_f12: mfc1 t0, $f12 b get_fs_s_done get_fs_s_f14: mfc1 t0, $f14 b get_fs_s_done get_fs_s_f16: mfc1 t0, $f16 b get_fs_s_done get_fs_s_f18: mfc1 t0, $f18 b get_fs_s_done get_fs_s_f20: mfc1 t0, $f20 b get_fs_s_done get_fs_s_f22: mfc1 t0, $f22 b get_fs_s_done get_fs_s_f24: mfc1 t0, $f24 b get_fs_s_done get_fs_s_f26: mfc1 t0, $f26 b get_fs_s_done get_fs_s_f28: mfc1 t0, $f28 b get_fs_s_done get_fs_s_f30: mfc1 t0, $f30 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 #endif 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 MachEmulateFP only. * * Results: * t0 contains the FS sign * t1 contains the FS (biased) exponent * t2 contains the FS fraction * t3 contains the FS remaining fraction * ta0 contains the FT sign * ta1 contains the FT (biased) exponent * ta2 contains the FT fraction * ta3 contains the FT remaining fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(get_ft_fs_d) #ifdef SOFTFLOAT srl ta3, a0, 16-2 lw ta0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi ta3, ta3, 0x0078 # Even regs only addu ta0, ta0, ta3 lw ta3, U_PCB_FPREGS+FRAME_FP0(ta0) lw ta0, U_PCB_FPREGS+FRAME_FP0+4(ta0) srl ta1, ta0, 20 # get exponent and ta1, ta1, 0x7FF and ta2, ta0, 0xFFFFF # get fraction srl ta0, ta0, 31 # get sign 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 */ #else srl a3, a0, 17 - 2 # get FT field (even regs only) and a3, a3, 0xF << 2 # mask FT field lw a3, get_ft_d_tbl(a3) # switch on register number j a3 .rdata get_ft_d_tbl: .word get_ft_d_f0 .word get_ft_d_f2 .word get_ft_d_f4 .word get_ft_d_f6 .word get_ft_d_f8 .word get_ft_d_f10 .word get_ft_d_f12 .word get_ft_d_f14 .word get_ft_d_f16 .word get_ft_d_f18 .word get_ft_d_f20 .word get_ft_d_f22 .word get_ft_d_f24 .word get_ft_d_f26 .word get_ft_d_f28 .word get_ft_d_f30 .text get_ft_d_f0: mfc1 ta3, $f0 mfc1 ta0, $f1 b get_ft_d_done get_ft_d_f2: mfc1 ta3, $f2 mfc1 ta0, $f3 b get_ft_d_done get_ft_d_f4: mfc1 ta3, $f4 mfc1 ta0, $f5 b get_ft_d_done get_ft_d_f6: mfc1 ta3, $f6 mfc1 ta0, $f7 b get_ft_d_done get_ft_d_f8: mfc1 ta3, $f8 mfc1 ta0, $f9 b get_ft_d_done get_ft_d_f10: mfc1 ta3, $f10 mfc1 ta0, $f11 b get_ft_d_done get_ft_d_f12: mfc1 ta3, $f12 mfc1 ta0, $f13 b get_ft_d_done get_ft_d_f14: mfc1 ta3, $f14 mfc1 ta0, $f15 b get_ft_d_done get_ft_d_f16: mfc1 ta3, $f16 mfc1 ta0, $f17 b get_ft_d_done get_ft_d_f18: mfc1 ta3, $f18 mfc1 ta0, $f19 b get_ft_d_done get_ft_d_f20: mfc1 ta3, $f20 mfc1 ta0, $f21 b get_ft_d_done get_ft_d_f22: mfc1 ta3, $f22 mfc1 ta0, $f23 b get_ft_d_done get_ft_d_f24: mfc1 ta3, $f24 mfc1 ta0, $f25 b get_ft_d_done get_ft_d_f26: mfc1 ta3, $f26 mfc1 ta0, $f27 b get_ft_d_done get_ft_d_f28: mfc1 ta3, $f28 mfc1 ta0, $f29 b get_ft_d_done get_ft_d_f30: mfc1 ta3, $f30 mfc1 ta0, $f31 get_ft_d_done: srl ta1, ta0, 20 # get exponent and ta1, ta1, 0x7FF and ta2, ta0, 0xFFFFF # get fraction srl ta0, ta0, 31 # get sign 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 */ #endif /*---------------------------------------------------------------------------- * get_fs_d -- * * Read (double precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MachEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * *---------------------------------------------------------------------------- */ STATIC_XLEAF(get_fs_d) #ifdef SOFTFLOAT srl t3, a0, 11-2 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t3, t3, 0x0078 # Even regs only addu t0, t0, t3 lw t3, U_PCB_FPREGS+FRAME_FP0(t0) lw t0, U_PCB_FPREGS+FRAME_FP0+4(t0) srl t1, t0, 20 # get exponent and t1, t1, 0x7FF and t2, t0, 0xFFFFF # get fraction srl t0, t0, 31 # get sign bne t1, DEXP_INF, 1f # is it a signaling NAN? and v0, t2, DSIGNAL_NAN bne v0, zero, invalid_d 1: j ra #else srl a3, a0, 12 - 2 # get FS field (even regs only) and a3, a3, 0xF << 2 # mask FS field lw a3, get_fs_d_tbl(a3) # switch on register number j a3 .rdata get_fs_d_tbl: .word get_fs_d_f0 .word get_fs_d_f2 .word get_fs_d_f4 .word get_fs_d_f6 .word get_fs_d_f8 .word get_fs_d_f10 .word get_fs_d_f12 .word get_fs_d_f14 .word get_fs_d_f16 .word get_fs_d_f18 .word get_fs_d_f20 .word get_fs_d_f22 .word get_fs_d_f24 .word get_fs_d_f26 .word get_fs_d_f28 .word get_fs_d_f30 .text get_fs_d_f0: mfc1 t3, $f0 mfc1 t0, $f1 b get_fs_d_done get_fs_d_f2: mfc1 t3, $f2 mfc1 t0, $f3 b get_fs_d_done get_fs_d_f4: mfc1 t3, $f4 mfc1 t0, $f5 b get_fs_d_done get_fs_d_f6: mfc1 t3, $f6 mfc1 t0, $f7 b get_fs_d_done get_fs_d_f8: mfc1 t3, $f8 mfc1 t0, $f9 b get_fs_d_done get_fs_d_f10: mfc1 t3, $f10 mfc1 t0, $f11 b get_fs_d_done get_fs_d_f12: mfc1 t3, $f12 mfc1 t0, $f13 b get_fs_d_done get_fs_d_f14: mfc1 t3, $f14 mfc1 t0, $f15 b get_fs_d_done get_fs_d_f16: mfc1 t3, $f16 mfc1 t0, $f17 b get_fs_d_done get_fs_d_f18: mfc1 t3, $f18 mfc1 t0, $f19 b get_fs_d_done get_fs_d_f20: mfc1 t3, $f20 mfc1 t0, $f21 b get_fs_d_done get_fs_d_f22: mfc1 t3, $f22 mfc1 t0, $f23 b get_fs_d_done get_fs_d_f24: mfc1 t3, $f24 mfc1 t0, $f25 b get_fs_d_done get_fs_d_f26: mfc1 t3, $f26 mfc1 t0, $f27 b get_fs_d_done get_fs_d_f28: mfc1 t3, $f28 mfc1 t0, $f29 b get_fs_d_done get_fs_d_f30: mfc1 t3, $f30 mfc1 t0, $f31 get_fs_d_done: srl t1, t0, 20 # get exponent and t1, t1, 0x7FF and t2, t0, 0xFFFFF # get fraction srl t0, t0, 31 # get sign bne t1, DEXP_INF, 1f # is it a signaling NAN? and v0, t2, DSIGNAL_NAN bne v0, zero, invalid_d 1: j ra #endif 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 MachEmulateFP 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 * *---------------------------------------------------------------------------- */ STATIC_LEAF(get_cmp_s) #ifdef SOFTFLOAT srl t1, a0, 11-2 lw ta2, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x0078 # Even regs only addu t0, ta2, t1 lw t0, U_PCB_FPREGS+FRAME_FP0(t0) srl t1, t0, 23 # get exponent and t1, t1, 0xFF and t2, t0, 0x7FFFFF # get fraction srl t0, t0, 31 # get sign srl ta0, a0, 16-2 andi ta0, ta0, 0x0078 # Even regs only addu ta2, ta2, ta0 lw ta0, U_PCB_FPREGS+FRAME_FP0(ta2) srl ta1, ta0, 23 # get exponent and ta1, ta1, 0xFF and ta2, ta0, 0x7FFFFF # get fraction srl ta0, ta0, 31 # get sign j ra #else srl a3, a0, 12 - 2 # get FS field (even regs only) and a3, a3, 0xF << 2 # mask FS field lw a3, cmp_fs_s_tbl(a3) # switch on register number j a3 .rdata cmp_fs_s_tbl: .word cmp_fs_s_f0 .word cmp_fs_s_f2 .word cmp_fs_s_f4 .word cmp_fs_s_f6 .word cmp_fs_s_f8 .word cmp_fs_s_f10 .word cmp_fs_s_f12 .word cmp_fs_s_f14 .word cmp_fs_s_f16 .word cmp_fs_s_f18 .word cmp_fs_s_f20 .word cmp_fs_s_f22 .word cmp_fs_s_f24 .word cmp_fs_s_f26 .word cmp_fs_s_f28 .word cmp_fs_s_f30 .text cmp_fs_s_f0: mfc1 t0, $f0 b cmp_fs_s_done cmp_fs_s_f2: mfc1 t0, $f2 b cmp_fs_s_done cmp_fs_s_f4: mfc1 t0, $f4 b cmp_fs_s_done cmp_fs_s_f6: mfc1 t0, $f6 b cmp_fs_s_done cmp_fs_s_f8: mfc1 t0, $f8 b cmp_fs_s_done cmp_fs_s_f10: mfc1 t0, $f10 b cmp_fs_s_done cmp_fs_s_f12: mfc1 t0, $f12 b cmp_fs_s_done cmp_fs_s_f14: mfc1 t0, $f14 b cmp_fs_s_done cmp_fs_s_f16: mfc1 t0, $f16 b cmp_fs_s_done cmp_fs_s_f18: mfc1 t0, $f18 b cmp_fs_s_done cmp_fs_s_f20: mfc1 t0, $f20 b cmp_fs_s_done cmp_fs_s_f22: mfc1 t0, $f22 b cmp_fs_s_done cmp_fs_s_f24: mfc1 t0, $f24 b cmp_fs_s_done cmp_fs_s_f26: mfc1 t0, $f26 b cmp_fs_s_done cmp_fs_s_f28: mfc1 t0, $f28 b cmp_fs_s_done cmp_fs_s_f30: mfc1 t0, $f30 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 srl a3, a0, 17 - 2 # get FT field (even regs only) and a3, a3, 0xF << 2 # mask FT field lw a3, cmp_ft_s_tbl(a3) # switch on register number j a3 .rdata cmp_ft_s_tbl: .word cmp_ft_s_f0 .word cmp_ft_s_f2 .word cmp_ft_s_f4 .word cmp_ft_s_f6 .word cmp_ft_s_f8 .word cmp_ft_s_f10 .word cmp_ft_s_f12 .word cmp_ft_s_f14 .word cmp_ft_s_f16 .word cmp_ft_s_f18 .word cmp_ft_s_f20 .word cmp_ft_s_f22 .word cmp_ft_s_f24 .word cmp_ft_s_f26 .word cmp_ft_s_f28 .word cmp_ft_s_f30 .text cmp_ft_s_f0: mfc1 ta0, $f0 b cmp_ft_s_done cmp_ft_s_f2: mfc1 ta0, $f2 b cmp_ft_s_done cmp_ft_s_f4: mfc1 ta0, $f4 b cmp_ft_s_done cmp_ft_s_f6: mfc1 ta0, $f6 b cmp_ft_s_done cmp_ft_s_f8: mfc1 ta0, $f8 b cmp_ft_s_done cmp_ft_s_f10: mfc1 ta0, $f10 b cmp_ft_s_done cmp_ft_s_f12: mfc1 ta0, $f12 b cmp_ft_s_done cmp_ft_s_f14: mfc1 ta0, $f14 b cmp_ft_s_done cmp_ft_s_f16: mfc1 ta0, $f16 b cmp_ft_s_done cmp_ft_s_f18: mfc1 ta0, $f18 b cmp_ft_s_done cmp_ft_s_f20: mfc1 ta0, $f20 b cmp_ft_s_done cmp_ft_s_f22: mfc1 ta0, $f22 b cmp_ft_s_done cmp_ft_s_f24: mfc1 ta0, $f24 b cmp_ft_s_done cmp_ft_s_f26: mfc1 ta0, $f26 b cmp_ft_s_done cmp_ft_s_f28: mfc1 ta0, $f28 b cmp_ft_s_done cmp_ft_s_f30: mfc1 ta0, $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 #endif 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 MachEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * ta0 contains the sign * ta1 contains the (biased) exponent * ta2 contains the fraction * ta3 contains the remaining fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(get_cmp_d) #ifdef SOFTFLOAT srl t1, a0, 11-2 lw ta2, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x0078 # Even regs only addu t0, ta2, t1 lw t3, U_PCB_FPREGS+FRAME_FP0(t0) lw t0, U_PCB_FPREGS+FRAME_FP0+4(t0) srl t1, t0, 20 # get exponent and t1, t1, 0x7FF and t2, t0, 0xFFFFF # get fraction srl t0, t0, 31 # get sign srl ta0, a0, 16-2 andi ta0, ta0, 0x0078 # Even regs only addu ta2, ta2, ta0 lw ta3, U_PCB_FPREGS+FRAME_FP0(ta2) lw ta0, U_PCB_FPREGS+FRAME_FP0+4(ta2) srl ta1, ta0, 20 # get exponent and ta1, ta1, 0x7FF and ta2, ta0, 0xFFFFF # get fraction srl ta0, ta0, 31 # get sign j ra #else srl a3, a0, 12 - 2 # get FS field (even regs only) and a3, a3, 0xF << 2 # mask FS field lw a3, cmp_fs_d_tbl(a3) # switch on register number j a3 .rdata cmp_fs_d_tbl: .word cmp_fs_d_f0 .word cmp_fs_d_f2 .word cmp_fs_d_f4 .word cmp_fs_d_f6 .word cmp_fs_d_f8 .word cmp_fs_d_f10 .word cmp_fs_d_f12 .word cmp_fs_d_f14 .word cmp_fs_d_f16 .word cmp_fs_d_f18 .word cmp_fs_d_f20 .word cmp_fs_d_f22 .word cmp_fs_d_f24 .word cmp_fs_d_f26 .word cmp_fs_d_f28 .word cmp_fs_d_f30 .text cmp_fs_d_f0: mfc1 t3, $f0 mfc1 t0, $f1 b cmp_fs_d_done cmp_fs_d_f2: mfc1 t3, $f2 mfc1 t0, $f3 b cmp_fs_d_done cmp_fs_d_f4: mfc1 t3, $f4 mfc1 t0, $f5 b cmp_fs_d_done cmp_fs_d_f6: mfc1 t3, $f6 mfc1 t0, $f7 b cmp_fs_d_done cmp_fs_d_f8: mfc1 t3, $f8 mfc1 t0, $f9 b cmp_fs_d_done cmp_fs_d_f10: mfc1 t3, $f10 mfc1 t0, $f11 b cmp_fs_d_done cmp_fs_d_f12: mfc1 t3, $f12 mfc1 t0, $f13 b cmp_fs_d_done cmp_fs_d_f14: mfc1 t3, $f14 mfc1 t0, $f15 b cmp_fs_d_done cmp_fs_d_f16: mfc1 t3, $f16 mfc1 t0, $f17 b cmp_fs_d_done cmp_fs_d_f18: mfc1 t3, $f18 mfc1 t0, $f19 b cmp_fs_d_done cmp_fs_d_f20: mfc1 t3, $f20 mfc1 t0, $f21 b cmp_fs_d_done cmp_fs_d_f22: mfc1 t3, $f22 mfc1 t0, $f23 b cmp_fs_d_done cmp_fs_d_f24: mfc1 t3, $f24 mfc1 t0, $f25 b cmp_fs_d_done cmp_fs_d_f26: mfc1 t3, $f26 mfc1 t0, $f27 b cmp_fs_d_done cmp_fs_d_f28: mfc1 t3, $f28 mfc1 t0, $f29 b cmp_fs_d_done cmp_fs_d_f30: mfc1 t3, $f30 mfc1 t0, $f31 cmp_fs_d_done: srl t1, t0, 20 # get exponent and t1, t1, 0x7FF and t2, t0, 0xFFFFF # get fraction srl t0, t0, 31 # get sign srl a3, a0, 17 - 2 # get FT field (even regs only) and a3, a3, 0xF << 2 # mask FT field lw a3, cmp_ft_d_tbl(a3) # switch on register number j a3 .rdata cmp_ft_d_tbl: .word cmp_ft_d_f0 .word cmp_ft_d_f2 .word cmp_ft_d_f4 .word cmp_ft_d_f6 .word cmp_ft_d_f8 .word cmp_ft_d_f10 .word cmp_ft_d_f12 .word cmp_ft_d_f14 .word cmp_ft_d_f16 .word cmp_ft_d_f18 .word cmp_ft_d_f20 .word cmp_ft_d_f22 .word cmp_ft_d_f24 .word cmp_ft_d_f26 .word cmp_ft_d_f28 .word cmp_ft_d_f30 .text cmp_ft_d_f0: mfc1 ta3, $f0 mfc1 ta0, $f1 b cmp_ft_d_done cmp_ft_d_f2: mfc1 ta3, $f2 mfc1 ta0, $f3 b cmp_ft_d_done cmp_ft_d_f4: mfc1 ta3, $f4 mfc1 ta0, $f5 b cmp_ft_d_done cmp_ft_d_f6: mfc1 ta3, $f6 mfc1 ta0, $f7 b cmp_ft_d_done cmp_ft_d_f8: mfc1 ta3, $f8 mfc1 ta0, $f9 b cmp_ft_d_done cmp_ft_d_f10: mfc1 ta3, $f10 mfc1 ta0, $f11 b cmp_ft_d_done cmp_ft_d_f12: mfc1 ta3, $f12 mfc1 ta0, $f13 b cmp_ft_d_done cmp_ft_d_f14: mfc1 ta3, $f14 mfc1 ta0, $f15 b cmp_ft_d_done cmp_ft_d_f16: mfc1 ta3, $f16 mfc1 ta0, $f17 b cmp_ft_d_done cmp_ft_d_f18: mfc1 ta3, $f18 mfc1 ta0, $f19 b cmp_ft_d_done cmp_ft_d_f20: mfc1 ta3, $f20 mfc1 ta0, $f21 b cmp_ft_d_done cmp_ft_d_f22: mfc1 ta3, $f22 mfc1 ta0, $f23 b cmp_ft_d_done cmp_ft_d_f24: mfc1 ta3, $f24 mfc1 ta0, $f25 b cmp_ft_d_done cmp_ft_d_f26: mfc1 ta3, $f26 mfc1 ta0, $f27 b cmp_ft_d_done cmp_ft_d_f28: mfc1 ta3, $f28 mfc1 ta0, $f29 b cmp_ft_d_done cmp_ft_d_f30: mfc1 ta3, $f30 mfc1 ta0, $f31 cmp_ft_d_done: srl ta1, ta0, 20 # get exponent and ta1, ta1, 0x7FF and ta2, ta0, 0xFFFFF # get fraction srl ta0, ta0, 31 # get sign j ra #endif END(get_cmp_d) /*---------------------------------------------------------------------------- * set_fd_s -- * * Write (single precision) the FD register (bits 10-6). * This is an internal routine used by MachEmulateFP 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 MachEmulateFP only. * * Arguments: * a0 contains the FP instruction * t2 contains the integer * *---------------------------------------------------------------------------- */ STATIC_LEAF(set_fd_s) sll t0, t0, 31 # position sign sll t1, t1, 23 # position exponent or t2, t2, t0 or t2, t2, t1 STATIC_XLEAF(set_fd_word) #ifdef SOFTFLOAT srl t1, a0, 6-2 lw t0, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x0078 # Even regs only addu t0, t0, t1 sw t2, U_PCB_FPREGS+FRAME_FP0(t0) j ra #else srl a3, a0, 7 - 2 # get FD field (even regs only) and a3, a3, 0xF << 2 # mask FT field lw a3, set_fd_s_tbl(a3) # switch on register number j a3 .rdata set_fd_s_tbl: .word set_fd_s_f0 .word set_fd_s_f2 .word set_fd_s_f4 .word set_fd_s_f6 .word set_fd_s_f8 .word set_fd_s_f10 .word set_fd_s_f12 .word set_fd_s_f14 .word set_fd_s_f16 .word set_fd_s_f18 .word set_fd_s_f20 .word set_fd_s_f22 .word set_fd_s_f24 .word set_fd_s_f26 .word set_fd_s_f28 .word set_fd_s_f30 .text set_fd_s_f0: mtc1 t2, $f0 j ra set_fd_s_f2: mtc1 t2, $f2 j ra set_fd_s_f4: mtc1 t2, $f4 j ra set_fd_s_f6: mtc1 t2, $f6 j ra set_fd_s_f8: mtc1 t2, $f8 j ra set_fd_s_f10: mtc1 t2, $f10 j ra set_fd_s_f12: mtc1 t2, $f12 j ra set_fd_s_f14: mtc1 t2, $f14 j ra set_fd_s_f16: mtc1 t2, $f16 j ra set_fd_s_f18: mtc1 t2, $f18 j ra set_fd_s_f20: mtc1 t2, $f20 j ra set_fd_s_f22: mtc1 t2, $f22 j ra set_fd_s_f24: mtc1 t2, $f24 j ra set_fd_s_f26: mtc1 t2, $f26 j ra set_fd_s_f28: mtc1 t2, $f28 j ra set_fd_s_f30: mtc1 t2, $f30 j ra #endif END(set_fd_s) /*---------------------------------------------------------------------------- * set_fd_d -- * * Write (double precision) the FT register (bits 10-6). * This is an internal routine used by MachEmulateFP only. * * Arguments: * a0 contains the FP instruction * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(set_fd_d) #ifdef SOFTFLOAT sll t0, t0, 31 # set sign sll t1, t1, 20 # set exponent or t0, t0, t1 or t0, t0, t2 # set fraction srl t1, a0, 6-2 lw t2, L_ADDR(MIPS_CURLWP) # get pcb of current process andi t1, t1, 0x0078 # Even regs only addu t2, t2, t1 sw t3, U_PCB_FPREGS+FRAME_FP0(t2) sw t0, U_PCB_FPREGS+FRAME_FP0+4(t2) j ra #else sll t0, t0, 31 # set sign sll t1, t1, 20 # set exponent or t0, t0, t1 or t0, t0, t2 # set fraction srl a3, a0, 7 - 2 # get FD field (even regs only) and a3, a3, 0xF << 2 # mask FD field lw a3, set_fd_d_tbl(a3) # switch on register number j a3 .rdata set_fd_d_tbl: .word set_fd_d_f0 .word set_fd_d_f2 .word set_fd_d_f4 .word set_fd_d_f6 .word set_fd_d_f8 .word set_fd_d_f10 .word set_fd_d_f12 .word set_fd_d_f14 .word set_fd_d_f16 .word set_fd_d_f18 .word set_fd_d_f20 .word set_fd_d_f22 .word set_fd_d_f24 .word set_fd_d_f26 .word set_fd_d_f28 .word set_fd_d_f30 .text set_fd_d_f0: mtc1 t3, $f0 mtc1 t0, $f1 j ra set_fd_d_f2: mtc1 t3, $f2 mtc1 t0, $f3 j ra set_fd_d_f4: mtc1 t3, $f4 mtc1 t0, $f5 j ra set_fd_d_f6: mtc1 t3, $f6 mtc1 t0, $f7 j ra set_fd_d_f8: mtc1 t3, $f8 mtc1 t0, $f9 j ra set_fd_d_f10: mtc1 t3, $f10 mtc1 t0, $f11 j ra set_fd_d_f12: mtc1 t3, $f12 mtc1 t0, $f13 j ra set_fd_d_f14: mtc1 t3, $f14 mtc1 t0, $f15 j ra set_fd_d_f16: mtc1 t3, $f16 mtc1 t0, $f17 j ra set_fd_d_f18: mtc1 t3, $f18 mtc1 t0, $f19 j ra set_fd_d_f20: mtc1 t3, $f20 mtc1 t0, $f21 j ra set_fd_d_f22: mtc1 t3, $f22 mtc1 t0, $f23 j ra set_fd_d_f24: mtc1 t3, $f24 mtc1 t0, $f25 j ra set_fd_d_f26: mtc1 t3, $f26 mtc1 t0, $f27 j ra set_fd_d_f28: mtc1 t3, $f28 mtc1 t0, $f29 j ra set_fd_d_f30: mtc1 t3, $f30 mtc1 t0, $f31 j ra #endif END(set_fd_d) /*---------------------------------------------------------------------------- * renorm_fs_s -- * * Results: * t1 unbiased exponent * t2 normalized fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(renorm_fs_s) /* * 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,t3 normalized fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(renorm_fs_d) /* * Find out how many leading zero bits are in t2,t3 and put in t9. */ move v0, t2 move t9, zero bne t2, zero, 1f move v0, t3 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,t3 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros li t1, DEXP_MIN subu t1, t1, t9 # adjust exponent li v0, 32 blt t9, v0, 1f subu t9, t9, v0 # shift fraction left >= 32 bits sll t2, t3, t9 move t3, zero j ra 1: subu v0, v0, t9 # shift fraction left < 32 bits sll t2, t2, t9 srl v1, t3, v0 or t2, t2, v1 sll t3, t3, t9 j ra END(renorm_fs_d) /*---------------------------------------------------------------------------- * renorm_ft_s -- * * Results: * ta1 unbiased exponent * ta2 normalized fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(renorm_ft_s) /* * 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, ta1, t9 # adjust exponent sll ta2, ta2, t9 j ra END(renorm_ft_s) /*---------------------------------------------------------------------------- * renorm_ft_d -- * * Results: * ta1 unbiased exponent * ta2,ta3 normalized fraction * *---------------------------------------------------------------------------- */ STATIC_LEAF(renorm_ft_d) /* * Find out how many leading zero bits are in ta2,ta3 and put in t9. */ move v0, ta2 move t9, zero bne ta2, zero, 1f move v0, ta3 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 ta2,ta3 the correct number of bits. */ 1: subu t9, t9, DLEAD_ZEROS # dont count normal leading zeros li ta1, DEXP_MIN subu ta1, ta1, t9 # adjust exponent li v0, 32 blt t9, v0, 1f subu t9, t9, v0 # shift fraction left >= 32 bits sll ta2, ta3, t9 move ta3, zero j ra 1: subu v0, v0, t9 # shift fraction left < 32 bits sll ta2, ta2, t9 srl v1, ta3, v0 or ta2, ta2, v1 sll ta3, ta3, t9 j ra END(renorm_ft_d) #ifdef SOFTFLOAT /* * Emulate branch delay slot CPU instruction. * Enter from BC1x emulation. * These instructions are not implemented and causes SIGILL. * jump/branch * COP0 * 64bit operation * trap/syscall/break * * Args are same as MachEmulateFP. * It should be used to emulate instruction in branch delay slot. */ STATIC_LEAF(bcemul_delay_slot) REG_PROLOGUE REG_S zero, FRAME_ZERO(a1) # ensure zero has value 0 REG_EPILOGUE srl t0, a0, 26-2 andi t0, t0, 0x00FC lw t0, bcemul_optbl(t0) j t0 bcemul_special: sll t0, a0, 2 andi t0, t0, 0x00FC lw t0, bcemul_specialtbl(t0) j t0 .rdata bcemul_optbl: .word bcemul_special # 0 .word _C_LABEL(bcemul_sigill) # 1 .word _C_LABEL(bcemul_sigill) # 2 .word _C_LABEL(bcemul_sigill) # 3 .word _C_LABEL(bcemul_sigill) # 4 .word _C_LABEL(bcemul_sigill) # 5 .word _C_LABEL(bcemul_sigill) # 6 .word _C_LABEL(bcemul_sigill) # 7 .word bcemul_addi # 8 .word bcemul_addiu # 9 .word bcemul_slti # 10 .word bcemul_sltiu # 11 .word bcemul_andi # 12 .word bcemul_ori # 13 .word bcemul_xori # 14 .word bcemul_lui # 15 .word _C_LABEL(bcemul_sigill) # 16 .word _C_LABEL(MachEmulateFP) # 17 .word _C_LABEL(bcemul_sigill) # 18 .word _C_LABEL(bcemul_sigill) # 19 .word _C_LABEL(bcemul_sigill) # 20 .word _C_LABEL(bcemul_sigill) # 21 .word _C_LABEL(bcemul_sigill) # 22 .word _C_LABEL(bcemul_sigill) # 23 .word _C_LABEL(bcemul_sigill) # 24 .word _C_LABEL(bcemul_sigill) # 25 .word _C_LABEL(bcemul_sigill) # 26 .word _C_LABEL(bcemul_sigill) # 27 .word _C_LABEL(bcemul_sigill) # 28 .word _C_LABEL(bcemul_sigill) # 29 .word _C_LABEL(bcemul_sigill) # 30 .word _C_LABEL(bcemul_sigill) # 31 .word _C_LABEL(bcemul_lb) # 32 .word _C_LABEL(bcemul_lh) # 33 .word _C_LABEL(bcemul_lwl) # 34 .word _C_LABEL(bcemul_lw) # 35 .word _C_LABEL(bcemul_lbu) # 36 .word _C_LABEL(bcemul_lhu) # 37 .word _C_LABEL(bcemul_lwr) # 38 .word _C_LABEL(bcemul_sigill) # 39 .word _C_LABEL(bcemul_sb) # 40 .word _C_LABEL(bcemul_sh) # 41 .word _C_LABEL(bcemul_swl) # 42 .word _C_LABEL(bcemul_sw) # 43 .word _C_LABEL(bcemul_sigill) # 44 .word _C_LABEL(bcemul_sigill) # 45 .word _C_LABEL(bcemul_swr) # 46 .word _C_LABEL(bcemul_sigill) # 47 .word _C_LABEL(bcemul_sigill) # 48 .word _C_LABEL(MachEmulateLWC1) # 49 .word _C_LABEL(bcemul_sigill) # 50 .word _C_LABEL(bcemul_sigill) # 51 .word _C_LABEL(bcemul_sigill) # 52 .word _C_LABEL(MachEmulateLDC1) # 53 .word _C_LABEL(bcemul_sigill) # 54 .word _C_LABEL(bcemul_sigill) # 55 .word _C_LABEL(bcemul_sigill) # 56 .word _C_LABEL(MachEmulateSWC1) # 57 .word _C_LABEL(bcemul_sigill) # 58 .word _C_LABEL(bcemul_sigill) # 59 .word _C_LABEL(bcemul_sigill) # 60 .word _C_LABEL(MachEmulateSDC1) # 61 .word _C_LABEL(bcemul_sigill) # 62 .word _C_LABEL(bcemul_sigill) # 63 bcemul_specialtbl: .word bcemul_sll # 0 .word _C_LABEL(bcemul_sigill) # 1 .word bcemul_srl # 2 .word bcemul_sra # 3 .word bcemul_sllv # 4 .word _C_LABEL(bcemul_sigill) # 5 .word bcemul_srlv # 6 .word bcemul_srav # 7 .word _C_LABEL(bcemul_sigill) # 8 .word _C_LABEL(bcemul_sigill) # 9 .word _C_LABEL(bcemul_sigill) # 10 .word _C_LABEL(bcemul_sigill) # 11 .word _C_LABEL(bcemul_sigill) # 12 .word _C_LABEL(bcemul_sigill) # 13 .word _C_LABEL(bcemul_sigill) # 14 .word bcemul_sync # 15 .word bcemul_mfhi # 16 .word bcemul_mthi # 17 .word bcemul_mflo # 18 .word bcemul_mtlo # 19 .word _C_LABEL(bcemul_sigill) # 20 .word _C_LABEL(bcemul_sigill) # 21 .word _C_LABEL(bcemul_sigill) # 22 .word _C_LABEL(bcemul_sigill) # 23 .word bcemul_mult # 24 .word bcemul_multu # 25 .word bcemul_div # 26 .word bcemul_divu # 27 .word _C_LABEL(bcemul_sigill) # 28 .word _C_LABEL(bcemul_sigill) # 29 .word _C_LABEL(bcemul_sigill) # 30 .word _C_LABEL(bcemul_sigill) # 31 .word bcemul_add # 32 .word bcemul_addu # 33 .word bcemul_sub # 34 .word bcemul_subu # 35 .word bcemul_and # 36 .word bcemul_or # 37 .word bcemul_xor # 38 .word bcemul_nor # 39 .word _C_LABEL(bcemul_sigill) # 40 .word _C_LABEL(bcemul_sigill) # 41 .word bcemul_slt # 42 .word bcemul_sltu # 43 .word _C_LABEL(bcemul_sigill) # 44 .word _C_LABEL(bcemul_sigill) # 45 .word _C_LABEL(bcemul_sigill) # 46 .word _C_LABEL(bcemul_sigill) # 47 .word _C_LABEL(bcemul_sigill) # 48 .word _C_LABEL(bcemul_sigill) # 49 .word _C_LABEL(bcemul_sigill) # 50 .word _C_LABEL(bcemul_sigill) # 51 .word _C_LABEL(bcemul_sigill) # 52 .word _C_LABEL(bcemul_sigill) # 53 .word _C_LABEL(bcemul_sigill) # 54 .word _C_LABEL(bcemul_sigill) # 55 .word _C_LABEL(bcemul_sigill) # 56 .word _C_LABEL(bcemul_sigill) # 57 .word _C_LABEL(bcemul_sigill) # 58 .word _C_LABEL(bcemul_sigill) # 59 .word _C_LABEL(bcemul_sigill) # 60 .word _C_LABEL(bcemul_sigill) # 61 .word _C_LABEL(bcemul_sigill) # 62 .word _C_LABEL(bcemul_sigill) # 63 .text bcemul_addi: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 sll t2, a0, 16 sra t2, t2, 16 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_EPILOGUE addu t0, v0, t2 /* Overflow check */ xor t2, v0, t2 srl t2, t2, 31 bne t2, zero, addiok xor v0, v0, t0 srl v0, v0, 31 beq v0, zero, addiok j _C_LABEL(bcemul_sigfpe) addiok: REG_PROLOGUE REG_S t0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_addiu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 sll t2, a0, 16 sra t2, t2, 16 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) addu v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_slti: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 sll t2, a0, 16 sra t2, t2, 16 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) slt v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_sltiu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 sll t2, a0, 16 sra t2, t2, 16 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) sltu v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_andi: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 andi t2, a0, 0xFFFF REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) and v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_ori: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 andi t2, a0, 0xFFFF REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) or v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_xori: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 andi t2, a0, 0xFFFF REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) xor v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_lui: srl t0, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK addu t0, a1, t0 sll v0, a0, 16 REG_PROLOGUE REG_S v0, FRAME_ZERO(t0) REG_EPILOGUE b bcemul_done bcemul_sll: srl t0, a0, 16-SZREG_SHFT # rt srl t1, a0, 11-SZREG_SHFT # rd srl t2, a0, 6 # sa andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, 0x001F addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) sllv v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_srl: srl t0, a0, 16-SZREG_SHFT # rt srl t1, a0, 11-SZREG_SHFT # rd srl t2, a0, 6 # sa andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, 0x001F addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) srlv v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_sra: srl t0, a0, 16-SZREG_SHFT # rt srl t1, a0, 11-SZREG_SHFT # rd srl t2, a0, 6 # sa andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, 0x001F addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) srav v0, v0, t2 REG_S v0, FRAME_ZERO(t1) REG_EPILOGUE b bcemul_done bcemul_sllv: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) sllv v0, v1, v0 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_srlv: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) srlv v0, v1, v0 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_srav: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) srav v0, v1, v0 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_sync: b bcemul_done bcemul_mfhi: srl t0, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK addu t0, a1, t0 REG_PROLOGUE REG_L v0, FRAME_MULHI(a1) REG_S v0, FRAME_ZERO(t0) REG_EPILOGUE b bcemul_done bcemul_mthi: srl t0, a0, 21-SZREG_SHFT # rs andi t0, t0, SZREG_MASK addu t0, a1, t0 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_S v0, FRAME_MULHI(a1) REG_EPILOGUE b bcemul_done bcemul_mflo: srl t0, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK addu t0, a1, t0 REG_PROLOGUE REG_L v0, FRAME_MULLO(a1) REG_S v0, FRAME_ZERO(t0) REG_EPILOGUE b bcemul_done bcemul_mtlo: srl t0, a0, 21-SZREG_SHFT # rs andi t0, t0, SZREG_MASK addu t0, a1, t0 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_S v0, FRAME_MULLO(a1) REG_EPILOGUE b bcemul_done bcemul_mult: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE mult v0, v1 mflo v0 mfhi v1 REG_PROLOGUE REG_S v0, FRAME_MULLO(a1) REG_S v1, FRAME_MULHI(a1) REG_EPILOGUE b bcemul_done bcemul_multu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE multu v0, v1 mflo v0 mfhi v1 REG_PROLOGUE REG_S v0, FRAME_MULLO(a1) REG_S v1, FRAME_MULHI(a1) REG_EPILOGUE b bcemul_done bcemul_div: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE div v0, v1 mflo v0 mfhi v1 REG_PROLOGUE REG_S v0, FRAME_MULLO(a1) REG_S v1, FRAME_MULHI(a1) REG_EPILOGUE b bcemul_done bcemul_divu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE divu v0, v1 mflo v0 mfhi v1 REG_PROLOGUE REG_S v0, FRAME_MULLO(a1) REG_S v1, FRAME_MULHI(a1) REG_EPILOGUE b bcemul_done bcemul_add: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE addu t0, v0, v1 /* Overflow check */ xor v1, v0, v1 srl v1, v1, 31 bne v1, zero, addok xor v0, v0, t0 srl v0, v0, 31 beq v0, zero, addok j _C_LABEL(bcemul_sigfpe) addok: REG_PROLOGUE REG_S t0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_addu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) addu v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_sub: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) REG_EPILOGUE subu t0, v0, v1 /* Overflow check */ xor v1, v0, v1 srl v1, v1, 31 beq v1, zero, subok xor v0, v0, t0 srl v0, v0, 31 beq v0, zero, subok j _C_LABEL(bcemul_sigfpe) subok: REG_PROLOGUE REG_S t0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_subu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) subu v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_and: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) and v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_or: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) or v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_xor: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) xor v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_nor: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) nor v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_slt: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) slt v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE b bcemul_done bcemul_sltu: srl t0, a0, 21-SZREG_SHFT # rs srl t1, a0, 16-SZREG_SHFT # rt srl t2, a0, 11-SZREG_SHFT # rd andi t0, t0, SZREG_MASK andi t1, t1, SZREG_MASK andi t2, t2, SZREG_MASK addu t0, a1, t0 addu t1, a1, t1 addu t2, a1, t2 REG_PROLOGUE REG_L v0, FRAME_ZERO(t0) REG_L v1, FRAME_ZERO(t1) sltu v0, v0, v1 REG_S v0, FRAME_ZERO(t2) REG_EPILOGUE sw v0, FRAME_ZERO(t2) # b bcemul_done # fall through to bcemul_done bcemul_done: /* * Succeeded to emulate instruction with no error * so compute the next PC. */ subu sp, sp, CALLFRAME_SIZ sw ra, CALLFRAME_RA(sp) sw a1, CALLFRAME_SIZ + 4(sp) /* Fetch previous branch instruction */ REG_PROLOGUE REG_L a0, FRAME_EPC(a1) REG_EPILOGUE jal _C_LABEL(fuiword) lw a1, CALLFRAME_SIZ + 4(sp) /* Calculate branch destination */ sll t0, v0, 16 sra t0, t0, 16-2 REG_PROLOGUE REG_L t1, FRAME_EPC(a1) addiu t0, t0, 4 addu t1, t1, t0 REG_S t1, FRAME_EPC(a1) REG_EPILOGUE lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j ra END(bcemul_delay_slot) #endif /* * Send SIGILL, SIGFPE. * Args are same as MachEmulateFP. */ STATIC_LEAF(fpemul_sigill) #ifdef SOFTFLOAT STATIC_XLEAF(bcemul_sigill) #endif li t0, 0xFFFFFF00 and a2, a2, t0 ori a2, a2, T_RES_INST << MIPS_CR_EXC_CODE_SHIFT REG_PROLOGUE REG_S a2, FRAME_CAUSE(a1) REG_EPILOGUE move a2, a0 # code = instruction move a0, MIPS_CURLWP # get current process li a1, SIGILL j _C_LABEL(fpemul_trapsignal) END(fpemul_sigill) STATIC_LEAF(fpemul_sigfpe) li t0, 0xFFFFFF00 and a2, a2, t0 ori a2, a2, T_FPE << MIPS_CR_EXC_CODE_SHIFT REG_PROLOGUE REG_S a2, FRAME_CAUSE(a1) REG_EPILOGUE move a2, a0 # code = instruction move a0, MIPS_CURLWP # get current process li a1, SIGFPE j _C_LABEL(fpemul_trapsignal) END(fpemul_sigfpe) #ifdef SOFTFLOAT STATIC_LEAF(bcemul_sigfpe) li t0, 0xFFFFFF00 and a2, a2, t0 ori a2, a2, T_OVFLOW << MIPS_CR_EXC_CODE_SHIFT REG_PROLOGUE REG_S a2, FRAME_CAUSE(a1) REG_EPILOGUE move a2, a0 # code = instruction move a0, MIPS_CURLWP # get current process li a1, SIGFPE j _C_LABEL(fpemul_trapsignal) END(bcemul_sigfpe) #endif