;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Microsoft Research Singularity ;;; ;;; Copyright (c) Microsoft Corporation. All rights reserved. ;;; ;;; This file contains ARM-specific assembly code. ;;; ; format_d.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 CodeArea |FPL$$Format| IMPORT __fp_nonveneer_error ; Functions for converting ; double <-> internal, ; double <-> int, ; double <-> longlong ; and for fiddling with the double format (frexp) DNaNInf EQU NaNInfExp_Double - EIExp_bias + DExp_bias exp RN 2 ;============================================================================== [ :DEF: dflt_s :LOR: :DEF: dfltu_s ;This code needed for the unsigned float too. MACRO DoubleNormalise ;Now we have the basis of the exponent, we round. MOVS utmp1, a1, LSR #16 MOVEQ a1, a1, LSL #16 SUBEQ tmp, tmp, #16< 0 BNE _ll_to_d_shared | BEQ %FT02 01 LongDoubleNormalise 02 ] EnterWithStack BL _dfltu ORR dOPh, dOPh, #Sign_bit ReturnToStack ] ;------------------------------------------------------------------------------ [ :DEF: ll_uto_d_s Export _ll_uto_d ExportCodeSize _ll_to_d_shared _ll_uto_d EnterWithLR_16 IMPORT _dfltu TEQ a2, #0 BEQ _dfltu [ CodeSize = 2 MOV tmp, #0 _ll_to_d_shared ORR tmp, tmp, #((DExp_bias + 63) :AND: 0xff00) << DExp_pos | MOV tmp, #((DExp_bias + 63) :AND: 0xff00) << DExp_pos ] [ CodeSize = 1 _ll_to_d_shared ] ORR tmp, tmp, #((DExp_bias + 63) :AND: 0x00ff) << DExp_pos LongDoubleNormalise ] ;=========================================================================== [ :DEF: dfix_s Export _dfix ROUT _dfix EnterWithLR_16 MOVS a3, dOPh, LSL #1 ; C<--sign MOV a3, a3, LSR #DFhi_len+1 MOV dOPh, dOPh, LSL #DExp_len ORR a1, dOPh, dOPl, LSR #DFhi_len+1 ORR a1, a1, #1<<31 SUB a3, a3, #(DExp_bias:AND:0xff00) BCS _dfix_neg SUBS a3, a3, #(DExp_bias:AND:0x00ff) BMI _dfix_zero RSBS a3, a3, #31 ; if resulting shift is -ve, or zero, then the result would ; overflow (zero because it would leave the units bit ; unchanged, and this path is for +ve arguments) MOVGT a1, a1, LSR a3 ; Don't return -ve results for +ve arguments - will only happen ; if the shift amount is zero ReturnToLR GT ; a1 contains the mantissa, with units bit at bit 31 (shift ; did not happen, or was zero) ; a2 contains the other bits of the mantissa BIC a1, a1, #Sign_bit ; ensure any untrapped result is +ve B _dfix_ivo _dfix_zero MOV a1, #0 ReturnToLR _dfix_neg SUBS a3, a3, #(DExp_bias:AND:0x00ff) BMI _dfix_zero RSBS a3, a3, #31 MOVGT a1, a1, LSR a3 RSBGT a1, a1, #0 ; don't return +ve for -ve arguments ReturnToLR GT ; Special case - INT_MIN will leave a shift of zero (Z set), and ; r0=0x80000000 r1=0x00000000 ORREQS ip, dOPl, dOPh, LSL #1 ; Z<-special case ReturnToLR EQ ; ORR a1, a1, #Sign_bit ; ensure untrapped result is -ve _dfix_ivo MOV a4, #IVO_bit :OR: FixFn [ {TRUE} ; On some systems, casting NaN returns zero ; check for maximum exponent ADD a3, a3, #:NOT:(31-((DExp_mask:SHR:DExp_pos)-DExp_bias)) CMN a3, #1 BNE __fp_nonveneer_error ORRS ip, dOPl, a1, LSL #1 ; ignore prospective sign MOVNE a4, #IVO_bit :OR: FixZeroFn ] B __fp_nonveneer_error ] ;--------------------------------------------------------------------------- [ :DEF: dfixu_s ROUT Export _dfixu _dfixu EnterWithLR_16 MOVS a3, dOPh, LSL #1 ; C<-sign BCS _dfixu_neg [ CodeSize <> 0 ;; This doesn't work at the moment, because dfixu will return UINT_MAX on ;; overflow, whereas for dfix it should return INT_MAX. The same applies ;; to longlong and float versions _dfix_shared ] MOV a3, a3, LSR #DFhi_len+1 ; get exponent into a3 MOV dOPh, dOPh, LSL #DExp_len ORR a1, dOPh, dOPl, LSR #DFhi_len+1 ; get mantissa into a1 ORR a1, a1, #1<<31 ; and add units bit SUB a3, a3, #(DExp_bias:AND:0xff00) SUBS a3, a3, #(DExp_bias:AND:0x00ff) BMI _dfix_zero RSBS a3, a3, #31 ; in the unsigned case, a shift of zero is perfectly allowable MOVPL a1, a1, LSR a3 ReturnToLR PL _dfixu_ivo MOV a4, #IVO_bit :OR: FixuFn [ {TRUE} ; On some systems, casting NaN returns zero ; check for maximum exponent ADD a3, a3, #:NOT:(31-((DExp_mask:SHR:DExp_pos)-DExp_bias)) CMN a3, #1 BNE __fp_nonveneer_error ORRS ip, dOPl, a1, LSL #1 ; ignore units bit MOVNE a4, #IVO_bit :OR: FixZeroFn ] B __fp_nonveneer_error _dfixu_neg ORRS a4, dOPl, dOPh, LSL #1 MOVNE a4, #IVO_bit :OR: FixZeroFn BNE __fp_nonveneer_error _dfix_zero MOV a1, #0 ReturnToLR ] ;------------------------------------------------------------------------------ [ :DEF: ll_sfrom_d_s Export _ll_sfrom_d ROUT _ll_sfrom_d EnterWithLR_16 MOVS a4, dOPh, LSL #1 ; C<-sign MOV a4, a4, LSR #DFhi_len+1 ; exp MOV tmp, dOPh, LSL #DExp_len ; mhi ORR tmp, tmp, dOPl, LSR #DFhi_len+1 ; add mlo to mhi ORR tmp, tmp, #1<<31 ; set units bit -- tmp now has top of mantissa MOV a1, dOPl, LSL #DExp_len ; a1 <- low of mantissa ; a1 <- lsw of mantissa ; a2 <- original low word of mantissa ; tmp <- msw of mantissa, with units ; a4 <- exponent, still biased ; C <- sign SUB a4, a4, #(DExp_bias :AND: 0xff00) BCS ll_from_d_negative SUBS a4, a4, #(DExp_bias :AND: 0x00ff) BMI _ll_from_d_zero RSBS a3, a4, #31 ; N <- large exponent MOVGT a1, tmp, LSR a3 ; small exponent - 32+a3 shift MOVGT a2, #0 ; msw is zero ReturnToLR GT ADDS a3, a3, #32 ; large exponent, N <- too large SUB a4, a4, #31 MOVGT a1, a1, LSR a3 ORRGT a1, a1, tmp, LSL a4 MOVGT a2, tmp, LSR a3 ; ensure result is +ve ReturnToLR GT ; fall through ; tmp/a2 <- mantissa ; a4 <- unbiased exponent BIC a1, a1, #Sign_bit ; prospective result is +ve B _ll_from_d_ivo _ll_from_d_zero MOV a1, #0 MOV a2, #0 ReturnToLR ll_from_d_negative SUBS a4, a4, #(DExp_bias :AND: 0x00ff) BMI _ll_from_d_zero RSBS a3, a4, #31 MOVPL a1, tmp, LSR a3 MOVPL a2, #0 BPL %ft01 ADDS a3, a3, #32 SUB a4, a4, #31 BLE %f02 MOV a1, a1, LSR a3 ORR a1, a1, tmp, LSL a4 MOV a2, tmp, LSR a3 01 RSBS a1, a1, #0 RSC a2, a2, #0 ReturnToLR 02 ; special case for LLINT_MIN ORREQS a1, dOPl, ip, LSL #1 MOVEQ a2, #Sign_bit ReturnToLR EQ ORR a1, a1, #Sign_bit ; ensure result is -ve ; tmp/a2 <- mantissa ; a3 <- unbiased exponent _ll_from_d_ivo MOV a4, #IVO_bit :OR: FixFn :OR: LongLong_bit [ {TRUE} ; On some systems, casting NaN returns zero ; check for maximum exponent ADD a3, a3, #:NOT:(63-((DExp_mask:SHR:DExp_pos)-DExp_bias)) CMN a3, #1 BNE __fp_nonveneer_error ORRS ip, dOPl, tmp, LSL #1 ; ignore units bit MOVNE a4, #IVO_bit :OR: FixZeroFn :OR: LongLong_bit ] B __fp_nonveneer_error ] ;------------------------------------------------------------------------------ [ :DEF: ll_ufrom_d_s Export _ll_ufrom_d ROUT _ll_ufrom_d EnterWithLR_16 MOVS a3, dOPh, LSL #1 ; C<-sign BCS _ll_ufrom_d_neg MOV a3, a3, LSR #DFhi_len+1 ; exp MOV a4, dOPh, LSL #DExp_len ; mhi ORR a4, a4, dOPl, LSR #DFhi_len+1 ; add mlo to mhi ORR a4, a4, #1<<31 ; set units bit -- a4 now has top of mantissa MOV a1, dOPl, LSL #DExp_len ; a1 <- low of mantissa MOV a2, a4 ; a2 <- high of mantissa ; a1 <- lsw of mantissa ; a2 <- msw of mantissa, with units SUB a3, a3, #(DExp_bias :AND: 0xff00) SUBS a3, a3, #(DExp_bias :AND: 0x00ff) BMI _ll_ufrom_d_zero RSBS a4, a3, #31 ; N <- large exponent MOVPL a1, a2, LSR a4 ; small exponent - 32+a4 shift MOVPL a2, #0 ; msw is zero ReturnToLR PL ADDS a4, a4, #32 ; large exponent, N <- too large SUB a3, a3, #31 MOVPL a1, a1, LSR a4 ORRPL a1, a1, a2, LSL a3 MOVPL a2, a2, LSR a4 ReturnToLR PL ; fall through _ll_ufrom_d_ivo ; On some systems, casting NaN returns zero ; check for maximum exponent ADD a3, a4, #:NOT:(63-((DExp_mask:SHR:DExp_pos)-DExp_bias)) CMN a3, #1 MOV a4, #IVO_bit :OR: FixuFn :OR: LongLong_bit BNE __fp_nonveneer_error ORRS ip, a1, dOPl, LSL #1 ; ignore units bit MOVNE a4, #IVO_bit :OR: FixZeroFn :OR: LongLong_bit B __fp_nonveneer_error _ll_ufrom_d_neg ORRS a4, dOPl, dOPh, LSL #1 MOVNE a4, #IVO_bit :OR: FixZeroFn :OR: LongLong_bit BNE __fp_nonveneer_error _ll_ufrom_d_zero MOV a1, #0 MOV a2, #0 ReturnToLR ] ;============================================================================== [ :DEF: d2e_s EXPORT _d2e _d2e EnterWithLR MOVS tmp,dOPh,LSL #1 ;C=sign; Z=exp & frac.top zero TEQEQ dOPl,#0 ;C unchanged; Z=value is a zero MOV a4,tmp,LSL #DExp_len-1 ;Frac.top in bits 30:11 of mhi MOV dOPh,tmp,LSR #DExp_pos ;Exponent in bits 11:1 MOV OP1mlo,dOPl,LSL #DExp_len ; OP2mhi and 31:11 of OP2mlo ORR OP1mhi,a4,dOPl,LSR #DFhi_len+1 ;Fraction in bits 30:0 of ADDNE dOPh,dOPh,#(EIExp_bias-DExp_bias):SHL:1 MOV OP1sue,dOPh,RRX ;Recombine sign and exponent ORRNE OP1mhi,OP1mhi,#EIUnits_bit ; Gets here with the *double precision* exponent in the top 11 bits ; of tmp. (Exponent<<1+DExp_pos.) We use a sign extended shift to ; spot the "maximum exponent case" - leaves us with -1 in tmp. MOVS tmp,tmp,ASR #1+DExp_pos BEQ _d2e_norm_op1 ;Returns to caller CMP tmp,#&ffffffff ORREQ OP1sue,OP1sue,#Uncommon_bit ReturnToLR _d2e_norm_op1 ; Got to here implies a denormalised number. This needs normalising. The ; units bit is (incorrectly) set. If it *is* unset then this is a zero, ; and we have got here "by accident". TST OP1mhi, #EIUnits_bit ReturnToLR EQ BICS OP1mhi,OP1mhi,#Sign_bit BEQ _d2e_denorm_low ; The top set bit in the high word, so find out how much to denormalise ; by MOVS RNDexp,OP1mhi,LSR #16 MOVEQ OP1mhi,OP1mhi,LSL #16 MOVEQ tmp,#16 MOVNE tmp,#0 MOVS RNDexp,OP1mhi,LSR #24 MOVEQ OP1mhi,OP1mhi,LSL #8 ADDEQ tmp,tmp,#8 MOVS RNDexp,OP1mhi,LSR #28 MOVEQ OP1mhi,OP1mhi,LSL #4 ADDEQ tmp,tmp,#4 MOVS RNDexp,OP1mhi,LSR #30 MOVEQ OP1mhi,OP1mhi,LSL #2 ADDEQ tmp,tmp,#2 MOVS RNDexp,OP1mhi,LSR #31 MOVEQ OP1mhi,OP1mhi,LSL #1 ADDEQ tmp,tmp,#1 ; tmp now contains the amount to shift by. RSB RNDexp,tmp,#32 ORR OP1mhi,OP1mhi,OP1mlo,LSR RNDexp MOV OP1mlo,OP1mlo,LSL tmp SUB OP1sue,OP1sue,tmp ADD OP1sue,OP1sue,#1 ReturnToLR _d2e_denorm_low ; The top bit to be set is in OP1mlo MOVS RNDexp,OP1mlo,LSR #16 MOVEQ OP1mlo,OP1mlo,LSL #16 MOVEQ tmp,#16 MOVNE tmp,#0 MOVS RNDexp,OP1mlo,LSR #24 MOVEQ OP1mlo,OP1mlo,LSL #8 ADDEQ tmp,tmp,#8 MOVS RNDexp,OP1mlo,LSR #28 MOVEQ OP1mlo,OP1mlo,LSL #4 ADDEQ tmp,tmp,#4 MOVS RNDexp,OP1mlo,LSR #30 MOVEQ OP1mlo,OP1mlo,LSL #2 ADDEQ tmp,tmp,#2 MOVS RNDexp,OP1mlo,LSR #31 MOVEQ OP1mlo,OP1mlo,LSL #1 ADDEQ tmp,tmp,#1 ; tmp now contains the amount to shift by. MOV OP1mhi,OP1mlo MOV OP1mlo,#0 SUB OP1sue,OP1sue,#31 SUB OP1sue,OP1sue,tmp ReturnToLR ] ;============================================================================== [ :DEF: e2d_s EXPORT _e2d EXPORT __fp_e2d MACRO E2D_Return $cc=AL MOV$cc a4, r10 LDM$cc.FD sp!, {r10} IF Interworking :LOR: Thumbing BX$cc lr ELSE MOV$cc pc, lr ENDIF MEND _e2d EnterWithLR MOV RNDexp, OP1sue, LSL #32-EIExp_len MOV RNDexp, RNDexp, LSR #32-EIExp_len BIC OP1sue, OP1sue, RNDexp __fp_e2d STMFD sp!, {r10} ; r10 is used to store exception information MOV r10, #0 ; Assume no exceptions ;Passed in the result of an operation. That is: ; - the uncommon/sign are in OP1sue ; an error can be flagged as Uncommon, with the Error bit set, and ; a further bit specifying which. fpe.s defines appropriate values ; (e.g. IVO_bits). These are transferred to a4 on exit. ; - the exponent in RNDexp, ; - the fraction in OP1mlo/OP1mhi. ;Return with ; - a result in dOPh/dOPl and possibly some error flags in a4 ASSERT Uncommon_bit = 1:SHL:(31-1) ASSERT EIUnits_bit = 1:SHL:31 BICS tmp, OP1mhi, OP1sue, LSL #1 BPL _e2d_SpecialCase SUBS RNDexp, RNDexp, #(EIExp_bias-DExp_bias) BMI _e2d_ExpUnderflow ASSERT tmp <> RNDexp ADDNE tmp, RNDexp, #1 CMPNE tmp, #DNaNInf+1 BGE _e2d_ExpOverflow MOVS tmp, OP1mlo, LSR #32-DFhi_len-1 ; 1 is for the J bit ;If rounding is needed then a one will have dropped out BCS _e2d_NeedsRounding ;Simple enough now then. ; Test for inexact ORRS Rarith, Rarith, OP1mlo, LSL #DFhi_len+1 ORRNE r10, r10, #INX_bit ORR dOPh, OP1sue, RNDexp, LSL #DExp_pos BIC OP1mhi, OP1mhi, #EIUnits_bit ORR dOPh, dOPh, OP1mhi, LSR #32-DFhi_len-1 ORR dOPl, tmp, OP1mhi, LSL #DFhi_len+1 E2D_Return ; 22S+1N ;.............................................................................. _e2d_SpecialCase TST OP1sue, #Uncommon_bit BNE _e2d_Uncommon _e2d_UnitsBit ;Sign is in OP1sue's top bit. The units bit of OP1mhi is clear indicating a ;zero value (since the denorm case is handled by the uncommon bit). AND dOPh, OP1sue, #Sign_bit MOV dOPl, #0 E2D_Return ; 9S+2N ;.............................................................................. _e2d_ExpOverflow ;Sign is in OP1sue's sign bit. May still need rounding. The exponent (RNDexp) ;is out of range for a double precision number, and wasn't signalled as a NaN. ;The exponent has been re-biased. ;Might just be the "just underflowing case" (because of a quirk above). In ;that case RNDexp = 0 TEQ RNDexp, #0 BEQ _e2d_ExpUnderflow MOV r10, #OVF_bit :OR: INX_bit MOV r0, #0 ; Have an overflow so clear mantissa and MVN r2, #0 ; force exponent to max, preserving the sign ANDS r1, r1, r2, LSL #20 ; .. ORR r1, r1, r2, LSL #20 ; .. BICPL r1, r1, #0x80000000 ; .. E2D_Return ;.............................................................................. Export _e2d_ExpUnderflow _e2d_ExpUnderflow ;Underflow. If the value can be represented as a denorm in the target ;precision, then it should be. For this to be the case the exponent needs ;to lie in the range [&380-23..&380]. Otherwise the result is a suitably ;signed zero. (A zero is, however, a denorm with zero mantissa.) ;The exponent (RNDexp) has been rebiased (by (EIExp_bias-SExp_bias)) ADDS RNDexp, RNDexp, #DFhi_len+32 ;If the result is zero then we round according to the top bit of the ;fraction. Branch out of line to do this. BEQ _e2d_ExpJustUnderflow ;If this result is negative, nothing can be done, so return a signed zero. ANDMI dOPh, OP1sue, #Sign_bit MOVMI dOPl, #0 ORRMI r10, r10, #UNF_bits E2D_Return MI ;We now have in OP1mhi 1MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM ;and in OP1mlo MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM ;These need to be converted into a denormalised number. We want the N ;left most bits (N<=52) from this 64-bit value. This splits into three ;cases - [1..20], [21..32] and [33..52]. We actually split it into the ;[1..32] and [33..52] cases. SUBS RNDexp, RNDexp, #32 BEQ _e2d_Underflow32 BLT _e2d_ShortUnderflow ;Okay - all the bits we are going to throw away are in the low word. ;Check for rounding. SUB tmp, RNDexp, #1 ORRS tmp, Rarith, OP1mlo, LSL RNDexp ORRNE r10, r10, #UNF_bits ; Determine inexact MOVS tmp, OP1mlo, LSL RNDexp BMI _e2d_LongUnderflowNeedsRounding RSB tmp, RNDexp, #32 ASSERT dOPh <> OP1mhi ORR dOPh, OP1sue, OP1mhi, LSR tmp MOV OP1mlo, OP1mlo, LSR tmp ORR dOPl, OP1mlo, OP1mhi, LSL RNDexp E2D_Return _e2d_LongUnderflowNeedsRounding ;We need to determine whether to just round upwards, or to round to even. ORRS tmp, Rarith, tmp, LSL #1 ;C=1, Z=definite round to even. ;Now we calculate the shift amount and do the shift, probably throwing away ;lots of mantissa bits RSB tmp, RNDexp, #32 ;Merge in the sign bit and add one (C flag). Then undo the rounding if we ;need to round to even and the result isn't even. ORR dOPh, OP1sue, OP1mhi, LSR tmp MOV OP1mlo, OP1mlo, LSR tmp ORR dOPl, OP1mlo, OP1mhi, LSL RNDexp TSTEQ dOPl, #1 E2D_Return EQ ADDS dOPl, dOPl, #1 ADDCS dOPh, dOPh, #1 TST dOPh, #0x00100000 ; Check if rounded up to MinNormal BICNE r10, r10, #UNF_bit ; If did, no longer underflow E2D_Return ;.............................................................................. _e2d_Underflow32 ; Check for inexact ORRS tmp, Rarith, OP1mlo ORRNE r10, r10, #UNF_bits ;We are going to throw away the entire of the bottom word. This makes ;rounding simple, so it is special cased. TEQ OP1mlo, #1<<31 ;Z flag is set if only the top bit is set. The N flag is set to the ;*inverse* of the top bit. ASSERT OP1sue = dOPh ASSERT OP1mhi = dOPl E2D_Return MI ;No rounding to be done TSTEQ dOPl, #1 ;Z flag now clear if rounding needed E2D_Return EQ ADDS dOPl, dOPl, #1 ADDCS dOPh, dOPh, #1 E2D_Return ;.............................................................................. _e2d_ShortUnderflow ;We are going to throw away all of the bottom word. The amount to shift ;by is in RNDexp, but has had 32 taken away. ADD RNDexp, RNDexp, #32 ; Undo the subtraction ; Check for inexact SUB tmp, RNDexp, #0 ORR tmp, Rarith, OP1mhi, LSL tmp ORRS tmp, tmp, OP1mlo ORRNE r10, r10, #UNF_bits MOVS tmp, OP1mhi, LSL RNDexp ; test top bit to be thrown BMI _e2d_ShortUnderflowNeedsRounding RSB tmp, RNDexp, #32 ASSERT dOPh <> OP1mhi MOV dOPl, OP1mhi, LSR tmp AND dOPh, OP1sue, #Sign_bit E2D_Return _e2d_ShortUnderflowNeedsRounding TEQ tmp, #1<<31 ; any bits other than rounding ORREQS tmp, OP1mlo, Rarith ; bit? i.e. in lo or in sticky? RSB tmp, RNDexp, #32 ASSERT dOPh = OP1sue MOV dOPl, OP1mhi, LSR tmp TSTEQ dOPl, #1 ADDNE dOPl, dOPl, #1 ; Can't overflow in this case E2D_Return _e2d_ExpJustUnderflow ;The exponent is just at the limits of underflow - i.e. we may be able ;to represent the number as the float epsilon. ; MOVS dOPh, dOPh, LSR #20 ; ADC fOP, tmp, #0 ;But that's not how the FP emulator behaves. It does this: TEQ OP1mhi, #1<<31 TEQEQ OP1mlo, #0 ASSERT OP1sue = dOPh MOVEQ dOPl, #0 MOVNE dOPl, #1 ORR r10, r10, #UNF_bits E2D_Return _e2d_Uncommon ;The uncommon bit may signal an error (in which case the error bit will ;be set too) ; RDCFix: Get rid of this? Take care of NaNs, etc. in special code for each routine? ; TST OP1sue,#Error_bit ; BNE _e2d_Error ;The uncommon bit (infinity or a NaN) bit was set. The exponent in RNDexp ;is invalid. An infinity is signalled by mhi=mlo=0. TEQ OP1mhi, #0 MOVNES OP1mhi, OP1mhi, LSL #1 MOVMI dOPh, #-1 E2D_Return MI TEQEQ OP1mlo, #0 E2D_Return NE ;An infinity. The sign of the resulting infinity is in tmp. AND dOPh, OP1sue, #Sign_bit ORR dOPh, dOPh,#(DNaNInf:AND:&ff00)<dOPh STMIA a3,{dOPh,a4} ASSERT dOP2l=a4 EOR dOP2h,dOP1h,#Sign_bit B _dadd modf_truncate_top MOV a4,dOPh,LSR tmp MOV a4,a4,LSL tmp MOV tmp,#0 ASSERT tmp>a4 STMIA a3,{a4,tmp} EOR dOP2h,a4,#Sign_bit MOV dOP2l,#0 B _dadd modf_big ; The number is so big that it has no fractional part. STMIA a3,{dOPh,dOPl} MOV dOPh,#0 MOV dOPl,#0 ReturnToLR modf_small ; The number is so small that it has a zero integer part. MOV a4,#0 MOV tmp,#0 STMIA a3,{a4,tmp} ReturnToLR ] ;=========================================================================== [ :DEF: floor_s EXPORT floor EXPORT ceil mask RN 12 ; Floor - Round to an integer towards -Inf floor EnterWithLR MOVS exp, dOPh, LSL #1 BCS ceil_1 floor_1 MOV exp, exp, LSR #21 RSB exp, exp, #1088 ; 1088 is first 8-bit constant > 1023+53 RSBS exp, exp, #65 BLO floor_exp_overflow ; exp > 1088 or exp < 1023 -> overflow ; exp is number of fraction bits to preserve (0 .. 65) RSBS exp, exp, #20 ; number of bits to clear in high word MOV mask, #-1 ANDGE dOPh, dOPh, mask, LSL exp ; clear exp bits in high word MOVGE dOPl, #0 ReturnToLR GE RSB exp, exp, #0 ; number of bits to preserve in low word BIC dOPl, dOPl, mask, LSR exp ; preserve exp bits in low word ReturnToLR floor_exp_overflow ; PL if exp too large, MI too small ANDMI dOPh, dOPh, #Sign_bit ; create signed zero MOVMI dOPl, #0 ReturnToLR ; Ceil - Round to an integer towards +Inf ceil EnterWithLR MOVS exp, dOPh, LSL #1 BCS floor_1 ceil_1 MOV exp, exp, LSR #21 RSB exp, exp, #1088 RSBS exp, exp, #65 BLO ceil_exp_overflow ; exp > 1088 or exp < 1023 -> overflow ; exp is number of fraction bits to preserve (0 .. 65) MOV mask, #-1 SUBS exp, exp, #20 ; number of bits to preserve in low word BGT ceil_low ADD exp, exp, #32 ; number of bits to preserve in high word ADDS dOPl, dOPl, #-1 ; round up low word ADC dOPh, dOPh, mask, LSR exp ; round up high word BIC dOPh, dOPh, mask, LSR exp ; clear exp bits in high word MOV dOPl, #0 ReturnToLR ceil_low ADDS dOPl, dOPl, mask, LSR exp ; round up low word BIC dOPl, dOPl, mask, LSR exp ; clear exp bits in low word ReturnToLR CC ADD dOPh, dOPh, #1 ; round up high word ReturnToLR ceil_exp_overflow ; PL if exp too large, MI too small ReturnToLR PL ORRS tmp, dOPl, dOPh, LSL #1 ; zero? ANDNE dOPh, dOPh, #Sign_bit ORRNE dOPh, dOPh, #0x30000000 ; no, create +-1.0 ORRNE dOPh, dOPh, #0x0FF00000 MOVNE dOPl, #0 ReturnToLR ] ;=========================================================================== END