/**
***  Copyright  (C) 1996-97 Intel Corporation. All rights reserved.
***
*** The information and source code contained herein is the exclusive
*** property of Intel Corporation and may not be disclosed, examined
*** or reproduced in whole or in part without explicit written authorization
*** from the company.
**/

//      TITLE("Context Conversion")
//++
//                                                        
// Module Name:
//
//    convctx.s
//
// Abstract:
//
//    This module implements the code necessary to convert or assign 
//    the user to kernel transition context to or from iA mode context.
//
// Author:
//
//    Edward G. Chron (echron) 01-Apr-1996
//
// Environment:
//
//    Kernel mode only.
//
// Revision History:
//
//
//--

#include "ksia64.h"

        .file       "convctx.s"
         
//++
//
// VOID
// RtlEmFpToIaFpContext (
//      IN     PCONTEXT  ContextEM,
//      IN OUT UCHAR    *iAFpArea   
//    )
//
// Routine Description:
//
//      This function takes the values stored for the EM FP registers which
//      map the iA mode FP registers and copies them (in iA mode 10 byte
//      format) to the targeted 80 byte iA mode FP register context area.
//
// Arguments:
//
//      ContextEM (a0) - Pointer to the EM mode Context which contain the FP registers.
//      iAFpArea(a1)   - Pointer to area to store 8 * 10 byte iA mode FP regs. 
//
// Return Value:
//
//    None.
//
// N.B. The format iA mode FP registers is 80 bits and will not change.
//
//--

        LEAF_ENTRY(RtlEmFpToIaFpContext)

        add         t5 = -8, r0             // Need to convert 8 EM mode FP Regs
         
cvtEmFp:         

        ldfe        ft0 = [a0], 16          // Get EM FP reg mapping iA FP reg
        add         t4 = -4, r0             // Need to store 2 bytes 4 times
        ;;
         
        getf.sig    t2 = ft0                // floating-point reg significand
        getf.exp    t3 = ft0                // floating-point sign & exponent
        ;;
         
stIaFpReg:

        st2         [a1] = t2, 2            // save 2 bytes of significand 
        extr.u      t2 = t2, 16, 48         // shift to the next two bytes
        adds        t4 = 0x1, t4            // bump loop count
        ;;

        cmp.lt      p6, p0 = t4, r0         // done?
(p6)    br.cond.dpnt.few stIaFpReg          // no, store the next two bytes
         
        adds        t5 = 0x1, t5            // bump loop count
        add         t4 = 0, t3              // copy of exponent and sign
        ;;
        extr.u      t4 = t4, 2, 62          // get the sign in bit 15
        ;;

        cmp.lt      p6, p7 = t5, r0         // done?
        dep         t3 = t3, t4, 0, 15      // just first 16 bits of exponent
        ;;

        st2         [a1] = t3, 2            // save sign and iA exponent
(p6)    br.cond.dpnt.few cvtEmFp            // no, process the next register
(p7)    br.ret.sptk brp
        ;;

        LEAF_EXIT(RtlEmFpToIaFpContext)    

//++
//
// VOID
// RtlIaFpToEmFpContext (
//      IN  UCHAR        *iAFpArea,   
//      IN  OUT PCONTEXT  ContextEM,
//      IN  OUT FLOAT128 *FpWorkArea  
//    )
//
// Routine Description:
//
//      This function takes the values stored for the EM FP registers which
//      map the iA mode FP registers and copies them (in iA mode 10 byte
//      format) to the targeted 80 byte iA mode FP register context area.
//
// Arguments:
//
//      ContextEM (a0) - Pointer to the EM mode Context registers that map iA mode FP regs.
//      iAFpArea(a1)   - Pointer to area to store 8 * 10 byte iA mode FP regs. 
//      alignedFp(a2)  - FLOAT128 work area (aligned on 16 byte boundry).
//
// Return Value:
//
//    None.
//
// N.B. The format iA mode FP registers is 80 bits and will not change.
//
//--

        LEAF_ENTRY(RtlIaFpToEmFpContext)
         
        add         t0 = 8, a0              // iA Fp Save Area Pointer
        add         t5 = -8, r0             // Need to convert 8 iA mode FP Regs
        ;;
         
cvtIaFp:         
        add         t8 = -4, r0             // Need to load 2 bytes 4 times
        ld2         t3 = [t0], -2           // load exponent and sign
        ;;
        add         t4 = 0, t3              // copy of exponent and sign
        ;;

        add         t2 = 0, r0
        extr.u      t4 = t4, 15, 49         // get the sign in bit 17
        ;;
        dep         t3 = t4, t3, 17, 1      // just first 16 bits of exponent
         

ldIaFpReg:
        ld2         t6 = [t0], -2           // load 2 bytes of significand 
        adds        t8 = 0x1, t8            // bump loop count
        ;;
        or          t2 = t2, t6             // retain until complete

        cmp.lt      p6, p0 = t8, r0         // done?
        ;;
(p6)    dep.z       t2 = t2, 16, 48         //   no, shift to the next two bytes
(p6)    br.cond.dpnt.few ldIaFpReg          //   no, get next two bytes
        ;;
         
        add         t8 = -4, r0             // Need to store 2 bytes 4 times
        mov         t7 = a2                 // get address of aligned save area
        ;;

alignIaFp:
        st2         [t7] = t2, 2            // save 2 bytes of significand 
        extr.u      t2 = t2, 16, 48         // shift to the next two bytes
        adds        t8 = 0x1, t8            // bump loop count
        ;;

        cmp.lt      p6, p0 = t8, r0         // done?
        add         t6 = 0, t3              // copy of exponent and sign
(p6)    br.cond.dpnt.few alignIaFp          //   maybe
        ;;

        nop.m       0
        extr.u      t6 = t6, 2, 62          // get the sign in bit 15
        ;;
        dep         t3 = t3, t6, 0, 15      // just first 15 bits of exponent
        ;;

        st2         [t7] = t3, 2            // save sign and iA exponent
        ldfe        ft0 = [a2]
        adds        t5 = 0x1, t5            // bump loop count
        ;;

        stfe        [a1] = ft0, CxFltT3 - CxFltT2   // Store value into EM FP Context
        cmp.lt      p6, p7 = t5, r0         // done?
        ;;
(p6)    add         t2 = 0, r0              //   no, reset significand for next

(p6)    add         t0 = 20, t0             //   no, starting at the high end
(p6)    br.cond.dpnt.few cvtIaFp            //   no, get next context record
(p7)    br.ret.sptk brp
        ;;

        LEAF_EXIT(RtlIaFpToEmFpContext)