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

; fpe.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     defaults.asm
        GET     callcode.asm
        GBLL    FPEWanted
        GBLL    FPASCWanted
        GBLL    EnableInterrupts
        GBLA    CoreDebugging

FPEWanted       SETL    {FALSE}
FPASCWanted     SETL    {FALSE}
EnableInterrupts        SETL    {FALSE}
CoreDebugging   SETA    0


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

; 
; Allow some control over the code/speed of code produced.
; 0 = fastest -> 2 = smallest (overall)
; 

        GBLA    CodeSize
CodeSize        SETA    0

        MACRO
        ImportCodeSize $name
        [ CodeSize <> 0
        IMPORT  $name
        ]
        MEND

        MACRO
        ExportCodeSize $name
        [ CodeSize <> 0
        EXPORT  $name
        ]
        MEND

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

        MACRO
$label  CDebug4 $level,$message,$reg1,$reg2,$reg3,$reg4
        MEND
        MACRO
$label  CDebug3 $level,$message,$reg1,$reg2,$reg3
        MEND
        MACRO
$label  CDebug2 $level,$message,$reg1,$reg2
        MEND
        MACRO
$label  CDebug1 $level,$message,$reg1
        MEND
        MACRO
$label  CDebug0 $level,$message
        MEND

; File for setting up THUMB macros for entry and exit from the THUMB
; versions of the functions.

        GBLA    V_N

        [ :DEF: thumb

        MACRO
$label  VEnter_16               ; Like VEnter, but declare __16$label as the
        CODE16                  ; THUMB entry point
__16$label
        BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
$label  STMFD   r13!,veneer_s   ; ARM is the declared entry point
        MEND

        MACRO
$label  VEnter                  ; Declare the THUMB entry point as the main
        CODE16                  ; entry point
$label  BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
__32$label                      ; Declare a __32$label entry point for ARM
        STMFD   r13!,veneer_s
        MEND

        MACRO
$label  VReturn $cc
$label  LDM$cc.FD r13!,veneer_s
        BX$cc   lr
        MEND

        MACRO
$label  VPull $cc
$label  LDM$cc.FD r13!,veneer_s
        MEND

        MACRO
$label  ReturnToLR $cc
$label  BX$cc   lr
        MEND

        MACRO
$label  ReturnToLR_flg $cc
$label  BX$cc   lr
        MEND

        MACRO
$label  ReturnToStack $cc
$label  LDM$cc.FD sp!,{lr}
        BX$cc   lr
        MEND

        MACRO
$label  PullFromStack $cc
$label  LDM$cc.FD sp!,{lr}
        MEND

        MACRO
$label  EnterWithLR_16
        CODE16
__16$label
        BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
$label
        MEND

        MACRO
$label  EnterWithStack_16
        CODE16
__16$label
        BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
$label  STMFD   sp!,{lr}
        MEND

        MACRO
$label  EnterWithLR
        CODE16
$label  BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
__32$label
        MEND

        MACRO
$label  EnterWithStack
        CODE16
$label  BX      pc
        CODE32
V_N     SETA    V_N+1
        LCLS    f_lab
f_lab   SETS    "|":CC:"$F":CC::STR:V_N:CC:"|"
        KEEP    $f_lab
$f_lab
__32$label
        STMFD   sp!,{lr}
        MEND
        
        MACRO
        Export $name
        EXPORT  $name
        EXPORT  __16$name
        MEND

        MACRO
        Export_32 $name
        EXPORT  __32$name
        EXPORT  $name
        MEND

        MACRO
        Import_32 $name
        IMPORT __32$name
        MEND

        MACRO
$label  B_32 $name
$label  B       __32$name
        MEND

        |

;ARM 32 and 26-bit mode

        MACRO
$label  VEnter_16
$label  STMFD   r13!,veneer_s
        MEND

        MACRO
$label  VEnter
$label  STMFD   r13!,veneer_s
        MEND

        MACRO
$label  VReturn $cc
$label  [ Interworking :LOR: Thumbing
        LDM$cc.FD r13!,veneer_s
        BX$cc   lr
        |
        [ {CONFIG} = 32 
        LDM$cc.FD r13!,veneer_l
        ]
        [ {CONFIG} = 26
        LDM$cc.FD r13!,veneer_l^
        ]
        ]
        MEND    

        MACRO
$label  VPull $cc
$label  LDM$cc.FD r13!,veneer_s
        MEND

        MACRO
$label  ReturnToLR $cc
$label  [ Interworking :LOR: Thumbing
        BX$cc   lr
        |
        [ {CONFIG} = 32
        MOV$cc  pc,lr
        ]
        [ {CONFIG} = 26
        MOV$cc.S pc,lr
        ]
        ]
        MEND

        MACRO
$label  ReturnToLR_flg $cc
$label  [ Interworking :LOR: Thumbing
        BX$cc   lr
        |
        MOV$cc  pc,lr
        ]
        MEND

        MACRO
$label  ReturnToStack $cc
$label  [ Interworking :LOR: Thumbing
        LDM$cc.FD sp!,{lr}
        BX$cc    lr
        |
        [ {CONFIG} = 32
        LDM$cc.FD sp!,{pc}
        ]
        [ {CONFIG} = 26
        LDM$cc.FD sp!,{pc}^
        ]
        ]
        MEND

        MACRO
$label  PullFromStack $cc
$label  LDM$cc.FD sp!,{lr}
        MEND

        MACRO
$label  EnterWithLR_16
$label
        MEND

        MACRO
$label  EnterWithStack_16
$label  STMFD   sp!,{lr}
        MEND

        MACRO
$label  EnterWithLR
$label
        MEND

        MACRO
$label  EnterWithStack
$label  STMFD   sp!,{lr}
        MEND

        MACRO
        Export $name
        EXPORT  $name
        MEND

        MACRO
        Export_32 $name
        EXPORT  $name
        MEND

        MACRO
        Import_32 $name
        IMPORT $name
        MEND

        MACRO
$label  B_32 $name
$label  B       $name
        MEND

        ]

        MACRO
        CodeArea $name
;; $name will be a name for the area. However for a release we'll use
;; C$$code instead
        [ Interworking
	AREA   |.text|, CODE, READONLY
        |
	AREA   |.text|, CODE, READONLY
        ]
        MEND

        GET     regnames.asm
        GET     armdefs.asm
        GET     fpadefs.asm
        GET     macros.asm

sp      RN      R13
lr      RN      R14
pc      RN      R15

dOP1h   RN      R1      ;Double OP1 hi-reg ("First word") - sign,expn,etc.
dOP1l   RN      R0      ;Double OP1 lo-reg ("Second word")
dOPh    RN      R1      ;Double OP hi-reg (unary ops)
dOPl    RN      R0      ;Double OP lo-reg
dOP2h   RN      R3      ;Double OP2 hi-reg ("First word")
dOP2l   RN      R2      ;Double OP2 lo-reg ("Second word")

fOP1    RN      R0      ;Float OP1
fOP     RN      R0      ;Float OP for unary ops
fOP2    RN      R1      ;Float OP2

utmp1   RN      R2      ;Temporary register fo unary operations
utmp2   RN      R3      ;    "

ip      RN      R12
tmp     RN      R12     ;A temporary register

SignBit         EQU     &80000000
fSignalBit      EQU     &00400000
dSignalBit      EQU     &00080000
w_oSignBit      EQU     &7fffffff
w_ofSignalBit    EQU     &ffbfffff
w_odSignalBit    EQU     &fff7ffff
Internal_mask   EQU     &00000000
Single_pos      EQU     0
Double_pos      EQU     1
Single_mask     EQU     1:SHL:Single_pos
Double_mask     EQU     1:SHL:Double_pos
Reverse         EQU     0x4     ; Used to signal a reverse divide

;;Error flags - an extension to the normal internal format

Error_pos       EQU     29
Error_bit       EQU     1:SHL:Error_pos

Except_len      EQU     5
Except_pos      EQU     Error_pos-Except_len

        ASSERT  IOC_pos < DZC_pos
        ASSERT  DZC_pos < OFC_pos
        ASSERT  OFC_pos < UFC_pos
        ASSERT  UFC_pos < IXC_pos
FPExceptC_pos   EQU     IOC_pos
        ASSERT  IOE_pos < DZE_pos
        ASSERT  DZE_pos < OFE_pos
        ASSERT  OFE_pos < UFE_pos
        ASSERT  UFE_pos < IXE_pos
FPExceptE_pos   EQU     IOE_pos


; Following fields are used to identify the originator function and the return type so that the
; error handler can return the correct value.

;;
;;  All fields and values must agree with C headers and programs.
;;
;;  r12 (defined as ip above) is used to pass information about the operation being performed
;;  to the exception handler.  The bit fields are defined as follows.
;;
;;   31                             0
;;  +--------------------------------+
;;  |                                |
;;  +--------------------------------+
;;
;;  Bits   Meaning
;;  ~~~~   ~~~~~~~
;;  31     unused
;;  30     Uncommon (possible exceptional case -- requires more checking)
;;  29     Error (exceptional case)
;;  28:25  unused
;;  24:20  Operation code (must agree with enumerated type in fpraise.c)
;;  19:5   unused
;;   4     Exception cause: Inexact   (must agree with float.h)
;;   3     Exception cause: Underflow
;;   2     Exception cause: Overflow
;;   1     Exception cause: Zero Divide
;;   0     Exception cause: Invalid Operation
;;


;;
;;  Operation code defines.  These must match with the FP_CODE enumerated
;;  type in fpraise.c.
;;
Fn_pos          EQU     20               ;; Function (operation) code position
Fn_mask         EQU     31 << Fn_pos     ;; Mask for the field

_FpAddD         EQU     ( 0 << Fn_pos)   ;; Add Double
_FpAddS         EQU     ( 1 << Fn_pos)   ;; Add Single
_FpSubD         EQU     ( 2 << Fn_pos)   ;; Subtract Double
_FpSubS         EQU     ( 3 << Fn_pos)   ;; Subtract Single
_FpCmpD         EQU     ( 4 << Fn_pos)   ;; Compare Double
_FpCmpS         EQU     ( 5 << Fn_pos)   ;; Compare Single
_FpDivD         EQU     ( 6 << Fn_pos)   ;; Divide Double
_FpDivS         EQU     ( 7 << Fn_pos)   ;; Divide Single
_FpDToI         EQU     ( 8 << Fn_pos)   ;; Convert Double To int
_FpDToI64       EQU     ( 9 << Fn_pos)   ;; Convert Double To __int64
_FpDToS         EQU     (10 << Fn_pos)   ;; Convert Double To Single
_FpDToU         EQU     (11 << Fn_pos)   ;; Convert Double To unsigned int
_FpDToU64       EQU     (12 << Fn_pos)   ;; Convert Double To unsigned __int64
_FpIToS         EQU     (13 << Fn_pos)   ;; Convert int To Single
_FpMulD         EQU     (14 << Fn_pos)   ;; Multiply Double
_FpMulS         EQU     (15 << Fn_pos)   ;; Multiply Single
_FpSToD         EQU     (16 << Fn_pos)   ;; Convert Single To Double
_FpSToI         EQU     (17 << Fn_pos)   ;; Convert Single To int
_FpSToI64       EQU     (18 << Fn_pos)   ;; Convert Single To __int64
_FpSToU         EQU     (19 << Fn_pos)   ;; Convert Single To unsigned int
_FpSToU64       EQU     (20 << Fn_pos)   ;; Convert Single To unsigned __int64
_FpUToS         EQU     (21 << Fn_pos)   ;; Convert unsigned int To Single
_FpI64ToD       EQU     (22 << Fn_pos)   ;; Convert __int64 To Double
_FpI64ToS       EQU     (23 << Fn_pos)   ;; Convert __int64 To Single
_FpU64ToD       EQU     (24 << Fn_pos)   ;; Convert unsigned __int64 To Double
_FpU64ToS       EQU     (25 << Fn_pos)   ;; Convert unsigned __int64 To Single
_FpRndD         EQU     (26 << Fn_pos)   ;; Round to double integer


;; FP Exception Causes (must agree with fpraise.c FPExInfo)
;; Note that this is modelled after the ARM 7500FE FPSR Cumulative exception
;; flags byte.  The semantics here are slightly different.  If a bit is set
;; here, it means that the corresponding exception occurred during the current
;; FP operation.  If a bit is clear, it means that the corresponding exception
;; did not occur during the current FP operation.  The bits are set regardless
;; of which exceptions are enabled, etc.  Raising exceptions, checking enabled
;; exceptions, and updating status and cause bits is done in fpraise.c which
;; maintains the "true" FPSCR.
INX_bit         EQU     (1 << 4)      ;; Inexact
UNF_bit         EQU     (1 << 3)      ;; Underflow
OVF_bit         EQU     (1 << 2)      ;; Overflow
DVZ_bit         EQU     (1 << 1)      ;; Zero Divide
IVO_bit         EQU     (1 << 0)      ;; Invalid Operation
FPECause_mask   EQU     (INX_bit :OR: \
                         UNF_bit :OR: \
                         OVF_bit :OR: \
                         DVZ_bit :OR: \
                         IVO_bit )


INX_bits         EQU     (INX_bit)
UNF_bits         EQU     (UNF_bit :OR: INX_bit)
OVF_bits         EQU     (OVF_bit :OR: INX_bit)
DVZ_bits         EQU     (DVZ_bit)
IVO_bits         EQU     (IVO_bit)


;; FP compare values from fpieee.h _FPIEEE_COMPARE_RESULT
;; These are used for the exception handler.
_FpCompareEqual      EQU   0
_FpCompareGreater    EQU   1
_FpCompareLess       EQU   2
_FpCompareUnordered  EQU   3



Double_bit      EQU     ((1 << 18) :AND:0)         ;; RDCFix: Get rid of this and fix what it breaks.
LongLong_bit    EQU     ((1 << 18) :AND:0)         ;; RDCFix: Get rid of this and fix what it breaks.

EDOM            EQU     1                          ;; RDCFix: Need this?
ERANGE          EQU     2                          ;; RDCFix: Need this?
ESIGNUM         EQU     3                          ;; RDCFix: Need this?

veneer_s        RLIST   {r4-r9,r11,lr}
veneer_l        RLIST   {r4-r9,r11,pc}


;; Macro to do a load immediate of an arbitrary whole word.
    MACRO
    LWI $cc, $reg, $imm
    MOV$cc $reg, #(($imm) :AND: 0x000000FF)
    ORR$cc $reg, $reg, #(($imm) :AND: 0x0000FF00)
    ORR$cc $reg, $reg, #(($imm) :AND: 0x00FF0000)
    ORR$cc $reg, $reg, #(($imm) :AND: 0xFF000000)
    MEND





        END
