446 lines
11 KiB
NASM
446 lines
11 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; 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
|