201 lines
7.8 KiB
NASM
201 lines
7.8 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Microsoft Research Singularity
|
|
;;;
|
|
;;; Copyright (c) Microsoft Corporation. All rights reserved.
|
|
;;;
|
|
;;; This file contains ARM-specific assembly code.
|
|
;;;
|
|
|
|
; __int64 to float and unsigned __int64 to float conversion routine.
|
|
;
|
|
; Input: r1 - Most significant word of 64-bit integer to be converted
|
|
; r0 - Least significant word of 64-bit integer to be converted
|
|
;
|
|
; Output: r0 - Converted number to floating point single precision format.
|
|
;
|
|
|
|
; Local storage size and offsets
|
|
LOC_SIZE EQU 0x18
|
|
OrgOp1h EQU 0x14
|
|
OrgOp1l EQU 0x10
|
|
ExDResl EQU 0x08
|
|
NewResl EQU 0x10
|
|
|
|
GET fpe.asm
|
|
GET kxarm.inc
|
|
|
|
Export __u64tos
|
|
Export __i64tos
|
|
IMPORT FPE_Raise
|
|
|
|
AREA |.text|, CODE, READONLY
|
|
|
|
; Prolog must match __i64tos
|
|
NESTED_ENTRY __u64tos
|
|
EnterWithLR_16
|
|
STMFD sp!, {lr} ; Save return address
|
|
SUB sp, sp, #LOC_SIZE
|
|
PROLOG_END
|
|
STR r0, [sp, #OrgOp1l] ; Save original arg in case of exception
|
|
ORRS r2, r0, r1 ; Check for zero
|
|
STR r1, [sp, #OrgOp1h] ; Save original arg in case of exception
|
|
ADDEQ sp, sp, #LOC_SIZE ; If zero, restore stack
|
|
IF Interworking :LOR: Thumbing
|
|
LDMEQFD sp!, {lr} ; and return zero
|
|
BXEQ lr
|
|
ELSE
|
|
LDMEQFD sp!, {pc} ; and return zero
|
|
ENDIF
|
|
MOV r14, #_FpU64ToS ; Initialize opcode, no exceptions
|
|
MOV r12, #0
|
|
B LongSingleNormalize
|
|
ENTRY_END __u64tos
|
|
|
|
; Prolog must match __u64tos
|
|
NESTED_ENTRY __i64tos
|
|
EnterWithLR_16
|
|
STMFD sp!, {lr} ; Save return address
|
|
SUB sp, sp, #LOC_SIZE
|
|
PROLOG_END
|
|
STR r0, [sp, #OrgOp1l] ; Save original arg in case of exception
|
|
ORRS r2, r0, r1 ; Check for zero
|
|
STR r1, [sp, #OrgOp1h] ; Save original arg in case of exception
|
|
ADDEQ sp, sp, #LOC_SIZE ; If zero, restore stack
|
|
IF Interworking :LOR: Thumbing
|
|
LDMEQFD sp!, {lr} ; and return zero
|
|
BXEQ lr
|
|
ELSE
|
|
LDMEQFD sp!, {pc} ; and return zero
|
|
ENDIF
|
|
MOV r14, #_FpI64ToS ; Initialize opcode, no exceptions
|
|
ANDS r12, r1, #Sign_bit ; Extract sign
|
|
BEQ LongSingleNormalize ; Positive value so do convert
|
|
RSBS r0, r0, #0 ; Else we have a negative number so
|
|
RSC r1, r1, #0 ; take the 2's complement inverse
|
|
|
|
|
|
; Sign is in r12.
|
|
; Mantissa abs(input 64-bit integer) is stored in r1:r0.
|
|
;
|
|
; Sign
|
|
; +-+-------------------------------+
|
|
; r12: |S|0000000000000000000000000000000|
|
|
; +-+-------------------------------+
|
|
;
|
|
; Unnormalized mantissa
|
|
; +--------------------------------+
|
|
; r1: | Most Significant Word |
|
|
; +--------------------------------+
|
|
;
|
|
; +--------------------------------+
|
|
; r0: | Least Significant Word |
|
|
; +--------------------------------+
|
|
;
|
|
; Only the high mantissa is shifted. After it is shifted into the correct
|
|
; position, the low mantissa is shifted into place. The exception is the
|
|
; first shift by 32 which moves the low mantissa into the high.
|
|
;
|
|
LongSingleNormalize
|
|
MOV r2, #0 ; Exponent adjustment/mantissa shift
|
|
|
|
CMP r1, #0 ; Any high 32 bits set?
|
|
ADDEQ r2, r2, #32 ; If not, adjust exponent
|
|
MOVEQ r1, r0 ; and shift the WHOLE mantissa
|
|
MOVEQ r0, #0 ; ..
|
|
|
|
MOVS r3, r1, LSR #16 ; Any high 16 bits set?
|
|
ADDEQ r2, r2, #16 ; If not, adjust exponent
|
|
MOVEQ r1, r1, LSL #16 ; and shift high mantissa
|
|
|
|
TST r1, #0xFF000000 ; Any high 8 bits set?
|
|
ADDEQ r2, r2, #8 ; If not, adjust exponent
|
|
MOVEQ r1, r1, LSL #8 ; and shift high mantissa
|
|
|
|
TST r1, #0xF0000000 ; Any high 4 bits set?
|
|
ADDEQ r2, r2, #4 ; If not, adjust exponent
|
|
MOVEQ r1, r1, LSL #4 ; and shift high mantissa
|
|
|
|
TST r1, #0xC0000000 ; Any high 2 bits set?
|
|
ADDEQ r2, r2, #2 ; If not, adjust exponent
|
|
MOVEQS r1, r1, LSL #2 ; and shift high mantissa
|
|
|
|
ADDPL r2, r2, #1 ; If high bit clear, adjust exponent
|
|
MOVPL r1, r1, LSL #1 ; and shift high mantissa
|
|
|
|
RSB r3, r2, #SExp_bias+63 ; Calculate exponent
|
|
ORR r12, r12, r3, LSL #SExp_pos
|
|
; Combine sign and exponent
|
|
|
|
CMP r2, #32 ; If all low shifted into high ...
|
|
MOV r1, r1, LSL #1 ; Hide the hidden one
|
|
ADD r2, r2, #1 ; ..
|
|
BGE insert_mantissa ; ... just insert the mantissa
|
|
|
|
; R2 contains the amount the mantissa has been shifted left, including
|
|
; the shift for the hidden one. It is in the range 1..32. R1 contains
|
|
; the high portion of the mantissa without any of R0 shifted into it.
|
|
; R0 is unshifted. Note that the case where the entire low word was
|
|
; shifted into the high word has already been taken care of and never
|
|
; reaches this code.
|
|
RSB r3, r2, #32 ; Determine amount of low mantissa
|
|
; shifted into high mantissa
|
|
|
|
ORR r1, r1, r0, LSR r3 ; Get part of low word shifted in high
|
|
MOVS r0, r0, LSL r2 ; Bits lost in low word?
|
|
ORRNE r1, r1, #1 ; If lost bits, set sticky
|
|
|
|
insert_mantissa
|
|
ORR r0, r12, r1, LSR #9 ; Insert mantissa into result
|
|
|
|
MOVS r1, r1, LSL #23 ; Inexact?
|
|
ORRNE r14, r14, #INX_bit ; If bits set, set inexact
|
|
|
|
MOVS r1, r1, LSL #1 ; Round
|
|
; CS -> guard bit
|
|
; MI -> round bit
|
|
; NE -> sticky bit | round bit
|
|
BCC __i64tos_return
|
|
TSTEQ r0, #0x1 ; Check lost bit
|
|
ADDNE r0, r0, #1 ; If G & (L | R | S) round up
|
|
|
|
|
|
__i64tos_return
|
|
TST r14, #FPECause_mask ; Any exceptions?
|
|
ADDEQ sp, sp, #LOC_SIZE ; pop off original arg, and
|
|
IF Interworking :LOR: Thumbing
|
|
LDMEQFD sp!, {lr} ; return
|
|
BXEQ lr
|
|
ELSE
|
|
LDMEQFD sp!, {pc} ; return
|
|
ENDIF
|
|
|
|
; Have an exception
|
|
LDR r2, [sp, #OrgOp1l] ; Load original operand
|
|
LDR r3, [sp, #OrgOp1h] ; ..
|
|
STR r0, [sp, #ExDResl] ; Store default result
|
|
ADD r0, sp, #NewResl ; Pointer to new result
|
|
MOV r1, r14 ; Exception information
|
|
|
|
CALL FPE_Raise
|
|
|
|
IF Thumbing :LAND: :LNOT: Interworking
|
|
CODE16
|
|
bx pc ; switch back to ARM mode
|
|
nop
|
|
CODE32
|
|
ENDIF
|
|
|
|
LDR r0, [sp, #NewResl] ; Load new result
|
|
ADD sp, sp, #LOC_SIZE ; Pop off exception info and orig arg
|
|
IF Interworking :LOR: Thumbing
|
|
LDMFD sp!, {lr} ; Return
|
|
BX lr
|
|
ELSE
|
|
LDMFD sp!, {pc} ; Return
|
|
ENDIF
|
|
|
|
ENTRY_END __i64tos
|
|
|
|
END
|