;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Microsoft Research Singularity
;;; 
;;; Copyright (c) Microsoft Corporation.  All rights reserved.
;;;
;;; This file contains ARM-specific assembly code.
;;;

; nans.s
;
; Copyright (C) Advanced RISC Machines Limited, 1994. All rights reserved.
;
; RCS Revision: 1 
; Checkin Date: 2007/06/29 02:59:16 
; Revising Author

        GET     fpe.asm

        [ :DEF: thumb
        CODE32
        ]

	AREA   |.text|, CODE, READONLY

        EXPORT  __fp_convert_NaNs
        EXPORT  __fp_convert_NaN1
        EXPORT  __fp_convert_NaN_1Of2
        EXPORT  __fp_convert_NaN_2Of2

__fp_convert_NaNs

; First check for cases where the first operand determines which routine to
; use - i.e. if it is a signalling NaN or not a NaN at all.

        ORRS    Rtmp,OP1mlo,OP1mhi,LSL #1       ;First operand a NaN?
        BEQ     __fp_convert_NaN_2Of2           ;If not, use ConvertNaN2Of2
        TST     OP1mhi,#EIFracTop_bit           ;First operand a sign.NaN?
        BEQ     __fp_convert_NaN_1Of2           ;If so, use ConvertNaN1Of2

; First operand is a quiet NaN. If second is a signalling NaN, we use
; ConvertNaN2Of2; otherwise, we use ConvertNaN1Of2.

        ORRS    Rtmp,OP2mlo,OP2mhi,LSL #1       ;Second operand a NaN?
        BEQ     __fp_convert_NaN_1Of2           ;If not, use ConvertNaN1Of2
        TST     OP2mhi,#EIFracTop_bit           ;Second operand a sign.NaN?
        BNE     __fp_convert_NaN_1Of2           ;If not, use ConvertNaN1Of2

__fp_convert_NaN_2Of2

        CDebug3 4,"ConvertNaN2Of2: NaN =",OP2sue,OP2mhi,OP2mlo

; We must check for an invalid operation trap *before* we start using shared
; code, because the operands must be left unchanged for the trap handler.

;; There is always a trap handler, and it doesn't care about the operands

        TST     OP2mhi,#EIFracTop_bit           ;Signalling NaN?
        BEQ     ReturnIVO

; Now we can transfer the NaN to OP1sue/mhi/mlo and use shared code.

        MOV     OP1sue,OP2sue
        MOV     OP1mhi,OP2mhi
        MOV     OP1mlo,OP2mlo
        B       ConvertNaN1_NoTrap

__fp_convert_NaN1

; We must check for an invalid operation trap *before* we start using shared
; code, because the operands must be left unchanged for the trap handler.

        CDebug3 4,"ConvertNaN1: NaN =",OP1sue,OP1mhi,OP1mlo

        TST     OP1mhi,#EIFracTop_bit           ;Signalling NaN?
        BEQ     ReturnIVO
        B       ConvertNaN1_NoTrap              ; becomes 0 = InvReas_SigNaN

__fp_convert_NaN_1Of2

        CDebug3 4,"ConvertNaN1Of2: NaN =",OP1sue,OP1mhi,OP1mlo

; We must check for an invalid operation trap *before* we start using shared
; code, because the operands must be left unchanged for the trap handler.

        TST     OP1mhi,#EIFracTop_bit           ;Signalling NaN?
        BEQ     ReturnIVO

ConvertNaN1_NoTrap

; Now we need to perform the actual NaN conversion. The rules here are:
;
; * The exponent field must be converted to the appropriate value for the
;   destination precision;
;
; * Fraction bits that are not used by the destination precision must be
;   cleared;
;
; * If result precision is single or double, units bit is forced to 1;
;
; * If the NE bit is 0 and we're converting to extended precision, the
;   bottom bit of the fraction must be set or cleared to indicate whether
;   the NaN is "really" single or double precision respectively.

; Split according to result precision.

        TST     Rins,#Single_mask
        BNE     ConvertNaN1_ToSingle
        TST     Rins,#Double_mask
        BNE     ConvertNaN1_ToDouble

;------------------------------------------------------------------------------

ConvertNaN1_ToExtended

; If NE=0, we just need to modify the exponent. Otherwise, we need to
; establish the effective precision and set or clear the bottom bit of the
; fraction appropriately.

        TST     Rins,#NE_bit
        BNE     ConvertNaN1_ToExtended_MantissaDone
        AND     Rtmp,OP1sue,#ToExp_mask ;Isolate exponent field
        MOV     Rtmp2,#NaNInfExp_Double:AND:&FF
        ORR     Rtmp2,Rtmp2,#NaNInfExp_Double:AND:&FF00
        ASSERT  NaNInfExp_Double <= &FFFF
        CMP     Rtmp,Rtmp2              ;LO/EQ/HI if single/double/extended
        ASSERT  NaNInfExp_Single < NaNInfExp_Double
        ASSERT  NaNInfExp_Double < NaNInfExp_Extended
        BICLO   OP1mlo,OP1mlo,#1        ;Bottom bit cleared for single NaN
        ORREQ   OP1mlo,OP1mlo,#1        ;Bottom bit set for double NaN
                                        ;Bottom bit unchanged for extended NaN

ConvertNaN1_ToExtended_MantissaDone

; Change exponent and return.

        AND     OP1sue,OP1sue,#Sign_bit+Uncommon_bit
        ORR     OP1sue,OP1sue,#NaNInfExp_Extended:AND:&FF
        ORR     OP1sue,OP1sue,#NaNInfExp_Extended:AND:&FF00
        ASSERT  NaNInfExp_Extended <= &FFFF

        TEQ     OP1sue,OP1sue           ;Force EQ condition
  IF Interworking :LOR: Thumbing
        BX      LR
  ELSE
        MOV     PC,LR
  ENDIF

;------------------------------------------------------------------------------

ConvertNaN1_ToDouble

; Change exponent.

        AND     OP1sue,OP1sue,#Sign_bit+Uncommon_bit
        ORR     OP1sue,OP1sue,#NaNInfExp_Double:AND:&FF
        ORR     OP1sue,OP1sue,#NaNInfExp_Double:AND:&FF00
        ASSERT  NaNInfExp_Double <= &FFFF

; Clear appropriate fraction bits and set the units bit. Note that we know
; this won't change a NaN into an infinity unless someone is misusing
; extended precision with NE=0.

        MOV     OP1mlo,OP1mlo,LSR #11
        MOV     OP1mlo,OP1mlo,LSL #11
        ORR     OP1mhi,OP1mhi,#EIUnits_bit

        TEQ     OP1sue,OP1sue           ;Force EQ condition
  IF Interworking :LOR: Thumbing
        BX      LR
  ELSE
        MOV     PC,LR
  ENDIF

;------------------------------------------------------------------------------

ConvertNaN1_ToSingle

; Change exponent.

        AND     OP1sue,OP1sue,#Sign_bit+Uncommon_bit
        ORR     OP1sue,OP1sue,#NaNInfExp_Single:AND:&FF
        ORR     OP1sue,OP1sue,#NaNInfExp_Single:AND:&FF00
        ASSERT  NaNInfExp_Single <= &FFFF

; Clear appropriate fraction bits and set the units bit. Note that we know
; this won't change a NaN into an infinity unless someone is misusing
; extended precision with the NE bit equal to 0.

        MOV     OP1mlo,#0
        BIC     OP1mhi,OP1mhi,#&FF
        ORR     OP1mhi,OP1mhi,#EIUnits_bit
  IF Interworking :LOR: Thumbing
        BX      LR
  ELSE
        MOV     PC,LR                   ;Note we still have EQ from above
  ENDIF

;==============================================================================

ReturnIVO

; Return to the veneer with an IVO exception signalled.

        ORR     OP1sue,OP1sue,#IVO_bits
  IF Interworking :LOR: Thumbing
        BX      lr
  ELSE
        MOV     pc, lr
  ENDIF

;==============================================================================

        END
