;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Microsoft Research Singularity ;;; ;;; Copyright (c) Microsoft Corporation. All rights reserved. ;;; ;;; This file contains ARM-specific assembly code. ;;; ; except.s ; ; Copyright (C) Advanced RISC Machines Limited, 1994. All rights reserved. ; ; RCS Revision: 1 ; Checkin Date: 2007/06/29 02:59:16 ; Revising Author ;============================================================================== ;Error generation - from ANSI library GET fpe.asm GET h_errors.asm [ :DEF: liberror_s AREA |.text|, CODE, READONLY Export_32 __fp_edom Export_32 __fp_erange ; __fp_edom(ulong sign_bit, boolean huge_val); ; __fp_erange(ulong sign_bit, boolean huge_val); ; ; set errno to EDOM/ERANGE and return sign_bit | (huge_val ? HUGE_VAL : 0) __fp_edom EnterWithLR MOV a3, #EDOM B skip __fp_erange EnterWithLR MOV a3, #ERANGE skip AND a4, a1, #Sign_bit [ :DEF:EMBEDDED_CLIB IMPORT __rt_errno_addr LDR a1, =__rt_errno_addr CMP a1, #0 BEQ %FT1 STMDB sp!, {a2-a4, lr} BL __rt_errno_addr LDMIA sp!, {a2-a4, lr} STR a3, [a1] 1 | LDR a1, errno STR a3, [a1] ] TEQ a2, #0 MOVEQ a1, #0 ; generate +/- 0.0 in a1/a2 LDRNE a1, huge_val LDMNEIA a1, {a1, a2} ; load HUGE_VAL into a1/a2 ORR a1, a1, a4 ; add in sign bit ReturnToLR [ :LNOT::DEF:EMBEDDED_CLIB errno IMPORT __errno DCD __errno ] huge_val IMPORT __huge_val DCD __huge_val ] ;============================================================================== ;Setting/returning status flags. [ :DEF: status_s AREA |.text|, CODE, READONLY EXPORT __fp_status ; extern unsigned int __fp_status(unsigned int mask,unsigned int flags) __fp_status [ :DEF: thumb CODE16 ; mask "mask" to an acceptable value MOV a4,#&e0 LSL a3,a1,#32-FPExceptE_pos-Except_len LSR a3,a3,#32-FPExceptE_pos-Except_len BIC a3,a4 LSR a4,#8 BIC a3,a4 AND a4,a1 ORR a3,a1 AND a2,a3 ; mask in a3, masked flags in a2 LDR a4,status_ptr LDR a1,[a4] ; **** *WARNING* is ip spare under the TPCS ????? **** MOV ip,a1 ; store value BIC a1,a3 EOR a1,a2 STR a1,[a4] MOV a1,ip ; restore value BX lr ALIGN | ; mask "mask" to an acceptable value MOV a3,a1,LSL #32-FPExceptE_pos-Except_len BIC a3,a3,#&e0:SHL:(32-FPExceptE_pos-Except_len) BIC a3,a3,#&e0:SHL:(32-FPExceptE_pos-Except_len+8) AND a2,a2,a3,LSR #32-FPExceptE_pos-Except_len ; mask in a3, masked flags in a2. LDR a4,status_ptr LDR a1,[a4] ; load old flags BIC a3,a1,a3,LSR #32-FPExceptE_pos-Except_len EOR a3,a3,a2 ; clear/set/toggle flags and STR a3,[a4] ; write back. IF Interworking :LOR: Thumbing BX lr ELSE MOV pc,lr ; return ENDIF ] status_ptr IMPORT __fp_status_flags DCD __fp_status_flags ] ;============================================================================== ;Error checking - from fplib code [ :DEF: fcheck_s AREA |.text|, CODE, READONLY [ :DEF: thumb CODE32 ] EXPORT __fp_fcheck_NaN2 EXPORT __fp_dcheck_NaN2 EXPORT __fp_return_NaN EXPORT __fp_return_Inf IMPORT __fp_exception ; Check fOP1 and fOP2 for signalling NaN, IP contains exception flags. __fp_fcheck_NaN2 MOV a4, #0x01000000 CMN a4, fOP1, LSL #1 BLS fcheck_opnd2_NaN fcheck_opnd1_NaN TST fOP1, #fSignalBit BEQ __fp_exception CMN a4, fOP2, LSL #1 BLS __fp_return_NaN fcheck_opnd2_NaN MOV fOP1, fOP2 TST fOP1, #fSignalBit BNE __fp_return_NaN ;; RDCFix: Do we really want to do this? ; BEQ __fp_return_NaN B __fp_exception ; Check dOP1 and dOP2 for signalling NaN, IP contains exception flags. __fp_dcheck_NaN2 STMFD sp!, {ip} MOV tmp, #0x00200000 CMN tmp, dOP1h, LSL #1 CMPEQ dOP1l, #0 BLS dcheck_opnd2_NaN dcheck_opnd1_NaN TST dOP1h, #dSignalBit LDMEQFD sp!, {ip} BEQ __fp_exception CMN tmp, dOP2h, LSL #1 CMPEQ dOP2l, #0 LDMLSFD sp!, {ip} BLS __fp_return_NaN dcheck_opnd2_NaN LDMFD sp!, {ip} MOV dOP1h, dOP2h MOV dOP1l, dOP2l TST dOP1h, #dSignalBit BNE __fp_return_NaN ;; RDCFix: Do we really want to do this? ; BEQ __fp_return_NaN B __fp_exception ; Return NaN in fOP / dOP, except for non-float returning functions. ; IP contains exception flags. __fp_return_NaN ; test for special cases ;; ;; RDCFix: Will need to fix this once new defines are in. May want to ;; do some performance enhancements to keep from needing to check ;; each _Fp* operation code. Maybe a jump table. Maybe forget ;; this garbage and make the core emulation routines pack up ;; their proper results instead of hacking them up here. ;; ; AND a4, ip, #Fn_mask ; CMP a4, #CompareFalseFn ; CMPNE a4, #FixZeroFn ; BEQ return_zero ; CMP a4, #CompareTrueFn ; BEQ return_one ; CMP a4, #CmpLessFn ; BEQ return_HI ; CMP a4, #CmpGreaterFn ; BEQ return_LO ; CMP a4, #CmpEqualFn ; BEQ return_NE ; CMP a4, #FixFn ; BEQ return_smaxint ; CMP a4, #FixuFn ; BEQ return_umaxint ReturnToLR return_HI MOV a1, #1 CMP a1, #0 ReturnToLR_flg return_LO MOV a1, #0 CMP a1, #1 ReturnToLR_flg return_NE MOVS a1, #1 ReturnToLR_flg return_one MOV a1, #1 ReturnToLR return_zero MOV a1, #0 MOV a2, #0 ReturnToLR return_smaxint MOV a3, a1 TST ip, #LongLong_bit MOVEQ a1, #0x7fffffff MOVNE a1, #0xffffffff MOVNE a2, #0x7fffffff TST a3, #Sign_bit MVNNE a1, a1 MVNNE a2, a2 ReturnToLR return_umaxint MOV a1, #0xffffffff MOV a2, #0xffffffff ReturnToLR __fp_return_Inf ; no special cases ReturnToLR ] ;============================================================================== ;Error generation - from fplib code [ :DEF: except_s AREA |.text|, CODE, READONLY ; SWI Names [ :DEF: thumb CODE32 ] EXPORT __fp_veneer_error EXPORT __fp_nonveneer_error EXPORT __fp_exception IMPORT __fp_return_NaN IMPORT __fp_return_Inf __fp_veneer_error ; a4 contains the exception flags __fp_nonveneer_error ; a4 contains the exception flags OBSOLETE MOV ip, a4 ; fallthrough ; fp_exception is called when an IEEE exception has occurred ; a1 contains the sign of the NaN to be returned if the exception is disabled ; ip contains the exception flags (see fpe.s for a list) __fp_exception IMPORT FPE_Raise STMDB sp!,{lr} TST ip,#OVF_bit BNE overflow TST ip,#UNF_bit BNE underflow TST ip,#DVZ_bit BNE divide_by_zero TST ip,#INX_bit BNE divide_by_zero invalid_operation BL return_NaN B callraise overflow BL return_Inf B callraise underflow MOV a1, #0 MOV a2, #0 B callraise inexact B callraise divide_by_zero BL return_Inf callraise IF Interworking :LOR: Thumbing LDMIA sp!, {lr} BX lr ELSE LDMIA sp!, {pc} ENDIF ;GenerateError ; IMPORT RaiseException ; [ :DEF:EMBEDDED_CLIB ; STMDB sp!, {r0-r15} ; SUB lr, lr, #4 ; STR lr, [sp, #15*4] ; MOV r1, sp ; | ; LDR r1,ErrBlock ; SUB lr,lr,#4 ; STR lr,[r1,#15*4] ; MOV lr,#&de00 ; ORR lr,lr,#&00ad ; ORR lr,lr,lr,LSL #16 ; STMIA r1,{r0-r14} ; B RaiseException status_ptr IMPORT __fp_status_flags DCD __fp_status_flags ErrBlock IMPORT __fp_errblock DCD __fp_errblock trap ; ] IMPORT __rt_trap LDR ip, =__rt_trap CMP ip, #0 [ Interworking :LOR:(:DEF:thumb) BXNE ip | MOVNE pc, ip ] DCD 0xe6000010 ErrorBlock FP_IVO, "Floating Point Exception: Invalid Operation" ErrorBlock FP_OFL, "Floating Point Exception: Overflow" ErrorBlock FP_DVZ, "Floating Point Exception: Divide By Zero" return_Inf AND a3,a1,#Sign_bit TST ip,#Double_bit ADRNE a1,prototype_double_Inf LDMNEIA a1,{a1,a2} LDREQ a1,prototype_single_Inf ORR a1,a1,a3 B __fp_return_Inf return_NaN AND a3, a1, #Sign_bit TST ip, #Double_bit ADRNE a1,prototype_double_NaN LDMNEIA a1,{a1,a2} LDREQ a1,prototype_single_NaN ORR a1, a1, a3 B __fp_return_NaN prototype_double_Inf DCD &7ff00000,&00000000 prototype_single_Inf DCD &7f800000 prototype_double_NaN DCD &7ff00000,&00000001 prototype_single_NaN DCD &7f800001 ] ;------------------------------------------------------------------------------ [ :DEF: fpdata_s AREA |.data|, DATA EXPORT __fp_status_flags __fp_status_flags ; default - all flags enabled. DCD (&40:SHL:SysID_pos):OR:(((1:SHL:Except_len)-1):SHL:FPExceptE_pos) EXPORT __fp_errblock __fp_errblock DCD 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0 EXPORT __rt_trap __rt_trap DCD 0 ] ;============================================================================== END