372 lines
8.7 KiB
ArmAsm
372 lines
8.7 KiB
ArmAsm
// TITLE("Floating Point Control")
|
||
//++
|
||
//
|
||
// Copyright (c) 1992 Digital Equipment Corporation
|
||
//
|
||
// Module Name:
|
||
//
|
||
// fpctrl.s
|
||
//
|
||
// Abstract:
|
||
//
|
||
// This module implements routines that control floating point
|
||
// operations.
|
||
//
|
||
// Author:
|
||
//
|
||
// Thomas Van Baak (tvb) 31-Aug-1992
|
||
//
|
||
// Environment:
|
||
//
|
||
// Any mode.
|
||
//
|
||
// Revision History:
|
||
//
|
||
//--
|
||
|
||
#include "ksalpha.h"
|
||
|
||
//
|
||
// Define call frame used to exchange a floating point and integer register.
|
||
//
|
||
|
||
.struct 0
|
||
FpCr: .space 8 // fpcr value
|
||
.space 8 // ensure 16-byte stack alignment
|
||
FpFrameLength: // length of stack frame
|
||
|
||
SBTTL("Get Hardware Floating Point Control Register")
|
||
//++
|
||
//
|
||
// ULONGLONG
|
||
// _get_fpcr (
|
||
// VOID
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function obtains the current FPCR value.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// None.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The current value of the FPCR is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(_get_fpcr, FpFrameLength, ra)
|
||
|
||
lda sp, -FpFrameLength(sp) // allocate stack frame
|
||
|
||
PROLOGUE_END
|
||
|
||
excb // wait for all pending traps
|
||
mf_fpcr f0, f0, f0 // get current fpcr
|
||
excb // block against new traps
|
||
stt f0, FpCr(sp) // store floating register in order to
|
||
ldq v0, FpCr(sp) // load integer register with fpcr
|
||
|
||
lda sp, FpFrameLength(sp) // deallocate stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end _get_fpcr
|
||
|
||
SBTTL("Set Hardware Floating Point Control Register")
|
||
//++
|
||
//
|
||
// VOID
|
||
// _set_fpcr (
|
||
// ULONGLONG FpcrValue
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function sets a new value in the FPCR.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// FpcrValue (a0) - Supplies the new value for the FPCR.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(_set_fpcr, FpFrameLength, ra)
|
||
|
||
lda sp, -FpFrameLength(sp) // allocate stack frame
|
||
|
||
PROLOGUE_END
|
||
|
||
stq a0, FpCr(sp) // store integer register in order to
|
||
ldt f0, FpCr(sp) // load floating register with fpcr
|
||
excb // wait for all pending traps
|
||
mt_fpcr f0, f0, f0 // set new fpcr
|
||
excb // block against new traps
|
||
|
||
lda sp, FpFrameLength(sp) // deallocate stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end _set_fpcr
|
||
|
||
SBTTL("Get Software Floating Point Control and Status Register")
|
||
//++
|
||
//
|
||
// ULONG
|
||
// _get_softfpcr (
|
||
// VOID
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function obtains the current software FPCR value.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// None.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The current value of the software FPCR is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(_get_softfpcr)
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
ldl v0, TeSoftFpcr(v0) // get current software fpcr value
|
||
ret zero, (ra) // return
|
||
|
||
.end _get_softfpcr
|
||
|
||
SBTTL("Set Software Floating Point Control and Status Register")
|
||
//++
|
||
//
|
||
// VOID
|
||
// _set_softfpcr (
|
||
// ULONG SoftFpcrValue
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function sets a new value in the software FPCR.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// SoftFpcrValue (a0) - Supplies the new value for the software FPCR.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(_set_softfpcr)
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
stl a0, TeSoftFpcr(v0) // store new software fpcr value
|
||
ret zero, (ra) // return
|
||
|
||
.end _set_softfpcr
|
||
|
||
SBTTL("Set New Floating Control Register Value")
|
||
//++
|
||
//
|
||
// ULONG
|
||
// _ctrlfp (
|
||
// IN ULONG newctrl,
|
||
// IN ULONG mask
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// For Alpha AXP this function sets nothing. It returns the current
|
||
// rounding mode and the current IEEE exception disable mask in the
|
||
// fp32 internal control word format.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// newctrl (a0) - Supplies the new control bits to be set.
|
||
//
|
||
// mask (a1) - Supplies the mask of bits to be set.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// oldctrl (v0) - Returns the old value of the control bits.
|
||
//
|
||
//
|
||
//--
|
||
|
||
NESTED_ENTRY(_ctrlfp, FpFrameLength, ra)
|
||
|
||
lda sp, -FpFrameLength(sp) // allocate stack frame
|
||
|
||
PROLOGUE_END
|
||
|
||
//
|
||
// Get the dynamic rounding mode from the FPCR.
|
||
//
|
||
|
||
excb // wait for all pending traps
|
||
mf_fpcr f0, f0, f0 // get current fpcr
|
||
excb // block against new traps
|
||
stt f0, FpCr(sp) // store floating register in order to
|
||
ldq t0, FpCr(sp) // load integer register with fpcr
|
||
|
||
srl t0, 58, t0 // shift rounding mode to low end
|
||
and t0, 0x3, t0 // isolate rounding mode bits
|
||
sll t0, 58 - 32, t0 // shift to internal cw format
|
||
|
||
//
|
||
// Get the IEEE exception mask bits and status bits from the software FPCR.
|
||
//
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
ldl v0, TeSoftFpcr(v0) // get current software fpcr value
|
||
xor v0, 0x3e, v0 // convert enable bits to disable bits
|
||
or v0, t0, v0 // merge with current rounding mode
|
||
|
||
lda sp, FpFrameLength(sp) // deallocate stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end _ctrlfp
|
||
|
||
SBTTL("Get IEEE Sticky Status Bits")
|
||
//++
|
||
//
|
||
// ULONG
|
||
// _statfp (
|
||
// VOID
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function gets the IEEE sticky status bits from the software FPCR.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// None.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The current value of the status word is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(_statfp)
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
ldl v0, TeSoftFpcr(v0) // get current software fpcr value
|
||
ret zero, (ra) // return
|
||
|
||
.end _statfp
|
||
|
||
SBTTL("Clear IEEE Sticky Status Bits")
|
||
//++
|
||
//
|
||
// ULONG
|
||
// _clrfp (
|
||
// VOID
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function clears the IEEE sticky status bits in the software FPCR.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// None.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The previous value of the status word is returned as the function value.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(_clrfp)
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
ldl t0, TeSoftFpcr(v0) // get current software fpcr value
|
||
bic t0, 0x3e0000, t1 // clear status bits
|
||
stl t1, TeSoftFpcr(v0) // store new software fpcr value
|
||
mov t0, v0 // get previous value
|
||
ret zero, (ra) // return
|
||
|
||
.end _clrfp
|
||
|
||
SBTTL("Set IEEE Sticky Status Bits")
|
||
//++
|
||
//
|
||
// VOID
|
||
// _set_statfp (
|
||
// IN ULONG sw
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function sets a IEEE sticky status bit in the software FPCR.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// sw (a0) - Supplies the status bits to be set.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// None.
|
||
//
|
||
//--
|
||
|
||
LEAF_ENTRY(_set_statfp)
|
||
|
||
GET_THREAD_ENVIRONMENT_BLOCK // get Teb address in v0
|
||
ldl t0, TeSoftFpcr(v0) // get current software fpcr value
|
||
or t0, a0, t0 // set status bit(s)
|
||
stl t0, TeSoftFpcr(v0) // store new software fpcr value
|
||
ret zero, (ra) // return
|
||
|
||
.end _set_statfp
|
||
|
||
SBTTL("Convert Signal NaN to Quiet NaN")
|
||
//++
|
||
//
|
||
// double
|
||
// _nan2qnan (
|
||
// IN double x
|
||
// )
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// This function converts a signaling NaN to a quiet NaN without causing
|
||
// a hardware trap.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// x (f16) - Supplies the signal NaN value to be converted.
|
||
//
|
||
// Return Value:
|
||
//
|
||
// The quiet NaN value is returned as the function value.
|
||
//
|
||
//--
|
||
NESTED_ENTRY(_nan2qnan, FpFrameLength, ra)
|
||
|
||
lda sp, -FpFrameLength(sp) // allocate stack frame
|
||
|
||
PROLOGUE_END
|
||
|
||
stt f16, FpCr(sp) // store floating register in order to
|
||
ldq t0, FpCr(sp) // load integer register
|
||
ldiq t1, (1 << 51) // get NaN bit
|
||
or t0, t1, t0 // convert NaN to QNaN
|
||
stq t0, FpCr(sp) // store integer register in order to
|
||
ldt f0, FpCr(sp) // load floating register
|
||
|
||
lda sp, FpFrameLength(sp) // deallocate stack frame
|
||
ret zero, (ra) // return
|
||
|
||
.end _nan2qnan
|