Index: projects/mips64-clang/sys/mips/include/asm.h =================================================================== --- projects/mips64-clang/sys/mips/include/asm.h (revision 295726) +++ projects/mips64-clang/sys/mips/include/asm.h (revision 295727) @@ -1,711 +1,711 @@ /* $NetBSD: asm.h,v 1.29 2000/12/14 21:29:51 jeffs 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)machAsmDefs.h 8.1 (Berkeley) 6/10/93 * JNPR: asm.h,v 1.10 2007/08/09 11:23:32 katta * $FreeBSD$ */ /* * machAsmDefs.h -- * * Macros used when writing assembler programs. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsmDefs.h, * v 1.2 89/08/15 18:28:24 rab Exp SPRITE (DECWRL) */ #ifndef _MACHINE_ASM_H_ #define _MACHINE_ASM_H_ #include #include #include #undef __FBSDID #if !defined(lint) && !defined(STRIP_FBSDID) #define __FBSDID(s) .ident s #else #define __FBSDID(s) /* nothing */ #endif /* * Define -pg profile entry code. * Must always be noreorder, must never use a macro instruction * Final addiu to t9 must always equal the size of this _KERN_MCOUNT */ #define _KERN_MCOUNT \ .set push; \ .set noreorder; \ .set noat; \ subu sp,sp,16; \ sw t9,12(sp); \ move AT,ra; \ lui t9,%hi(_mcount); \ addiu t9,t9,%lo(_mcount); \ jalr t9; \ nop; \ lw t9,4(sp); \ addiu sp,sp,8; \ addiu t9,t9,40; \ .set pop; #ifdef GPROF #define MCOUNT _KERN_MCOUNT #else #define MCOUNT #endif #define _C_LABEL(x) x #ifdef USE_AENT #define AENT(x) \ .aent x, 0 #else #define AENT(x) #endif /* * WARN_REFERENCES: create a warning if the specified symbol is referenced */ #define WARN_REFERENCES(_sym,_msg) \ .section .gnu.warning. ## _sym ; .ascii _msg ; .text #ifdef __ELF__ # define _C_LABEL(x) x #else # define _C_LABEL(x) _ ## x #endif /* * WEAK_ALIAS: create a weak alias. */ #define WEAK_ALIAS(alias,sym) \ .weak alias; \ alias = sym /* * STRONG_ALIAS: create a strong alias. */ #define STRONG_ALIAS(alias,sym) \ .globl alias; \ alias = sym #define GLOBAL(sym) \ .globl sym; sym: #define ENTRY(sym) \ .text; .globl sym; .ent sym; sym: #define ASM_ENTRY(sym) \ .text; .globl sym; .type sym,@function; sym: /* * LEAF * A leaf routine does * - call no other function, * - never use any register that callee-saved (S0-S8), and * - not use any local stack storage. */ #define LEAF(x) \ .globl _C_LABEL(x); \ .ent _C_LABEL(x), 0; \ _C_LABEL(x): ; \ .frame sp, 0, ra; \ MCOUNT /* * LEAF_NOPROFILE * No profilable leaf routine. */ #define LEAF_NOPROFILE(x) \ .globl _C_LABEL(x); \ .ent _C_LABEL(x), 0; \ _C_LABEL(x): ; \ .frame sp, 0, ra /* * XLEAF * declare alternate entry to leaf routine */ #define XLEAF(x) \ .globl _C_LABEL(x); \ AENT (_C_LABEL(x)); \ _C_LABEL(x): /* * NESTED * A function calls other functions and needs * therefore stack space to save/restore registers. */ #define NESTED(x, fsize, retpc) \ .globl _C_LABEL(x); \ .ent _C_LABEL(x), 0; \ _C_LABEL(x): ; \ .frame sp, fsize, retpc; \ MCOUNT /* * NESTED_NOPROFILE(x) * No profilable nested routine. */ #define NESTED_NOPROFILE(x, fsize, retpc) \ .globl _C_LABEL(x); \ .ent _C_LABEL(x), 0; \ _C_LABEL(x): ; \ .frame sp, fsize, retpc /* * XNESTED * declare alternate entry point to nested routine. */ #define XNESTED(x) \ .globl _C_LABEL(x); \ AENT (_C_LABEL(x)); \ _C_LABEL(x): /* * END * Mark end of a procedure. */ #define END(x) \ .end _C_LABEL(x) /* * IMPORT -- import external symbol */ #define IMPORT(sym, size) \ .extern _C_LABEL(sym),size /* * EXPORT -- export definition of symbol */ #define EXPORT(x) \ .globl _C_LABEL(x); \ _C_LABEL(x): /* * VECTOR * exception vector entrypoint * XXX: regmask should be used to generate .mask */ #define VECTOR(x, regmask) \ .ent _C_LABEL(x),0; \ EXPORT(x); \ #define VECTOR_END(x) \ EXPORT(x ## End); \ END(x) /* * Macros to panic and printf from assembly language. */ #define PANIC(msg) \ PTR_LA a0, 9f; \ jal _C_LABEL(panic); \ nop; \ MSG(msg) #define PANIC_KSEG0(msg, reg) PANIC(msg) #define PRINTF(msg) \ PTR_LA a0, 9f; \ jal _C_LABEL(printf); \ nop; \ MSG(msg) #define MSG(msg) \ - .rdata; \ + .section .rdata; \ 9: .asciiz msg; \ .text #define ASMSTR(str) \ .asciiz str; \ .align 3 #if defined(__mips_o32) #define SZREG 4 #else #define SZREG 8 #endif #if defined(__mips_o32) || defined(__mips_o64) #define ALSK 7 /* stack alignment */ #define ALMASK -7 /* stack alignment */ #define SZFPREG 4 #define FP_L lwc1 #define FP_S swc1 #else #define ALSK 15 /* stack alignment */ #define ALMASK -15 /* stack alignment */ #define SZFPREG 8 #define FP_L ldc1 #define FP_S sdc1 #endif /* * standard callframe { * register_t cf_pad[N]; o32/64 (N=0), n32 (N=1) n64 (N=1) * register_t cf_args[4]; arg0 - arg3 (only on o32 and o64) * register_t cf_gp; global pointer (only on n32 and n64) * register_t cf_sp; frame pointer * register_t cf_ra; return address * }; */ #if defined(__mips_o32) || defined(__mips_o64) #define CALLFRAME_SIZ (SZREG * (4 + 2)) #define CALLFRAME_S0 0 #elif defined(__mips_n32) || defined(__mips_n64) #define CALLFRAME_SIZ (SZREG * 4) #define CALLFRAME_S0 (CALLFRAME_SIZ - 4 * SZREG) #endif #ifndef _KERNEL #define CALLFRAME_GP (CALLFRAME_SIZ - 3 * SZREG) #endif #define CALLFRAME_SP (CALLFRAME_SIZ - 2 * SZREG) #define CALLFRAME_RA (CALLFRAME_SIZ - 1 * SZREG) /* * Endian-independent assembly-code aliases for unaligned memory accesses. */ #if _BYTE_ORDER == _LITTLE_ENDIAN # define LWHI lwr # define LWLO lwl # define SWHI swr # define SWLO swl # if SZREG == 4 # define REG_LHI lwr # define REG_LLO lwl # define REG_SHI swr # define REG_SLO swl # else # define REG_LHI ldr # define REG_LLO ldl # define REG_SHI sdr # define REG_SLO sdl # endif #endif #if _BYTE_ORDER == _BIG_ENDIAN # define LWHI lwl # define LWLO lwr # define SWHI swl # define SWLO swr # if SZREG == 4 # define REG_LHI lwl # define REG_LLO lwr # define REG_SHI swl # define REG_SLO swr # else # define REG_LHI ldl # define REG_LLO ldr # define REG_SHI sdl # define REG_SLO sdr # endif #endif /* * While it would be nice to be compatible with the SGI * REG_L and REG_S macros, because they do not take parameters, it * is impossible to use them with the _MIPS_SIM_ABIX32 model. * * These macros hide the use of mips3 instructions from the * assembler to prevent the assembler from generating 64-bit style * ABI calls. */ #if _MIPS_SZPTR == 32 #define PTR_ADD add #define PTR_ADDI addi #define PTR_ADDU addu #define PTR_ADDIU addiu #define PTR_SUB add #define PTR_SUBI subi #define PTR_SUBU subu #define PTR_SUBIU subu #define PTR_L lw #define PTR_LA la #define PTR_LI li #define PTR_S sw #define PTR_SLL sll #define PTR_SLLV sllv #define PTR_SRL srl #define PTR_SRLV srlv #define PTR_SRA sra #define PTR_SRAV srav #define PTR_LL ll #define PTR_SC sc #define PTR_WORD .word #define PTR_SCALESHIFT 2 #else /* _MIPS_SZPTR == 64 */ #define PTR_ADD dadd #define PTR_ADDI daddi #define PTR_ADDU daddu #define PTR_ADDIU daddiu #define PTR_SUB dadd #define PTR_SUBI dsubi #define PTR_SUBU dsubu #define PTR_SUBIU dsubu #define PTR_L ld #define PTR_LA dla #define PTR_LI dli #define PTR_S sd #define PTR_SLL dsll #define PTR_SLLV dsllv #define PTR_SRL dsrl #define PTR_SRLV dsrlv #define PTR_SRA dsra #define PTR_SRAV dsrav #define PTR_LL lld #define PTR_SC scd #define PTR_WORD .dword #define PTR_SCALESHIFT 3 #endif /* _MIPS_SZPTR == 64 */ #if _MIPS_SZINT == 32 #define INT_ADD add #define INT_ADDI addi #define INT_ADDU addu #define INT_ADDIU addiu #define INT_SUB add #define INT_SUBI subi #define INT_SUBU subu #define INT_SUBIU subu #define INT_L lw #define INT_LA la #define INT_S sw #define INT_SLL sll #define INT_SLLV sllv #define INT_SRL srl #define INT_SRLV srlv #define INT_SRA sra #define INT_SRAV srav #define INT_LL ll #define INT_SC sc #define INT_WORD .word #define INT_SCALESHIFT 2 #else #define INT_ADD dadd #define INT_ADDI daddi #define INT_ADDU daddu #define INT_ADDIU daddiu #define INT_SUB dadd #define INT_SUBI dsubi #define INT_SUBU dsubu #define INT_SUBIU dsubu #define INT_L ld #define INT_LA dla #define INT_S sd #define INT_SLL dsll #define INT_SLLV dsllv #define INT_SRL dsrl #define INT_SRLV dsrlv #define INT_SRA dsra #define INT_SRAV dsrav #define INT_LL lld #define INT_SC scd #define INT_WORD .dword #define INT_SCALESHIFT 3 #endif #if _MIPS_SZLONG == 32 #define LONG_ADD add #define LONG_ADDI addi #define LONG_ADDU addu #define LONG_ADDIU addiu #define LONG_SUB add #define LONG_SUBI subi #define LONG_SUBU subu #define LONG_SUBIU subu #define LONG_L lw #define LONG_LA la #define LONG_S sw #define LONG_SLL sll #define LONG_SLLV sllv #define LONG_SRL srl #define LONG_SRLV srlv #define LONG_SRA sra #define LONG_SRAV srav #define LONG_LL ll #define LONG_SC sc #define LONG_WORD .word #define LONG_SCALESHIFT 2 #else #define LONG_ADD dadd #define LONG_ADDI daddi #define LONG_ADDU daddu #define LONG_ADDIU daddiu #define LONG_SUB dadd #define LONG_SUBI dsubi #define LONG_SUBU dsubu #define LONG_SUBIU dsubu #define LONG_L ld #define LONG_LA dla #define LONG_S sd #define LONG_SLL dsll #define LONG_SLLV dsllv #define LONG_SRL dsrl #define LONG_SRLV dsrlv #define LONG_SRA dsra #define LONG_SRAV dsrav #define LONG_LL lld #define LONG_SC scd #define LONG_WORD .dword #define LONG_SCALESHIFT 3 #endif #if SZREG == 4 #define REG_L lw #define REG_S sw #define REG_LI li #define REG_ADDU addu #define REG_SLL sll #define REG_SLLV sllv #define REG_SRL srl #define REG_SRLV srlv #define REG_SRA sra #define REG_SRAV srav #define REG_LL ll #define REG_SC sc #define REG_SCALESHIFT 2 #else #define REG_L ld #define REG_S sd #define REG_LI dli #define REG_ADDU daddu #define REG_SLL dsll #define REG_SLLV dsllv #define REG_SRL dsrl #define REG_SRLV dsrlv #define REG_SRA dsra #define REG_SRAV dsrav #define REG_LL lld #define REG_SC scd #define REG_SCALESHIFT 3 #endif #if _MIPS_ISA == _MIPS_ISA_MIPS1 || _MIPS_ISA == _MIPS_ISA_MIPS2 || \ _MIPS_ISA == _MIPS_ISA_MIPS32 #define MFC0 mfc0 #define MTC0 mtc0 #endif #if _MIPS_ISA == _MIPS_ISA_MIPS3 || _MIPS_ISA == _MIPS_ISA_MIPS4 || \ _MIPS_ISA == _MIPS_ISA_MIPS64 #define MFC0 dmfc0 #define MTC0 dmtc0 #endif #if defined(__mips_o32) || defined(__mips_o64) #ifdef __ABICALLS__ #define CPRESTORE(r) .cprestore r #define CPLOAD(r) .cpload r #else #define CPRESTORE(r) /* not needed */ #define CPLOAD(r) /* not needed */ #endif #define SETUP_GP \ .set push; \ .set noreorder; \ .cpload t9; \ .set pop #define SETUP_GPX(r) \ .set push; \ .set noreorder; \ move r,ra; /* save old ra */ \ bal 7f; \ nop; \ 7: .cpload ra; \ move ra,r; \ .set pop #define SETUP_GPX_L(r,lbl) \ .set push; \ .set noreorder; \ move r,ra; /* save old ra */ \ bal lbl; \ nop; \ lbl: .cpload ra; \ move ra,r; \ .set pop #define SAVE_GP(x) .cprestore x #define SETUP_GP64(a,b) /* n32/n64 specific */ #define SETUP_GP64_R(a,b) /* n32/n64 specific */ #define SETUP_GPX64(a,b) /* n32/n64 specific */ #define SETUP_GPX64_L(a,b,c) /* n32/n64 specific */ #define RESTORE_GP64 /* n32/n64 specific */ #define USE_ALT_CP(a) /* n32/n64 specific */ #endif /* __mips_o32 || __mips_o64 */ #if defined(__mips_o32) || defined(__mips_o64) #define REG_PROLOGUE .set push #define REG_EPILOGUE .set pop #endif #if defined(__mips_n32) || defined(__mips_n64) #define REG_PROLOGUE .set push ; .set mips3 #define REG_EPILOGUE .set pop #endif #if defined(__mips_n32) || defined(__mips_n64) #define SETUP_GP /* o32 specific */ #define SETUP_GPX(r) /* o32 specific */ #define SETUP_GPX_L(r,lbl) /* o32 specific */ #define SAVE_GP(x) /* o32 specific */ #define SETUP_GP64(a,b) .cpsetup $25, a, b #define SETUP_GPX64(a,b) \ .set push; \ move b,ra; \ .set noreorder; \ bal 7f; \ nop; \ 7: .set pop; \ .cpsetup ra, a, 7b; \ move ra,b #define SETUP_GPX64_L(a,b,c) \ .set push; \ move b,ra; \ .set noreorder; \ bal c; \ nop; \ c: .set pop; \ .cpsetup ra, a, c; \ move ra,b #define RESTORE_GP64 .cpreturn #define USE_ALT_CP(a) .cplocal a #endif /* __mips_n32 || __mips_n64 */ #define GET_CPU_PCPU(reg) \ PTR_L reg, _C_LABEL(pcpup); /* * Description of the setjmp buffer * * word 0 magic number (dependant on creator) * 1 RA * 2 S0 * 3 S1 * 4 S2 * 5 S3 * 6 S4 * 7 S5 * 8 S6 * 9 S7 * 10 SP * 11 S8 * 12 GP (dependent on ABI) * 13 signal mask (dependant on magic) * 14 (con't) * 15 (con't) * 16 (con't) * * The magic number number identifies the jmp_buf and * how the buffer was created as well as providing * a sanity check * */ #define _JB_MAGIC__SETJMP 0xBADFACED #define _JB_MAGIC_SETJMP 0xFACEDBAD /* Valid for all jmp_buf's */ #define _JB_MAGIC 0 #define _JB_REG_RA 1 #define _JB_REG_S0 2 #define _JB_REG_S1 3 #define _JB_REG_S2 4 #define _JB_REG_S3 5 #define _JB_REG_S4 6 #define _JB_REG_S5 7 #define _JB_REG_S6 8 #define _JB_REG_S7 9 #define _JB_REG_SP 10 #define _JB_REG_S8 11 #if defined(__mips_n32) || defined(__mips_n64) #define _JB_REG_GP 12 #endif /* Only valid with the _JB_MAGIC_SETJMP magic */ #define _JB_SIGMASK 13 #define __JB_SIGMASK_REMAINDER 14 /* sigmask_t is 128-bits */ #define _JB_FPREG_F20 15 #define _JB_FPREG_F21 16 #define _JB_FPREG_F22 17 #define _JB_FPREG_F23 18 #define _JB_FPREG_F24 19 #define _JB_FPREG_F25 20 #define _JB_FPREG_F26 21 #define _JB_FPREG_F27 22 #define _JB_FPREG_F28 23 #define _JB_FPREG_F29 24 #define _JB_FPREG_F30 25 #define _JB_FPREG_F31 26 #define _JB_FPREG_FCSR 27 /* * Various macros for dealing with TLB hazards * (a) why so many? * (b) when to use? * (c) why not used everywhere? */ /* * Assume that w alaways need nops to escape CP0 hazard * TODO: Make hazard delays configurable. Stuck with 5 cycles on the moment * For more info on CP0 hazards see Chapter 7 (p.99) of "MIPS32 Architecture * For Programmers Volume III: The MIPS32 Privileged Resource Architecture" */ #if defined(CPU_NLM) #define HAZARD_DELAY sll $0,3 #define ITLBNOPFIX sll $0,3 #elif defined(CPU_RMI) #define HAZARD_DELAY #define ITLBNOPFIX #elif defined(CPU_MIPS74K) #define HAZARD_DELAY sll $0,$0,3 #define ITLBNOPFIX sll $0,$0,3 #else #define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;sll $0,$0,3; #define HAZARD_DELAY nop;nop;nop;nop;sll $0,$0,3; #endif #endif /* !_MACHINE_ASM_H_ */ Index: projects/mips64-clang/sys/mips/mips/exception.S =================================================================== --- projects/mips64-clang/sys/mips/mips/exception.S (revision 295726) +++ projects/mips64-clang/sys/mips/mips/exception.S (revision 295727) @@ -1,1272 +1,1274 @@ /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Digital Equipment Corporation and 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 * JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta * $FreeBSD$ */ /* * Contains code that is the first executed at boot time plus * assembly language support routines. */ #include "opt_ddb.h" #include #include #include #include #include #include #include "assym.s" .set noreorder # Noreorder is default style! #ifdef KDTRACE_HOOKS .data .globl dtrace_invop_jump_addr .align 4 .type dtrace_invop_jump_addr, @object .size dtrace_invop_jump_addr, 8 dtrace_invop_jump_addr: .word 0 .word 0 .globl dtrace_invop_calltrap_addr .align 4 .type dtrace_invop_calltrap_addr, @object .size dtrace_invop_calltrap_addr, 8 dtrace_invop_calltrap_addr: .word 0 .word 0 .text #endif /* * Reasonable limit */ #define INTRCNT_COUNT 256 /* *---------------------------------------------------------------------------- * * MipsTLBMiss -- * * Vector code for the TLB-miss exception vector 0x80000000. * * This code is copied to the TLB exception vector address to * which the CPU jumps in response to an exception or a TLB miss. * NOTE: This code must be position independent!!! * * */ VECTOR(MipsTLBMiss, unknown) .set push .set noat j MipsDoTLBMiss MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address .set pop VECTOR_END(MipsTLBMiss) /* *---------------------------------------------------------------------------- * * MipsDoTLBMiss -- * * This is the real TLB Miss Handler code. * 'segbase' points to the base of the segment table for user processes. * * Don't check for invalid pte's here. We load them as well and * let the processor trap to load the correct value after service. *---------------------------------------------------------------------------- */ .set push .set noat MipsDoTLBMiss: bltz k0, 1f #02: k0<0 -> 1f (kernel fault) PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) GET_CPU_PCPU(k1) PTR_L k1, PC_SEGBASE(k1) beqz k1, 2f #05: make sure segbase is not null andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 #07: k1=seg entry address PTR_L k1, 0(k1) #08: k1=seg entry MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) beq k1, zero, 2f #0a: ==0 -- no page table #ifdef __mips_n64 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, 2f # ==0 -- no page table #endif PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) andi k0, k0, PTE2MASK #0c: k0=page tab offset PTR_ADDU k1, k1, k0 #0d: k1=pte address PTE_L k0, 0(k1) #0e: k0=lo0 pte PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded COP0_SYNC tlbwr #1a: write to tlb HAZARD_DELAY eret #1f: retUrn from exception 1: j MipsTLBMissException #20: kernel exception nop #21: branch delay slot 2: j SlowFault #22: no page table present nop #23: branch delay slot .set pop /* * This code is copied to the general exception vector address to * handle all execptions except RESET and TLBMiss. * NOTE: This code must be position independent!!! */ VECTOR(MipsException, unknown) /* * Find out what mode we came from and jump to the proper handler. * * Note: at turned off here because we cannot trash the at register * in this exception code. Only k0 and k1 may be modified before * we save registers. This is true of all functions called through * the pointer magic: Mips{User,Kern}Intr, Mips{User,Kern}GenException * and MipsTLBInvalidException */ .set noat mfc0 k0, MIPS_COP_0_STATUS # Get the status register mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value. and k0, k0, MIPS_SR_KSU_USER # test for user mode # sneaky but the bits are # with us........ sll k0, k0, 3 # shift user bit for cause index and k1, k1, MIPS_CR_EXC_CODE # Mask out the cause bits. or k1, k1, k0 # change index to user table #if defined(__mips_n64) PTR_SLL k1, k1, 1 # shift to get 8-byte offset #endif 1: + .set at PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table + .set noat PTR_ADDU k0, k0, k1 # Get the address of the # function entry. Note that # the cause is already # shifted left by 2 bits so # we dont have to shift. PTR_L k0, 0(k0) # Get the function address nop j k0 # Jump to the function. nop .set at VECTOR_END(MipsException) /* * We couldn't find a TLB entry. * Find out what mode we came from and call the appropriate handler. */ SlowFault: .set noat mfc0 k0, MIPS_COP_0_STATUS nop and k0, k0, MIPS_SR_KSU_USER bne k0, zero, _C_LABEL(MipsUserGenException) nop .set at /* * Fall though ... */ /*---------------------------------------------------------------------------- * * MipsKernGenException -- * * Handle an exception from kernel mode. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ #define SAVE_REG(reg, offs, base) \ REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base) #if defined(CPU_CNMIPS) #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ or a0, a0, a2 ; \ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #elif defined(CPU_RMI) || defined(CPU_NLM) #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \ or a0, a0, a2 ; \ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #else #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #endif /* * Save CPU and CP0 register state. * * This is straightforward except for saving the exception program * counter. The ddb backtrace code looks for the first instruction * matching the form "sw ra, (off)sp" to figure out the address of the * calling function. So we must make sure that we save the exception * PC by staging it through 'ra' as opposed to any other register. */ #define SAVE_CPU \ SAVE_REG(AT, AST, sp) ;\ .set at ; \ SAVE_REG(v0, V0, sp) ;\ SAVE_REG(v1, V1, sp) ;\ SAVE_REG(a0, A0, sp) ;\ SAVE_REG(a1, A1, sp) ;\ SAVE_REG(a2, A2, sp) ;\ SAVE_REG(a3, A3, sp) ;\ SAVE_REG(t0, T0, sp) ;\ SAVE_REG(t1, T1, sp) ;\ SAVE_REG(t2, T2, sp) ;\ SAVE_REG(t3, T3, sp) ;\ SAVE_REG(ta0, TA0, sp) ;\ SAVE_REG(ta1, TA1, sp) ;\ SAVE_REG(ta2, TA2, sp) ;\ SAVE_REG(ta3, TA3, sp) ;\ SAVE_REG(t8, T8, sp) ;\ SAVE_REG(t9, T9, sp) ;\ SAVE_REG(gp, GP, sp) ;\ SAVE_REG(s0, S0, sp) ;\ SAVE_REG(s1, S1, sp) ;\ SAVE_REG(s2, S2, sp) ;\ SAVE_REG(s3, S3, sp) ;\ SAVE_REG(s4, S4, sp) ;\ SAVE_REG(s5, S5, sp) ;\ SAVE_REG(s6, S6, sp) ;\ SAVE_REG(s7, S7, sp) ;\ SAVE_REG(s8, S8, sp) ;\ mflo v0 ;\ mfhi v1 ;\ mfc0 a0, MIPS_COP_0_STATUS ;\ mfc0 a1, MIPS_COP_0_CAUSE ;\ MFC0 a2, MIPS_COP_0_BAD_VADDR;\ MFC0 a3, MIPS_COP_0_EXC_PC ;\ SAVE_REG(v0, MULLO, sp) ;\ SAVE_REG(v1, MULHI, sp) ;\ SAVE_REG(a0, SR, sp) ;\ SAVE_REG(a1, CAUSE, sp) ;\ SAVE_REG(a2, BADVADDR, sp) ;\ move t0, ra ;\ move ra, a3 ;\ SAVE_REG(ra, PC, sp) ;\ move ra, t0 ;\ SAVE_REG(ra, RA, sp) ;\ PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\ SAVE_REG(v0, SP, sp) ;\ CLEAR_STATUS ;\ PTR_ADDU a0, sp, CALLFRAME_SIZ ;\ ITLBNOPFIX #define RESTORE_REG(reg, offs, base) \ REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base) #define RESTORE_CPU \ CLEAR_STATUS ;\ RESTORE_REG(k0, SR, sp) ;\ RESTORE_REG(t0, MULLO, sp) ;\ RESTORE_REG(t1, MULHI, sp) ;\ mtlo t0 ;\ mthi t1 ;\ MTC0 v0, MIPS_COP_0_EXC_PC ;\ .set noat ;\ RESTORE_REG(AT, AST, sp) ;\ RESTORE_REG(v0, V0, sp) ;\ RESTORE_REG(v1, V1, sp) ;\ RESTORE_REG(a0, A0, sp) ;\ RESTORE_REG(a1, A1, sp) ;\ RESTORE_REG(a2, A2, sp) ;\ RESTORE_REG(a3, A3, sp) ;\ RESTORE_REG(t0, T0, sp) ;\ RESTORE_REG(t1, T1, sp) ;\ RESTORE_REG(t2, T2, sp) ;\ RESTORE_REG(t3, T3, sp) ;\ RESTORE_REG(ta0, TA0, sp) ;\ RESTORE_REG(ta1, TA1, sp) ;\ RESTORE_REG(ta2, TA2, sp) ;\ RESTORE_REG(ta3, TA3, sp) ;\ RESTORE_REG(t8, T8, sp) ;\ RESTORE_REG(t9, T9, sp) ;\ RESTORE_REG(s0, S0, sp) ;\ RESTORE_REG(s1, S1, sp) ;\ RESTORE_REG(s2, S2, sp) ;\ RESTORE_REG(s3, S3, sp) ;\ RESTORE_REG(s4, S4, sp) ;\ RESTORE_REG(s5, S5, sp) ;\ RESTORE_REG(s6, S6, sp) ;\ RESTORE_REG(s7, S7, sp) ;\ RESTORE_REG(s8, S8, sp) ;\ RESTORE_REG(gp, GP, sp) ;\ RESTORE_REG(ra, RA, sp) ;\ PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\ mtc0 k0, MIPS_COP_0_STATUS /* * The kernel exception stack contains 18 saved general registers, * the status register and the multiply lo and high registers. * In addition, we set this up for linkage conventions. */ #define KERN_REG_SIZE (NUMSAVEREGS * SZREG) #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16) NESTED_NOPROFILE(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra) .set noat PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) /* * Save CPU state, building 'frame'. */ SAVE_CPU /* * Call the exception handler. a0 points at the saved frame. */ PTR_LA gp, _C_LABEL(_gp) PTR_LA k0, _C_LABEL(trap) jalr k0 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging /* * Update interrupt and CPU mask in saved status register * Some of interrupts could be disabled by * intr filters if interrupts are enabled later * in trap handler */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) RESTORE_REG(a1, SR, sp) and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) or a1, a1, a0 SAVE_REG(a1, SR, sp) RESTORE_CPU # v0 contains the return address. sync eret .set at END(MipsKernGenException) /*---------------------------------------------------------------------------- * * MipsUserGenException -- * * Handle an exception from user mode. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsUserGenException, CALLFRAME_SIZ, ra) .set noat .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) /* * Save all of the registers except for the kernel temporaries in u.u_pcb. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) SAVE_U_PCB_REG(AT, AST, k1) .set at SAVE_U_PCB_REG(v0, V0, k1) SAVE_U_PCB_REG(v1, V1, k1) SAVE_U_PCB_REG(a0, A0, k1) mflo v0 SAVE_U_PCB_REG(a1, A1, k1) SAVE_U_PCB_REG(a2, A2, k1) SAVE_U_PCB_REG(a3, A3, k1) SAVE_U_PCB_REG(t0, T0, k1) mfhi v1 SAVE_U_PCB_REG(t1, T1, k1) SAVE_U_PCB_REG(t2, T2, k1) SAVE_U_PCB_REG(t3, T3, k1) SAVE_U_PCB_REG(ta0, TA0, k1) mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg. SAVE_U_PCB_REG(ta1, TA1, k1) SAVE_U_PCB_REG(ta2, TA2, k1) SAVE_U_PCB_REG(ta3, TA3, k1) SAVE_U_PCB_REG(s0, S0, k1) mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg. SAVE_U_PCB_REG(s1, S1, k1) SAVE_U_PCB_REG(s2, S2, k1) SAVE_U_PCB_REG(s3, S3, k1) SAVE_U_PCB_REG(s4, S4, k1) MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr SAVE_U_PCB_REG(s5, S5, k1) SAVE_U_PCB_REG(s6, S6, k1) SAVE_U_PCB_REG(s7, S7, k1) SAVE_U_PCB_REG(t8, T8, k1) MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc. SAVE_U_PCB_REG(t9, T9, k1) SAVE_U_PCB_REG(gp, GP, k1) SAVE_U_PCB_REG(sp, SP, k1) SAVE_U_PCB_REG(s8, S8, k1) PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP SAVE_U_PCB_REG(ra, RA, k1) SAVE_U_PCB_REG(v0, MULLO, k1) SAVE_U_PCB_REG(v1, MULHI, k1) SAVE_U_PCB_REG(a0, SR, k1) SAVE_U_PCB_REG(a1, CAUSE, k1) SAVE_U_PCB_REG(a2, BADVADDR, k1) SAVE_U_PCB_REG(a3, PC, k1) REG_S a3, CALLFRAME_RA(sp) # for debugging PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP # Turn off fpu and enter kernel mode and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE) #if defined(CPU_CNMIPS) and t0, t0, ~(MIPS_SR_COP_2_BIT) or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) #elif defined(CPU_RMI) || defined(CPU_NLM) or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) #endif mtc0 t0, MIPS_COP_0_STATUS PTR_ADDU a0, k1, U_PCB_REGS ITLBNOPFIX /* * Call the exception handler. */ PTR_LA k0, _C_LABEL(trap) jalr k0 nop /* * Restore user registers and return. * First disable interrupts and set exeption level. */ DO_AST CLEAR_STATUS /* * The use of k1 for storing the PCB pointer must be done only * after interrupts are disabled. Otherwise it will get overwritten * by the interrupt code. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) /* * Update interrupt mask in saved status register * Some of interrupts could be enabled by ithread * scheduled by ast() */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, MIPS_SR_INT_MASK RESTORE_U_PCB_REG(a1, SR, k1) and a1, a1, ~MIPS_SR_INT_MASK or a1, a1, a0 SAVE_U_PCB_REG(a1, SR, k1) RESTORE_U_PCB_REG(t0, MULLO, k1) RESTORE_U_PCB_REG(t1, MULHI, k1) mtlo t0 mthi t1 RESTORE_U_PCB_REG(a0, PC, k1) RESTORE_U_PCB_REG(v0, V0, k1) MTC0 a0, MIPS_COP_0_EXC_PC # set return address RESTORE_U_PCB_REG(v1, V1, k1) RESTORE_U_PCB_REG(a0, A0, k1) RESTORE_U_PCB_REG(a1, A1, k1) RESTORE_U_PCB_REG(a2, A2, k1) RESTORE_U_PCB_REG(a3, A3, k1) RESTORE_U_PCB_REG(t0, T0, k1) RESTORE_U_PCB_REG(t1, T1, k1) RESTORE_U_PCB_REG(t2, T2, k1) RESTORE_U_PCB_REG(t3, T3, k1) RESTORE_U_PCB_REG(ta0, TA0, k1) RESTORE_U_PCB_REG(ta1, TA1, k1) RESTORE_U_PCB_REG(ta2, TA2, k1) RESTORE_U_PCB_REG(ta3, TA3, k1) RESTORE_U_PCB_REG(s0, S0, k1) RESTORE_U_PCB_REG(s1, S1, k1) RESTORE_U_PCB_REG(s2, S2, k1) RESTORE_U_PCB_REG(s3, S3, k1) RESTORE_U_PCB_REG(s4, S4, k1) RESTORE_U_PCB_REG(s5, S5, k1) RESTORE_U_PCB_REG(s6, S6, k1) RESTORE_U_PCB_REG(s7, S7, k1) RESTORE_U_PCB_REG(t8, T8, k1) RESTORE_U_PCB_REG(t9, T9, k1) RESTORE_U_PCB_REG(gp, GP, k1) RESTORE_U_PCB_REG(sp, SP, k1) RESTORE_U_PCB_REG(k0, SR, k1) RESTORE_U_PCB_REG(s8, S8, k1) RESTORE_U_PCB_REG(ra, RA, k1) .set noat RESTORE_U_PCB_REG(AT, AST, k1) mtc0 k0, MIPS_COP_0_STATUS # still exception level ITLBNOPFIX sync eret .set at END(MipsUserGenException) .set push .set noat NESTED(mips_wait, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) REG_S ra, CALLFRAME_RA(sp) # save RA mfc0 t0, MIPS_COP_0_STATUS xori t1, t0, MIPS_SR_INT_IE mtc0 t1, MIPS_COP_0_STATUS COP0_SYNC jal sched_runnable nop REG_L ra, CALLFRAME_RA(sp) mfc0 t0, MIPS_COP_0_STATUS ori t1, t0, MIPS_SR_INT_IE .align 4 GLOBAL(MipsWaitStart) # this is 16 byte aligned mtc0 t1, MIPS_COP_0_STATUS bnez v0, MipsWaitEnd nop wait GLOBAL(MipsWaitEnd) # MipsWaitStart + 16 jr ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(mips_wait) .set pop /*---------------------------------------------------------------------------- * * MipsKernIntr -- * * Handle an interrupt from kernel mode. * Interrupts use the standard kernel stack. * switch_exit sets up a kernel stack after exit so interrupts won't fail. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) .set noat PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) /* * Check for getting interrupts just before wait */ MFC0 k0, MIPS_COP_0_EXC_PC ori k0, 0xf xori k0, 0xf # 16 byte align PTR_LA k1, MipsWaitStart bne k0, k1, 1f nop PTR_ADDU k1, 16 # skip over wait MTC0 k1, MIPS_COP_0_EXC_PC 1: /* * Save CPU state, building 'frame'. */ SAVE_CPU /* * Call the interrupt handler. a0 points at the saved frame. */ PTR_LA gp, _C_LABEL(_gp) #ifdef MIPS_INTRNG PTR_LA k0, _C_LABEL(intr_irq_handler) #else PTR_LA k0, _C_LABEL(cpu_intr) #endif jalr k0 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging /* * Update interrupt and CPU mask in saved status register * Some of interrupts could be disabled by * intr filters if interrupts are enabled later * in trap handler */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) RESTORE_REG(a1, SR, sp) and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) or a1, a1, a0 SAVE_REG(a1, SR, sp) REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp) RESTORE_CPU # v0 contains the return address. sync eret .set at END(MipsKernIntr) /*---------------------------------------------------------------------------- * * MipsUserIntr -- * * Handle an interrupt from user mode. * Note: we save minimal state in the u.u_pcb struct and use the standard * kernel stack since there has to be a u page if we came from user mode. * If there is a pending software interrupt, then save the remaining state * and call softintr(). This is all because if we call switch() inside * interrupt(), not all the user registers have been saved in u.u_pcb. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra) .set noat .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) /* * Save the relevant user registers into the u.u_pcb struct. * We don't need to save s0 - s8 because the compiler does it for us. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) SAVE_U_PCB_REG(AT, AST, k1) .set at SAVE_U_PCB_REG(v0, V0, k1) SAVE_U_PCB_REG(v1, V1, k1) SAVE_U_PCB_REG(a0, A0, k1) SAVE_U_PCB_REG(a1, A1, k1) SAVE_U_PCB_REG(a2, A2, k1) SAVE_U_PCB_REG(a3, A3, k1) SAVE_U_PCB_REG(t0, T0, k1) SAVE_U_PCB_REG(t1, T1, k1) SAVE_U_PCB_REG(t2, T2, k1) SAVE_U_PCB_REG(t3, T3, k1) SAVE_U_PCB_REG(ta0, TA0, k1) SAVE_U_PCB_REG(ta1, TA1, k1) SAVE_U_PCB_REG(ta2, TA2, k1) SAVE_U_PCB_REG(ta3, TA3, k1) SAVE_U_PCB_REG(t8, T8, k1) SAVE_U_PCB_REG(t9, T9, k1) SAVE_U_PCB_REG(gp, GP, k1) SAVE_U_PCB_REG(sp, SP, k1) SAVE_U_PCB_REG(ra, RA, k1) /* * save remaining user state in u.u_pcb. */ SAVE_U_PCB_REG(s0, S0, k1) SAVE_U_PCB_REG(s1, S1, k1) SAVE_U_PCB_REG(s2, S2, k1) SAVE_U_PCB_REG(s3, S3, k1) SAVE_U_PCB_REG(s4, S4, k1) SAVE_U_PCB_REG(s5, S5, k1) SAVE_U_PCB_REG(s6, S6, k1) SAVE_U_PCB_REG(s7, S7, k1) SAVE_U_PCB_REG(s8, S8, k1) mflo v0 # get lo/hi late to avoid stall mfhi v1 mfc0 a0, MIPS_COP_0_STATUS mfc0 a1, MIPS_COP_0_CAUSE MFC0 a3, MIPS_COP_0_EXC_PC SAVE_U_PCB_REG(v0, MULLO, k1) SAVE_U_PCB_REG(v1, MULHI, k1) SAVE_U_PCB_REG(a0, SR, k1) SAVE_U_PCB_REG(a1, CAUSE, k1) SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK) #ifdef CPU_CNMIPS and t0, t0, ~(MIPS_SR_COP_2_BIT) or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) #elif defined(CPU_RMI) || defined(CPU_NLM) or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) #endif mtc0 t0, MIPS_COP_0_STATUS ITLBNOPFIX PTR_ADDU a0, k1, U_PCB_REGS /* * Call the interrupt handler. */ #ifdef MIPS_INTRNG PTR_LA k0, _C_LABEL(intr_irq_handler) #else PTR_LA k0, _C_LABEL(cpu_intr) #endif jalr k0 REG_S a3, CALLFRAME_RA(sp) # for debugging /* * Enable interrupts before doing ast(). * * On SMP kernels the AST processing might trigger IPI to other processors. * If that processor is also doing AST processing with interrupts disabled * then we may deadlock. */ mfc0 a0, MIPS_COP_0_STATUS or a0, a0, MIPS_SR_INT_IE mtc0 a0, MIPS_COP_0_STATUS ITLBNOPFIX /* * DO_AST enabled interrupts */ DO_AST /* * Restore user registers and return. */ CLEAR_STATUS GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) /* * Update interrupt mask in saved status register * Some of interrupts could be disabled by * intr filters */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, MIPS_SR_INT_MASK RESTORE_U_PCB_REG(a1, SR, k1) and a1, a1, ~MIPS_SR_INT_MASK or a1, a1, a0 SAVE_U_PCB_REG(a1, SR, k1) RESTORE_U_PCB_REG(s0, S0, k1) RESTORE_U_PCB_REG(s1, S1, k1) RESTORE_U_PCB_REG(s2, S2, k1) RESTORE_U_PCB_REG(s3, S3, k1) RESTORE_U_PCB_REG(s4, S4, k1) RESTORE_U_PCB_REG(s5, S5, k1) RESTORE_U_PCB_REG(s6, S6, k1) RESTORE_U_PCB_REG(s7, S7, k1) RESTORE_U_PCB_REG(s8, S8, k1) RESTORE_U_PCB_REG(t0, MULLO, k1) RESTORE_U_PCB_REG(t1, MULHI, k1) RESTORE_U_PCB_REG(t2, PC, k1) mtlo t0 mthi t1 MTC0 t2, MIPS_COP_0_EXC_PC # set return address RESTORE_U_PCB_REG(v0, V0, k1) RESTORE_U_PCB_REG(v1, V1, k1) RESTORE_U_PCB_REG(a0, A0, k1) RESTORE_U_PCB_REG(a1, A1, k1) RESTORE_U_PCB_REG(a2, A2, k1) RESTORE_U_PCB_REG(a3, A3, k1) RESTORE_U_PCB_REG(t0, T0, k1) RESTORE_U_PCB_REG(t1, T1, k1) RESTORE_U_PCB_REG(t2, T2, k1) RESTORE_U_PCB_REG(t3, T3, k1) RESTORE_U_PCB_REG(ta0, TA0, k1) RESTORE_U_PCB_REG(ta1, TA1, k1) RESTORE_U_PCB_REG(ta2, TA2, k1) RESTORE_U_PCB_REG(ta3, TA3, k1) RESTORE_U_PCB_REG(t8, T8, k1) RESTORE_U_PCB_REG(t9, T9, k1) RESTORE_U_PCB_REG(gp, GP, k1) RESTORE_U_PCB_REG(k0, SR, k1) RESTORE_U_PCB_REG(sp, SP, k1) RESTORE_U_PCB_REG(ra, RA, k1) .set noat RESTORE_U_PCB_REG(AT, AST, k1) mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set. ITLBNOPFIX sync eret .set at END(MipsUserIntr) LEAF_NOPROFILE(MipsTLBInvalidException) .set push .set noat .set noreorder MFC0 k0, MIPS_COP_0_BAD_VADDR PTR_LI k1, VM_MAXUSER_ADDRESS sltu k1, k0, k1 bnez k1, 1f nop /* Kernel address. */ lui k1, %hi(kernel_segmap) # k1=hi of segbase b 2f PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 1: /* User address. */ GET_CPU_PCPU(k1) PTR_L k1, PC_SEGBASE(k1) 2: /* Validate page directory pointer. */ beqz k1, 3f nop PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) beq k1, zero, MipsKernGenException # ==0 -- no seg tab andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 # k1=seg entry address PTR_L k1, 0(k1) # k1=seg entry /* Validate page table pointer. */ beqz k1, 3f nop #ifdef __mips_n64 MFC0 k0, MIPS_COP_0_BAD_VADDR PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) beq k1, zero, MipsKernGenException # ==0 -- no pde tab andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry /* Validate pde table pointer. */ beqz k1, 3f nop #endif MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN andi k0, k0, PTEMASK # k0=page tab offset PTR_ADDU k1, k1, k0 # k1=pte address PTE_L k0, 0(k1) # k0=this PTE /* Validate page table entry. */ andi k0, PTE_V beqz k0, 3f nop /* Check whether this is an even or odd entry. */ andi k0, k1, PTESIZE bnez k0, odd_page nop PTE_L k0, 0(k1) PTE_L k1, PTESIZE(k1) CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 COP0_SYNC b tlb_insert_entry nop odd_page: PTE_L k0, -PTESIZE(k1) PTE_L k1, 0(k1) CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 COP0_SYNC tlb_insert_entry: tlbp HAZARD_DELAY mfc0 k0, MIPS_COP_0_TLB_INDEX bltz k0, tlb_insert_random nop tlbwi eret ssnop tlb_insert_random: tlbwr eret ssnop 3: /* * Branch to the comprehensive exception processing. */ mfc0 k1, MIPS_COP_0_STATUS andi k1, k1, MIPS_SR_KSU_USER bnez k1, _C_LABEL(MipsUserGenException) nop /* * Check for kernel stack overflow. */ GET_CPU_PCPU(k1) PTR_L k0, PC_CURTHREAD(k1) PTR_L k0, TD_KSTACK(k0) sltu k0, k0, sp bnez k0, _C_LABEL(MipsKernGenException) nop /* * Kernel stack overflow. * * Move to a valid stack before we call panic. We use the boot stack * for this purpose. */ GET_CPU_PCPU(k1) lw k1, PC_CPUID(k1) sll k1, k1, PAGE_SHIFT + 1 PTR_LA k0, _C_LABEL(pcpu_space) PTR_ADDU k0, PAGE_SIZE * 2 PTR_ADDU k0, k0, k1 /* * Stash the original value of 'sp' so we can update trapframe later. * We assume that SAVE_CPU does not trash 'k1'. */ move k1, sp move sp, k0 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE move k0, ra move ra, zero REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */ REG_S zero, CALLFRAME_SP(sp) move ra, k0 SAVE_CPU /* * Now restore the value of 'sp' at the time of the tlb exception in * the trapframe. */ SAVE_REG(k1, SP, sp) /* * Squelch any more overflow checks by setting the stack base to 0. */ GET_CPU_PCPU(k1) PTR_L k0, PC_CURTHREAD(k1) PTR_S zero, TD_KSTACK(k0) move a1, a0 PANIC("kernel stack overflow - trapframe at %p") /* * This nop is necessary so that the 'ra' remains within the bounds * of this handler. Otherwise the ddb backtrace code will think that * the panic() was called from MipsTLBMissException. */ nop .set pop END(MipsTLBInvalidException) /*---------------------------------------------------------------------------- * * MipsTLBMissException -- * * Handle a TLB miss exception from kernel mode in kernel space. * The BaddVAddr, Context, and EntryHi registers contain the failed * virtual address. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ LEAF_NOPROFILE(MipsTLBMissException) .set noat MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against sltu k1, k1, k0 # upper bound of kernel_segmap bnez k1, MipsKernGenException # out of bound lui k1, %hi(kernel_segmap) # k1=hi of segbase PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base beq k1, zero, MipsKernGenException # ==0 -- no seg tab andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 # k1=seg entry address PTR_L k1, 0(k1) # k1=seg entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, MipsKernGenException # ==0 -- no page table #ifdef __mips_n64 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, MipsKernGenException # ==0 -- no page table #endif PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN andi k0, k0, PTE2MASK # k0=page tab offset PTR_ADDU k1, k1, k0 # k1=pte address PTE_L k0, 0(k1) # k0=lo0 pte PTE_L k1, PTESIZE(k1) # k1=lo1 pte CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded COP0_SYNC tlbwr # write to tlb HAZARD_DELAY eret # return from exception .set at END(MipsTLBMissException) /*---------------------------------------------------------------------------- * * MipsFPTrap -- * * Handle a floating point Trap. * * MipsFPTrap(statusReg, causeReg, pc) * unsigned statusReg; * unsigned causeReg; * unsigned pc; * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED(MipsFPTrap, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ mfc0 t0, MIPS_COP_0_STATUS REG_S ra, CALLFRAME_RA(sp) .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) or t1, t0, MIPS_SR_COP_1_BIT mtc0 t1, MIPS_COP_0_STATUS ITLBNOPFIX cfc1 t1, MIPS_FPU_CSR # stall til FP done cfc1 t1, MIPS_FPU_CSR # now get status nop sll t2, t1, (31 - 17) # unimplemented operation? bgez t2, 3f # no, normal trap nop /* * We got an unimplemented operation trap so * fetch the instruction, compute the next PC and emulate the instruction. */ bgez a1, 1f # Check the branch delay bit. nop /* * The instruction is in the branch delay slot so the branch will have to * be emulated to get the resulting PC. */ PTR_S a2, CALLFRAME_SIZ + 8(sp) GET_CPU_PCPU(a0) #mips64 unsafe? PTR_L a0, PC_CURPCB(a0) PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers move a1, a2 # second arg is instruction PC move a2, t1 # third arg is floating point CSR PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch jalr t3 # compute PC after branch move a3, zero # fourth arg is FALSE /* * Now load the floating-point instruction in the branch delay slot * to be emulated. */ PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc b 2f lw a0, 4(a2) # a0 = coproc instruction /* * This is not in the branch delay slot so calculate the resulting * PC (epc + 4) into v0 and continue to MipsEmulateFP(). */ 1: lw a0, 0(a2) # a0 = coproc instruction #xxx mips64 unsafe? PTR_ADDU v0, a2, 4 # v0 = next pc 2: GET_CPU_PCPU(t2) PTR_L t2, PC_CURPCB(t2) SAVE_U_PCB_REG(v0, PC, t2) # save new pc /* * Check to see if the instruction to be emulated is a floating-point * instruction. */ srl a3, a0, MIPS_OPCODE_SHIFT beq a3, MIPS_OPCODE_C1, 4f # this should never fail nop /* * Send a floating point exception signal to the current process. */ 3: GET_CPU_PCPU(a0) PTR_L a0, PC_CURTHREAD(a0) # get current thread cfc1 a2, MIPS_FPU_CSR # code = FP execptions ctc1 zero, MIPS_FPU_CSR # Clear exceptions PTR_LA t3, _C_LABEL(trapsignal) jalr t3 li a1, SIGFPE b FPReturn nop /* * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. */ 4: PTR_LA t3, _C_LABEL(MipsEmulateFP) jalr t3 nop /* * Turn off the floating point coprocessor and return. */ FPReturn: mfc0 t0, MIPS_COP_0_STATUS PTR_L ra, CALLFRAME_RA(sp) and t0, t0, ~MIPS_SR_COP_1_BIT mtc0 t0, MIPS_COP_0_STATUS ITLBNOPFIX j ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(MipsFPTrap) #ifndef MIPS_INTRNG /* * Interrupt counters for vmstat. */ .data .globl intrcnt .globl sintrcnt .globl intrnames .globl sintrnames intrnames: .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 sintrnames: #ifdef __mips_n64 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 #else .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 #endif .align (_MIPS_SZLONG / 8) intrcnt: .space INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 sintrcnt: #ifdef __mips_n64 .quad INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 #else .int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 #endif #endif /* MIPS_INTRNG */ /* * Vector to real handler in KSEG1. */ .text VECTOR(MipsCache, unknown) PTR_LA k0, _C_LABEL(MipsCacheException) li k1, MIPS_KSEG0_PHYS_MASK and k0, k1 PTR_LI k1, MIPS_KSEG1_START or k0, k1 j k0 nop VECTOR_END(MipsCache) .set at /* * Panic on cache errors. A lot more could be done to recover * from some types of errors but it is tricky. */ NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) .set noat .mask 0x80000000, -4 PTR_LA k0, _C_LABEL(panic) # return to panic PTR_LA a0, 9f # panicstr MFC0 a1, MIPS_COP_0_ERROR_PC mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error MTC0 k0, MIPS_COP_0_ERROR_PC # set return address mfc0 k0, MIPS_COP_0_STATUS # restore status li k1, MIPS_SR_DIAG_PE # ignore further errors or k0, k1 mtc0 k0, MIPS_COP_0_STATUS # restore status COP0_SYNC eret MSG("cache error @ EPC 0x%x CachErr 0x%x"); .set at END(MipsCacheException) Index: projects/mips64-clang/sys/mips/mips/fp.S =================================================================== --- projects/mips64-clang/sys/mips/mips/fp.S (revision 295726) +++ projects/mips64-clang/sys/mips/mips/fp.S (revision 295727) @@ -1,3610 +1,3610 @@ /* $OpenBSD: fp.S,v 1.2 1998/03/16 09:03:31 pefo Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: @(#)fp.s 8.1 (Berkeley) 6/10/93 * JNPR: fp.S,v 1.1 2006/08/07 05:38:57 katta * $FreeBSD$ */ /* * Standard header stuff. */ #include #include #include #include "assym.s" #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 .set hardfloat /*---------------------------------------------------------------------------- * * MipsEmulateFP -- * * Emulate unimplemented floating point operations. * This routine should only be called by MipsFPInterrupt(). * * MipsEmulateFP(instr) * unsigned instr; * * Results: * None. * * Side effects: * Floating point registers are modified according to instruction. * *---------------------------------------------------------------------------- */ NESTED(MipsEmulateFP, CALLFRAME_SIZ, ra) subu sp, sp, CALLFRAME_SIZ sw ra, CALLFRAME_RA(sp) /* * Decode the FMT field (bits 24-21) and FUNCTION field (bits 5-0). */ srl v0, a0, 21 - 2 # get FMT field and v0, v0, 0xF << 2 # mask FMT field and v1, a0, 0x3F # mask FUNC field sll v1, v1, 5 # align for table lookup bgt v0, 4 << 2, ill # illegal format or v1, v1, v0 cfc1 a1, MIPS_FPU_CSR # get exception register lw a3, func_fmt_tbl(v1) # switch on FUNC & FMT and a1, a1, ~MIPS_FPU_EXCEPTION_UNIMPL # clear exception ctc1 a1, MIPS_FPU_CSR j a3 - .rdata + .section .rdata func_fmt_tbl: .word add_s # 0 .word add_d # 0 .word ill # 0 .word ill # 0 .word ill # 0 .word ill # 0 .word ill # 0 .word ill # 0 .word sub_s # 1 .word sub_d # 1 .word ill # 1 .word ill # 1 .word ill # 1 .word ill # 1 .word ill # 1 .word ill # 1 .word mul_s # 2 .word mul_d # 2 .word ill # 2 .word ill # 2 .word ill # 2 .word ill # 2 .word ill # 2 .word ill # 2 .word div_s # 3 .word div_d # 3 .word ill # 3 .word ill # 3 .word ill # 3 .word ill # 3 .word ill # 3 .word ill # 3 .word ill # 4 .word ill # 4 .word ill # 4 .word ill # 4 .word ill # 4 .word ill # 4 .word ill # 4 .word ill # 4 .word abs_s # 5 .word abs_d # 5 .word ill # 5 .word ill # 5 .word ill # 5 .word ill # 5 .word ill # 5 .word ill # 5 .word mov_s # 6 .word mov_d # 6 .word ill # 6 .word ill # 6 .word ill # 6 .word ill # 6 .word ill # 6 .word ill # 6 .word neg_s # 7 .word neg_d # 7 .word ill # 7 .word ill # 7 .word ill # 7 .word ill # 7 .word ill # 7 .word ill # 7 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 8 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 9 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 10 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 11 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 12 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 13 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 14 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 15 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 16 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 17 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 18 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 19 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 20 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 21 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 22 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 23 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 24 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 25 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 26 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 27 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 28 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 29 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 30 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 31 .word ill # 32 .word cvt_s_d # 32 .word ill # 32 .word ill # 32 .word cvt_s_w # 32 .word ill # 32 .word ill # 32 .word ill # 32 .word cvt_d_s # 33 .word ill # 33 .word ill # 33 .word ill # 33 .word cvt_d_w # 33 .word ill # 33 .word ill # 33 .word ill # 33 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 34 .word ill # 35 .word ill # 35 .word ill # 35 .word ill # 35 .word ill # 35 .word ill # 35 .word ill # 35 .word ill # 35 .word cvt_w_s # 36 .word cvt_w_d # 36 .word ill # 36 .word ill # 36 .word ill # 36 .word ill # 36 .word ill # 36 .word ill # 36 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 37 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 38 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 39 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 40 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 41 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 42 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 43 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 44 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 45 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 46 .word ill # 47 .word ill # 47 .word ill # 47 .word ill # 47 .word ill # 47 .word ill # 47 .word ill # 47 .word ill # 47 .word cmp_s # 48 .word cmp_d # 48 .word ill # 48 .word ill # 48 .word ill # 48 .word ill # 48 .word ill # 48 .word ill # 48 .word cmp_s # 49 .word cmp_d # 49 .word ill # 49 .word ill # 49 .word ill # 49 .word ill # 49 .word ill # 49 .word ill # 49 .word cmp_s # 50 .word cmp_d # 50 .word ill # 50 .word ill # 50 .word ill # 50 .word ill # 50 .word ill # 50 .word ill # 50 .word cmp_s # 51 .word cmp_d # 51 .word ill # 51 .word ill # 51 .word ill # 51 .word ill # 51 .word ill # 51 .word ill # 51 .word cmp_s # 52 .word cmp_d # 52 .word ill # 52 .word ill # 52 .word ill # 52 .word ill # 52 .word ill # 52 .word ill # 52 .word cmp_s # 53 .word cmp_d # 53 .word ill # 53 .word ill # 53 .word ill # 53 .word ill # 53 .word ill # 53 .word ill # 53 .word cmp_s # 54 .word cmp_d # 54 .word ill # 54 .word ill # 54 .word ill # 54 .word ill # 54 .word ill # 54 .word ill # 54 .word cmp_s # 55 .word cmp_d # 55 .word ill # 55 .word ill # 55 .word ill # 55 .word ill # 55 .word ill # 55 .word ill # 55 .word cmp_s # 56 .word cmp_d # 56 .word ill # 56 .word ill # 56 .word ill # 56 .word ill # 56 .word ill # 56 .word ill # 56 .word cmp_s # 57 .word cmp_d # 57 .word ill # 57 .word ill # 57 .word ill # 57 .word ill # 57 .word ill # 57 .word ill # 57 .word cmp_s # 58 .word cmp_d # 58 .word ill # 58 .word ill # 58 .word ill # 58 .word ill # 58 .word ill # 58 .word ill # 58 .word cmp_s # 59 .word cmp_d # 59 .word ill # 59 .word ill # 59 .word ill # 59 .word ill # 59 .word ill # 59 .word ill # 59 .word cmp_s # 60 .word cmp_d # 60 .word ill # 60 .word ill # 60 .word ill # 60 .word ill # 60 .word ill # 60 .word ill # 60 .word cmp_s # 61 .word cmp_d # 61 .word ill # 61 .word ill # 61 .word ill # 61 .word ill # 61 .word ill # 61 .word ill # 61 .word cmp_s # 62 .word cmp_d # 62 .word ill # 62 .word ill # 62 .word ill # 62 .word ill # 62 .word ill # 62 .word ill # 62 .word cmp_s # 63 .word cmp_d # 63 .word ill # 63 .word ill # 63 .word ill # 63 .word ill # 63 .word ill # 63 .word ill # 63 .text /* * Single precision subtract. */ sub_s: jal get_ft_fs_s xor ta0, ta0, 1 # negate FT sign bit b add_sub_s /* * Single precision add. */ add_s: jal get_ft_fs_s add_sub_s: bne t1, SEXP_INF, 1f # is FS an infinity? bne ta1, SEXP_INF, result_fs_s # if FT is not inf, result=FS bne t2, zero, result_fs_s # if FS is NAN, result is FS bne ta2, zero, result_ft_s # if FT is NAN, result is FT bne t0, ta0, invalid_s # both infinities same sign? b result_fs_s # result is in FS 1: beq ta1, SEXP_INF, result_ft_s # if FT is inf, result=FT bne t1, zero, 4f # is FS a denormalized num? beq t2, zero, 3f # is FS zero? bne ta1, zero, 2f # is FT a denormalized num? beq ta2, zero, result_fs_s # FT is zero, result=FS jal renorm_fs_s jal renorm_ft_s b 5f 2: jal renorm_fs_s subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit b 5f 3: bne ta1, zero, result_ft_s # if FT != 0, result=FT bne ta2, zero, result_ft_s and v0, a1, 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 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, a1, 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 get_ft_fs_d xor ta0, ta0, 1 # negate sign bit b add_sub_d /* * Double precision add. */ add_d: jal get_ft_fs_d add_sub_d: bne t1, DEXP_INF, 1f # is FS an infinity? bne ta1, DEXP_INF, result_fs_d # if FT is not inf, result=FS bne t2, zero, result_fs_d # if FS is NAN, result is FS bne 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 renorm_fs_d jal renorm_ft_d b 5f 2: jal renorm_fs_d subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit b 5f 3: bne ta1, zero, result_ft_d # if FT != 0, result=FT bne ta2, zero, result_ft_d bne ta3, zero, result_ft_d and v0, a1, 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 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, a1, 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 get_ft_fs_s xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, SEXP_INF, 2f # is FS an infinity? bne t2, zero, result_fs_s # if FS is a NAN, result=FS bne ta1, SEXP_INF, 1f # FS is inf, is FT an infinity? bne ta2, zero, result_ft_s # if FT is a NAN, result=FT b result_fs_s # result is infinity 1: bne ta1, zero, result_fs_s # inf * zero? if no, result=FS bne ta2, zero, result_fs_s b invalid_s # infinity * zero is invalid 2: bne ta1, SEXP_INF, 1f # FS != inf, is FT an infinity? bne t1, zero, result_ft_s # zero * inf? if no, result=FT bne t2, zero, result_ft_s bne ta2, zero, result_ft_s # if FT is a NAN, result=FT b invalid_s # zero * infinity is invalid 1: bne t1, zero, 1f # is FS zero? beq t2, zero, result_fs_s # result is zero jal renorm_fs_s b 2f 1: subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit 2: bne ta1, zero, 1f # is FT zero? beq ta2, zero, result_ft_s # result is zero jal renorm_ft_s b 2f 1: subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit 2: addu t1, t1, ta1 # compute result exponent addu t1, t1, 9 # account for binary point multu t2, ta2 # multiply fractions mflo t8 mfhi t2 b norm_s /* * Double precision multiply. */ mul_d: jal get_ft_fs_d xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, DEXP_INF, 2f # is FS an infinity? bne t2, zero, result_fs_d # if FS is a NAN, result=FS bne 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 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 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 get_ft_fs_s xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, result_fs_s # if FS is NAN, result is FS bne ta1, SEXP_INF, result_fs_s # is FT an infinity? bne ta2, zero, result_ft_s # if FT is NAN, result is FT b invalid_s # infinity/infinity is invalid 1: bne ta1, SEXP_INF, 1f # is FT an infinity? bne ta2, zero, result_ft_s # if FT is NAN, result is FT move t1, zero # x / infinity is zero move t2, zero b result_fs_s 1: bne t1, zero, 2f # is FS zero? bne t2, zero, 1f bne ta1, zero, result_fs_s # FS=zero, is FT zero? beq ta2, zero, invalid_s # 0 / 0 b result_fs_s # result = zero 1: jal renorm_fs_s b 3f 2: subu t1, t1, SEXP_BIAS # unbias FS exponent or t2, t2, SIMPL_ONE # set implied one bit 3: bne ta1, zero, 2f # is FT zero? bne ta2, zero, 1f or a1, a1, MIPS_FPU_EXCEPTION_DIV0 | MIPS_FPU_STICKY_DIV0 and v0, a1, MIPS_FPU_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions li t1, SEXP_INF # result is infinity move t2, zero b result_fs_s 1: jal renorm_ft_s b 3f 2: subu ta1, ta1, SEXP_BIAS # unbias FT exponent or ta2, ta2, SIMPL_ONE # set implied one bit 3: subu t1, t1, ta1 # compute exponent subu t1, t1, 3 # compensate for result position li v0, SFRAC_BITS+3 # number of bits to divide move t8, t2 # init dividend move t2, zero # init result 1: bltu t8, ta2, 3f # is dividend >= divisor? 2: subu t8, t8, ta2 # subtract divisor from dividend or t2, t2, 1 # remember that we did bne t8, zero, 3f # if not done, continue sll t2, t2, v0 # shift result to final position b norm_s 3: sll t8, t8, 1 # shift dividend sll t2, t2, 1 # shift result subu v0, v0, 1 # are we done? bne v0, zero, 1b # no, continue b norm_s /* * Double precision divide. */ div_d: jal get_ft_fs_d xor t0, t0, ta0 # compute sign of result move ta0, t0 bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, result_fs_d # if FS is NAN, result is FS bne 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 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 a1, a1, MIPS_FPU_EXCEPTION_DIV0 | MIPS_FPU_STICKY_DIV0 and v0, a1, MIPS_FPU_ENABLE_DIV0 # trap enabled? bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # Save exceptions li t1, DEXP_INF # result is infinity move t2, zero move t3, zero b result_fs_d 1: jal renorm_ft_d b 3f 2: subu ta1, ta1, DEXP_BIAS # unbias FT exponent or ta2, ta2, DIMPL_ONE # set implied one bit 3: subu t1, t1, ta1 # compute exponent subu t1, t1, 3 # compensate for result position li v0, DFRAC_BITS+3 # number of bits to divide move t8, t2 # init dividend move 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 /* * Single precision absolute value. */ abs_s: jal get_fs_s move t0, zero # set sign positive b result_fs_s /* * Double precision absolute value. */ abs_d: jal get_fs_d move t0, zero # set sign positive b result_fs_d /* * Single precision move. */ mov_s: jal get_fs_s b result_fs_s /* * Double precision move. */ mov_d: jal get_fs_d b result_fs_d /* * Single precision negate. */ neg_s: jal get_fs_s xor t0, t0, 1 # reverse sign b result_fs_s /* * Double precision negate. */ neg_d: jal get_fs_d xor t0, t0, 1 # reverse sign b result_fs_d /* * Convert double to single. */ cvt_s_d: jal get_fs_d bne t1, DEXP_INF, 1f # is FS an infinity? li t1, SEXP_INF # convert to single 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 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 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 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 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 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: jal get_fs_s bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, invalid_w # invalid conversion 1: bne t1, zero, 1f # is FS zero? beq t2, zero, result_fs_w # result is zero move t2, zero # result is an inexact zero b inexact_w 1: subu t1, t1, SEXP_BIAS # unbias exponent or t2, t2, SIMPL_ONE # add implied one bit sll t3, t2, 32 - 3 # convert S fraction to D srl t2, t2, 3 b cvt_w /* * Convert double to integer. */ cvt_w_d: jal 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: blt t1, WEXP_MIN, underflow_w # is exponent too small? li v0, WEXP_MAX+1 bgt t1, v0, overflow_w # is exponent too large? bne t1, v0, 1f # special check for INT_MIN beq t0, zero, overflow_w # if positive, overflow bne t2, DIMPL_ONE, overflow_w 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, a1, 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 a1, a1, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions b result_fs_w /* * Conversions to integer which overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an invalid exception. */ overflow_w: or a1, a1, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a1, MIPS_FPU_ENABLE_OVERFLOW bne v0, zero, fpe_trap and v0, a1, 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 a1, a1, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW and v0, a1, MIPS_FPU_ENABLE_UNDERFLOW bne v0, zero, fpe_trap and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, inexact_w # inexact traps enabled? b invalid_w /* * Compare single. */ cmp_s: jal get_cmp_s bne t1, SEXP_INF, 1f # is FS an infinity? bne t2, zero, unordered # FS is a NAN 1: bne ta1, SEXP_INF, 2f # is FT an infinity? bne ta2, zero, unordered # FT is a NAN 2: sll t1, t1, 23 # reassemble exp & frac or t1, t1, t2 sll ta1, ta1, 23 # reassemble exp & frac or ta1, ta1, ta2 beq t0, zero, 1f # is FS positive? negu t1 1: beq ta0, zero, 1f # is FT positive? negu ta1 1: li v0, COND_LESS blt t1, ta1, test_cond # is FS < FT? li v0, COND_EQUAL beq t1, ta1, test_cond # is FS == FT? move v0, zero # FS > FT b test_cond /* * Compare double. */ cmp_d: jal get_cmp_d bne t1, DEXP_INF, 1f # is FS an infinity? bne t2, zero, unordered 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 a1, a1, ~MIPS_FPU_COND_BIT # clear condition bit b 2f 1: or a1, a1, MIPS_FPU_COND_BIT # set condition bit 2: ctc1 a1, MIPS_FPU_CSR # save condition bit b done unordered: and v0, a0, COND_UNORDERED # this cmp match unordered? bne v0, zero, 1f and a1, a1, ~MIPS_FPU_COND_BIT # clear condition bit b 2f 1: or a1, a1, MIPS_FPU_COND_BIT # set condition bit 2: and v0, a0, COND_SIGNAL beq v0, zero, 1f # is this a signaling cmp? or a1, a1, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a1, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap 1: ctc1 a1, MIPS_FPU_CSR # save condition bit b done /* * Determine the amount to shift the fraction in order to restore the * normalized position. After that, round and handle exceptions. */ norm_s: move v0, t2 move t9, zero # t9 = num of leading zeros bne t2, zero, 1f move v0, t8 addu t9, 32 1: srl v1, v0, 16 bne v1, zero, 1f addu t9, 16 sll v0, 16 1: srl v1, v0, 24 bne v1, zero, 1f addu t9, 8 sll v0, 8 1: srl v1, v0, 28 bne v1, zero, 1f addu t9, 4 sll v0, 4 1: srl v1, v0, 30 bne v1, zero, 1f addu t9, 2 sll v0, 2 1: srl v1, v0, 31 bne v1, zero, 1f addu t9, 1 /* * Now shift t2,t8 the correct number of bits. */ 1: subu t9, t9, SLEAD_ZEROS # dont count leading zeros subu t1, t1, t9 # adjust the exponent beq t9, zero, norm_noshift_s li v1, 32 blt t9, zero, 1f # if shift < 0, shift right subu v1, v1, t9 sll t2, t2, t9 # shift t2,t8 left srl v0, t8, v1 # save bits shifted out or t2, t2, v0 sll t8, t8, t9 b norm_noshift_s 1: negu t9 # shift t2,t8 right by t9 subu v1, v1, t9 sll v0, t8, v1 # save bits shifted out sltu v0, zero, v0 # be sure to save any one bits srl t8, t8, t9 or t8, t8, v0 sll v0, t2, v1 # save bits shifted out or t8, t8, v0 srl t2, t2, t9 norm_noshift_s: move ta1, t1 # save unrounded exponent move ta2, t2 # save unrounded fraction and v0, a1, 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 set_fd_s # save result or a1, a1, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_s: or a1, a1, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a1, MIPS_FPU_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 192 # bias exponent and t2, t2, ~SIMPL_ONE # clear implied one bit jal set_fd_s # save result b fpe_trap 1: and v0, a1, 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, a1, 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 set_fd_s # save result or a1, a1, 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 a1, a1, 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, a1, 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, a1, 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 set_fd_s # save result beq t8, zero, done # check for exact result or a1, a1, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW or a1, a1, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions b done /* * Determine the amount to shift the fraction in order to restore the * normalized position. After that, round and handle exceptions. */ norm_d: move v0, t2 move t9, zero # t9 = num of leading zeros 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, a1, 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 set_fd_d # save result or a1, a1, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions b done /* * Overflow will trap (if enabled), * or generate an inexact trap (if enabled), * or generate an infinity. */ overflow_d: or a1, a1, MIPS_FPU_EXCEPTION_OVERFLOW | MIPS_FPU_STICKY_OVERFLOW and v0, a1, MIPS_FPU_ENABLE_OVERFLOW beq v0, zero, 1f subu t1, t1, 1536 # bias exponent and t2, t2, ~DIMPL_ONE # clear implied one bit jal set_fd_d # save result b fpe_trap 1: and v0, a1, 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, a1, 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 set_fd_d # save result or a1, a1, 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 a1, a1, 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, a1, 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, a1, 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 set_fd_d # save result beq t8, zero, done # check for exact result or a1, a1, MIPS_FPU_EXCEPTION_UNDERFLOW | MIPS_FPU_STICKY_UNDERFLOW or a1, a1, MIPS_FPU_EXCEPTION_INEXACT | MIPS_FPU_STICKY_INEXACT and v0, a1, MIPS_FPU_ENABLE_INEXACT bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is a quiet NAN. */ invalid_s: # trap invalid operation or a1, a1, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a1, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions move t0, zero # result is a quiet NAN li t1, SEXP_INF li t2, SQUIET_NAN jal set_fd_s # save result (in t0,t1,t2) b done /* * Signal an invalid operation if the trap is enabled; otherwise, * the result is a quiet NAN. */ invalid_d: # trap invalid operation or a1, a1, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a1, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions move t0, zero # result is a quiet NAN li t1, DEXP_INF li t2, DQUIET_NAN0 li t3, DQUIET_NAN1 jal 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 a1, a1, MIPS_FPU_EXCEPTION_INVALID | MIPS_FPU_STICKY_INVALID and v0, a1, MIPS_FPU_ENABLE_INVALID bne v0, zero, fpe_trap ctc1 a1, MIPS_FPU_CSR # save exceptions bne t0, zero, 1f li t2, INT_MAX # result is INT_MAX b result_fs_w 1: li t2, INT_MIN # result is INT_MIN b result_fs_w /* * Trap if the hardware should have handled this case. */ fpe_trap: move a2, a1 # code = FP CSR ctc1 a1, MIPS_FPU_CSR # save exceptions break 0 /* * Send an illegal instruction signal to the current process. */ ill: ctc1 a1, MIPS_FPU_CSR # save exceptions move a2, a0 # code = FP instruction break 0 result_ft_s: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 result_fs_s: # result is FS jal set_fd_s # save result (in t0,t1,t2) b done result_fs_w: jal set_fd_word # save result (in t2) b done result_ft_d: move t0, ta0 # result is FT move t1, ta1 move t2, ta2 move t3, ta3 result_fs_d: # result is FS jal set_fd_d # save result (in t0,t1,t2,t3) done: lw ra, CALLFRAME_RA(sp) addu sp, sp, CALLFRAME_SIZ j ra END(MipsEmulateFP) /*---------------------------------------------------------------------------- * get_fs_int -- * * Read (integer) the FS register (bits 15-11). * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t2 contains the fraction * *---------------------------------------------------------------------------- */ LEAF(get_fs_int) 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 + .section .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 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 MipsEmulateFP only. * * Results: * t0 contains the FS sign * t1 contains the FS (biased) exponent * t2 contains the FS fraction * ta0 contains the FT sign * ta1 contains the FT (biased) exponent * ta2 contains the FT fraction * *---------------------------------------------------------------------------- */ LEAF(get_ft_fs_s) 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 + .section .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 */ /*---------------------------------------------------------------------------- * get_fs_s -- * * Read (single precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * *---------------------------------------------------------------------------- */ XLEAF(get_fs_s) 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 + .section .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 END(get_ft_fs_s) /*---------------------------------------------------------------------------- * get_ft_fs_d -- * * Read (double precision) the FT register (bits 20-16) and * the FS register (bits 15-11) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the FS sign * t1 contains the FS (biased) exponent * t2 contains the FS fraction * 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 * *---------------------------------------------------------------------------- */ LEAF(get_ft_fs_d) 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 + .section .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 */ /*---------------------------------------------------------------------------- * get_fs_d -- * * Read (double precision) the FS register (bits 15-11) and * break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * *---------------------------------------------------------------------------- */ XLEAF(get_fs_d) 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 + .section .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 END(get_ft_fs_d) /*---------------------------------------------------------------------------- * get_cmp_s -- * * Read (single precision) the FS register (bits 15-11) and * the FT register (bits 20-16) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * ta0 contains the sign * ta1 contains the (biased) exponent * ta2 contains the fraction * *---------------------------------------------------------------------------- */ LEAF(get_cmp_s) 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 + .section .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 + .section .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 END(get_cmp_s) /*---------------------------------------------------------------------------- * get_cmp_d -- * * Read (double precision) the FS register (bits 15-11) and * the FT register (bits 20-16) and break up into fields. * This is an internal routine used by MipsEmulateFP only. * * Results: * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * ta0 contains the sign * ta1 contains the (biased) exponent * ta2 contains the fraction * ta3 contains the remaining fraction * *---------------------------------------------------------------------------- */ LEAF(get_cmp_d) 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 + .section .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 + .section .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 END(get_cmp_d) /*---------------------------------------------------------------------------- * set_fd_s -- * * Write (single precision) the FD register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * * set_fd_word -- * * Write (integer) the FD register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t2 contains the integer * *---------------------------------------------------------------------------- */ LEAF(set_fd_s) sll t0, t0, 31 # position sign sll t1, t1, 23 # position exponent or t2, t2, t0 or t2, t2, t1 XLEAF(set_fd_word) 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 + .section .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 END(set_fd_s) /*---------------------------------------------------------------------------- * set_fd_d -- * * Write (double precision) the FT register (bits 10-6). * This is an internal routine used by MipsEmulateFP only. * * Arguments: * a0 contains the FP instruction * t0 contains the sign * t1 contains the (biased) exponent * t2 contains the fraction * t3 contains the remaining fraction * *---------------------------------------------------------------------------- */ LEAF(set_fd_d) 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 + .section .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 END(set_fd_d) /*---------------------------------------------------------------------------- * renorm_fs_s -- * * Results: * t1 unbiased exponent * t2 normalized fraction * *---------------------------------------------------------------------------- */ 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 * *---------------------------------------------------------------------------- */ 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 * *---------------------------------------------------------------------------- */ 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 * *---------------------------------------------------------------------------- */ 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) Index: projects/mips64-clang/sys/mips/mips/locore.S =================================================================== --- projects/mips64-clang/sys/mips/mips/locore.S (revision 295726) +++ projects/mips64-clang/sys/mips/mips/locore.S (revision 295727) @@ -1,187 +1,187 @@ /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Digital Equipment Corporation and 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) * * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 * JNPR: locore.S,v 1.6.2.1 2007/08/29 12:24:49 girish * $FreeBSD$ */ /* * FREEBSD_DEVELOPERS_FIXME * The start routine below was written for a multi-core CPU * with each core being hyperthreaded. This serves as an example * for a complex CPU architecture. For a different CPU complex * please make necessary changes to read CPU-ID etc. * A clean solution would be to have a different locore file for * each CPU type. */ /* * Contains code that is the first executed at boot time plus * assembly language support routines. */ #include #include #include #include #include "assym.s" .data #ifdef YAMON GLOBAL(fenvp) .space 4 # Assumes mips32? Is that OK? #endif .set noreorder .text GLOBAL(btext) ASM_ENTRY(_start) VECTOR(_locore, unknown) /* UNSAFE TO USE a0..a3, need to preserve the args from boot loader */ mtc0 zero, MIPS_COP_0_CAUSE # Clear soft interrupts #if defined(CPU_CNMIPS) /* * t1: Bits to set explicitly: * Enable FPU */ /* Set these bits */ li t1, (MIPS_SR_COP_0_BIT | MIPS_SR_PX | MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_SX | MIPS_SR_BEV) /* Reset these bits */ li t0, ~(MIPS_SR_DE | MIPS_SR_SR | MIPS_SR_ERL | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_COP_2_BIT) #elif defined (CPU_RMI) || defined (CPU_NLM) /* Set these bits */ li t1, (MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT | MIPS_SR_KX | MIPS_SR_UX) /* Reset these bits */ li t0, ~(MIPS_SR_BEV | MIPS_SR_SR | MIPS_SR_INT_IE) #else /* * t0: Bits to preserve if set: * Soft reset * Boot exception vectors (firmware-provided) */ li t0, (MIPS_SR_BEV | MIPS_SR_SR) /* * t1: Bits to set explicitly: * Enable FPU */ li t1, MIPS_SR_COP_1_BIT #ifdef __mips_n64 or t1, MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX #endif #endif /* * Read coprocessor 0 status register, clear bits not * preserved (namely, clearing interrupt bits), and set * bits we want to explicitly set. */ mfc0 t2, MIPS_COP_0_STATUS and t2, t0 or t2, t1 mtc0 t2, MIPS_COP_0_STATUS COP0_SYNC /* Make sure KSEG0 is cached */ li t0, MIPS_CCA_CACHED mtc0 t0, MIPS_COP_0_CONFIG COP0_SYNC /*xxximp * now that we pass a0...a3 to the platform_init routine, do we need * to stash this stuff here? */ #ifdef YAMON /* Save YAMON boot environment pointer */ sw a2, _C_LABEL(fenvp) #endif #if defined(CPU_CNMIPS) && defined(SMP) .set push .set mips32r2 rdhwr t2, $0 beqz t2, 1f nop j octeon_ap_wait nop .set pop 1: #endif /* * Initialize stack and call machine startup. */ PTR_LA sp, _C_LABEL(pcpu_space) PTR_ADDU sp, (PAGE_SIZE * 2) - CALLFRAME_SIZ REG_S zero, CALLFRAME_RA(sp) # Zero out old ra for debugger REG_S zero, CALLFRAME_SP(sp) # Zero out old fp for debugger PTR_LA gp, _C_LABEL(_gp) /* Call the platform-specific startup code. */ jal _C_LABEL(platform_start) nop PTR_LA sp, _C_LABEL(thread0) PTR_L a0, TD_PCB(sp) REG_LI t0, ~7 and a0, a0, t0 PTR_SUBU sp, a0, CALLFRAME_SIZ jal _C_LABEL(mi_startup) # mi_startup(frame) - sw zero, CALLFRAME_SIZ - 8(sp) # Zero out old fp for debugger + sw zero, ((CALLFRAME_SIZ) - 8)(sp) # Zero out old fp for debugger PANIC("Startup failed!") VECTOR_END(_locore)