; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
        SUBT    Generic CPU Specific Definitions

OldOpt  SETA    {OPT}
        OPT     OptNoList+OptNoP1List

 [ :LNOT: :DEF: Included_Hdr_CPU_Generic26
        GBLL    Included_Hdr_CPU_Generic26
Included_Hdr_CPU_Generic26 SETL {TRUE}

; ***********************************
; ***    C h a n g e   L i s t    ***
; ***********************************
;
; Date       Name          Description
; ----       ----          -----------
; 13-Jul-93  JRoach        Created
; 30-Jun-94  AMcC          Restore OPT
; 05-Nov-99  KBracey       Keep an eye on No26bitCode flag

 [ :LNOT: :DEF: Included_Hdr_Machine_Machine
        GET     Hdr:Machine.<Machine>
 ]

        ; Standard register names

r0      RN      0
R0      RN      r0
r1      RN      1
R1      RN      r1
r2      RN      2
R2      RN      r2
r3      RN      3
R3      RN      r3
r4      RN      4
R4      RN      r4
r5      RN      5
R5      RN      r5
r6      RN      6
R6      RN      r6
r7      RN      7
R7      RN      r7
r8      RN      8
R8      RN      r8
r9      RN      9
R9      RN      r9
r10     RN      10
R10     RN      r10
r11     RN      11
R11     RN      r11
r12     RN      12
R12     RN      r12
r13     RN      13
R13     RN      r13
r14     RN      14
R14     RN      r14
r15     RN      15
R15     RN      r15


        ; Special names for the banked registers

r13_usr RN      13
r14_usr RN      14

r8_fiq  RN      8
r9_fiq  RN      9
r10_fiq RN      10
r11_fiq RN      11
r12_fiq RN      12
r13_fiq RN      13
r14_fiq RN      14

r13_irq RN      13
r14_irq RN      14

r13_svc RN      13
r14_svc RN      14


        ; Standard register synonyms

lr      RN      r14                     ; Link Register
LR      RN      r14
lr_usr  RN      r14_usr
lr_fiq  RN      r14_fiq
lr_irq  RN      r14_irq
lr_svc  RN      r14_svc
link    RN      r14
LINK    RN      r14

pc      RN      r15                     ; Program Counter
PC      RN      r15

 [ :LNOT: No26bitCode
psr     RN      r15                     ; Processor Status Register
PSR     RN      r15
 ]


        ; Registers for the ARM Procedure Calling Standard

sl      RN      10
SL      RN      10
fp      RN      11
FP      RN      11
IP      RN      12
ip      RN      12


        ; Condition code symbols

Cond_EQ *       0  :SHL: 28
Cond_NE *       1  :SHL: 28
Cond_CS *       2  :SHL: 28
Cond_HS * Cond_CS
Cond_CC *       3  :SHL: 28
Cond_LO * Cond_CC
Cond_MI *       4  :SHL: 28
Cond_PL *       5  :SHL: 28
Cond_VS *       6  :SHL: 28
Cond_VC *       7  :SHL: 28
Cond_HI *       8  :SHL: 28
Cond_LS *       9  :SHL: 28
Cond_GE *       10 :SHL: 28
Cond_LT *       11 :SHL: 28
Cond_GT *       12 :SHL: 28
Cond_LE *       13 :SHL: 28
Cond_AL *       14 :SHL: 28
Cond_   * Cond_AL
Cond_NV *       15 :SHL: 28

        ; Flag position specifiers for the PSR

N_bit_number    *       31
Z_bit_number    *       30
C_bit_number    *       29
V_bit_number    *       28
I_bit_number    *       27
F_bit_number    *       26


        ; Flag value specifiers for the PSR

N_bit           *       1 :SHL: N_bit_number
Z_bit           *       1 :SHL: Z_bit_number
C_bit           *       1 :SHL: C_bit_number
V_bit           *       1 :SHL: V_bit_number
I_bit           *       1 :SHL: I_bit_number
F_bit           *       1 :SHL: F_bit_number
M_bits          *       2_11


        ; Processor mode values for the PSR

USR_mode        *      2_00
FIQ_mode        *      2_01
IRQ_mode        *      2_10
SVC_mode        *      2_11

ARM_CC_Mask     *   &FC000003           ; Processor condition flags + mode bits


        ; Co_processor number allocations

                        ^       0
ARMCoProc_Reserved      #       1       ;  0, Reserved by Acorn
ARMCoProc_FPU           #       1       ;  1, All floating point systems
ARMCoProc_FPUextra      #       1       ;  2, For extra FP instructions
ARMCoProc_3             #       1       ;  3,
ARMCoProc_4             #       1       ;  4,
ARMCoProc_5             #       1       ;  5,
ARMCoProc_6             #       1       ;  6,
ARMCoProc_OMBRA         #       1       ;  7, Olivetti/Acorn 80x86
ARMCoProc_TestHardware  #       1       ;  8, Acorn
ARMCoProc_9             #       1       ;  9,
ARMCoProc_10            #       1       ; 10,
ARMCoProc_11            #       1       ; 11,
ARMCoProc_12            #       1       ; 12,
ARMCoProc_13            #       1       ; 13,
ARMCoProc_14            #       1       ; 14,
ARMCoProc_CacheControl  #       1       ; 15, Part of the ARM3 CPU


        ; 26 bit processor specific macro definitions

; ************************************************************
; ***  BSR - Branch to subroutine saving R14 on the stack  ***
; ************************************************************
        MACRO
$label  BSR     $dest
$label  Push    R14
        BL      $dest
        Pull    R14
        MEND

 [ No32bitCode
; ************************************************
; ***  CLC - Clear carry flag - will set nzcv  ***
; ************************************************
        MACRO
$label  CLC     $cond
$label  CMN$cond pc, #0
        MEND

; ***********************************************
; ***  CLRPSR - Clear bits in PSR from the    ***
; ***  mask in $bits, using register $regtmp  ***
; ***********************************************
        MACRO
$label  CLRPSR  $bits, $regtmp, $cond, $oldpsr
$label
        [ "$oldpsr" <> ""
        MOV$cond   $oldpsr, pc
        ]
        MVN$cond   $regtmp, #$bits
        TST$cond.P $regtmp, pc
        MEND

; **************************************************
; *** CLRV - Clear overflow flag - will set nzCv ***
; **************************************************
        MACRO
$label  CLRV    $cond
$label  CMP$cond pc, #0
        MEND

; **********************************************************************************
; ***  PHPSEI - Disable IRQs, saving an old interrupt state indicator in a       ***
; ***  register, default R14.  Note that this code preserves the C and V flags.  ***
; **********************************************************************************
        MACRO
$label  PHPSEI  $register=R14, $regtmp  ; (we don't use regtmp, 32-bit one does)
        LCLS    usereg
  [     "$register" = ""
usereg  SETS    "R14"
  |
usereg  SETS    "$register"
  ]
$label  MOV     $usereg, #I_bit
        TST     $usereg, PC             ; is I_bit set ?
        TEQEQP  $usereg, PC             ; no, then set it (and $register = I_bit)
        MOVNE   $usereg, #0             ; yes, then leave alone (and $register = 0)
        MEND

; **************************************************************************
; ***  PLP - Restore IRQ state from the indicator in a register (set up  ***
; ***  by PHPSEI).  Note that this code preserves the C and V flags.     ***
; **************************************************************************
        MACRO
$label  PLP     $register=R14
        LCLS    usereg
  [     "$register" = ""
usereg  SETS    "R14"
  |
usereg  SETS    "$register"
  ]
$label  TEQP    $usereg, PC
        MEND
 ]

; ****************
; ***  RETURN  ***
; ****************
        MACRO
$label  RETURN  $cond
$label  MOV$cond pc, lr
        MEND

; *****************
; ***  RETURNS  ***
; *****************
        MACRO
$label  RETURNS $cond, $nowarn
 [ "$nowarn"=""
 ! 0, "RETURNS macro indicates possible 32-bit incompatibility", 1
 ]
$label  MOV$cond.S pc, lr
        MEND

 [ No32bitCode
; ******************
; ***  RETURNVC  ***
; ******************
        MACRO
$label  RETURNVC  $cond
$label  BIC$cond.S pc, lr, #V_bit
        MEND

; ******************
; ***  RETURNVS  ***
; ******************
        MACRO
$label  RETURNVS  $cond
$label  ORR$cond.S pc, lr, #V_bit
        MEND

; ****************************************************
; ***  SavePSR - Save the PSR in a register, to be ***
; ***  restored later using RestorePSR             ***
; ****************************************************
        MACRO
$label  SavePSR  $reg, $cond
$label  MOV$cond $reg, pc
        MEND

; ****************************************************
; ***  RestPSR - Restore the PSR from a register   ***
; ***  set up by SavePSR                           ***
; ***  $fields may be set to "f" if the PSR fields ***
; ***  c,x,s do not need restoring, which will     ***
; ***  save a few cycles on newer ARMs (but the    ***
; ***  No32bitCode version of the macro will set   ***
; ***  the c field anyway). Values other than "f", ***
; ***  "cf", "fc" and unset are deprecated for     ***
; ***  compatibility with No32bitCode.             ***
; ****************************************************
        MACRO
$label  RestPSR    $reg, $cond, $fields
  [ "$fields"<>"" :LAND: "$fields"<>"cf" :LAND: "$fields"<>"fc" :LAND: "$fields"<>"f"
        !       0, "Unpredictable behaviour due to deprecated RestPSR fields parameter"
  ]
$label  TEQ$cond.P pc, $reg
  [ NoARMa :LAND: "$fields"<>"f"
        ; Assume mode may be changing, emit NOP for ARM2
        ! 0, "RestPSR inserting NOP for ARM2 TEQP bug", 1
        NOP
  ]
        MEND

; ****************************************************
; ***  SCPSR - Set and clear bits in PSR from the  ***
; ***  masks $set, $clr, using register $regtmp    ***
; ****************************************************
        MACRO
$label  SCPSR   $set, $clr, $regtmp, $cond, $oldpsr
        LCLS    srcreg
        [ "$oldpsr"=""
srcreg  SETS    "$regtmp"
        |
srcreg  SETS    "$oldpsr"
        ]
        [ (($set) :AND: ($clr)) <> 0
        ! 1, "Attempt to simultaneously set and clear a bit in SCPSR"
        ]
$label
    [ (($set) :OR: ($clr)) = ARM_CC_Mask
      [ "$oldpsr" <> ""
        MOV$cond   $oldpsr, pc
      ]
        TEQ$cond.P pc, #$set            ; All change, so skip the clear operation
    |
        MOV$cond   $srcreg, pc
        ORR$cond   $regtmp, $srcreg, #($set) :OR: ($clr)
        TEQ$cond.P $regtmp, #$clr
    ]
    [ NoARMa :LAND: ((($set) :OR: ($clr)) :AND: M_bits) <> 0
        ! 0, "SCPSR inserting NOP for ARM2 TEQP bug", 1
        NOP
    ]
        MEND

; **********************************************
; ***  SEC - Set carry flag - will set nzCv  ***
; **********************************************
        MACRO
$label  SEC     $cond
$label  CMP$cond pc, #0
        MEND

; ************************************************
; ***  SETPSR - Set bits in PSR from the mask  ***
; ***  in $bits, using register $regtmp        ***
; ************************************************
        MACRO
$label  SETPSR  $bits, $regtmp, $cond, $oldpsr
        LCLS    srcreg
        [ "$oldpsr"=""
srcreg  SETS    "$regtmp"
        |
srcreg  SETS    "$oldpsr"
        ]
$label  MOV$cond   $srcreg, pc
        ORR$cond   $regtmp, $srcreg, #$bits
        TEQ$cond.P $regtmp, #0
    [ NoARMa :LAND: (($bits) :AND: M_bits) <> 0
        ! 0, "SETPSR inserting NOP for ARM2 TEQP bug", 1
        NOP
    ]
        MEND

; **************************************************
; ***  SETV - Set overflow flag - will set NzcV  ***
; **************************************************
        MACRO
$label  SETV    $cond
$label  CMP$cond pc, #&80000000
        MEND

; ***********************************************
; ***  TOGPSR - Toggle bits in PSR from the   ***
; ***  mask in $bits, using register $regtmp  ***
; ***********************************************
        MACRO
$label  TOGPSR  $bits, $regtmp, $cond, $oldpsr
        LCLS    srcreg
        [ "$oldpsr"=""
srcreg  SETS    "$regtmp"
        |
srcreg  SETS    "$oldpsr"
        ]
$label  MOV$cond   $srcreg, pc
        TEQ$cond.P $srcreg, #$bits
    [ NoARMa :LAND: (($bits) :AND: M_bits) <> 0
        ! 0, "TOGPSR inserting NOP for ARM2 TEQP bug", 1
        NOP
    ]
        MEND

; ***********************************************
; ***  TOGPSRR - Toggle bits in PSR from the  ***
; ***  mask in $regtog, using reg $regtmp     ***
; ***********************************************
        MACRO
$label  TOGPSRR $regtog, $regtmp, $cond, $oldpsr, $fields
        [ "$oldpsr"<>""
$label  MOV$cond   $oldpsr, pc
        TEQ$cond.P $regtog, pc
        |
$label  TEQ$cond.P $regtog, pc
        ]
    [ NoARMa
        ! 0, "TOGPSRR inserting NOP for ARM2 TEQP bug", 1
        NOP
    ]
        MEND

; ***************************************************
; ***  WritePSRc - Set the PSR control bits to    ***
; ***  an absolute value.                         ***
; ***  Sets I,F,M[0:3], corrupts NZVC.            ***
; ***  Preserves 32-bitness. Ignored in USR mode. ***
; ***  PSR is specified as 26bit form, so only    ***
; ***  USR/IRQ/FIQ/SVC can be used as dest mode,  ***
; ***  but source can be any non-USR mode         ***
; ***  (M[2:3] will be cleared)                   ***
; ***  Use instead of TEQP PC,#$value             ***
; ***************************************************
        MACRO
$label  WritePSRc $value, $regtmp, $cond, $oldpsr
      [ ($value :AND::NOT: (I_bit+F_bit+SVC_mode)) <> 0
        ! 1, "Illegal flags for WritePSRc"
      ]
$label
 [ "$oldpsr" <> ""
        SavePSR $oldpsr, $cond
 ]
        TEQ$cond.P PC, #$value
    [ NoARMa
        ! 0, "WritePSRc inserting NOP for ARM2 TEQP bug", 1
        NOP
    ]
        MEND

 ] ; No32bitCode

; *************************************************
; ***  RemovePSRFromReg - remove PSR bits from  ***
; ***  a PC (or register holding a PC, eg. lr)  ***
; ***  Preserves all PSR bits                   ***
; *************************************************
        MACRO
$label  RemovePSRFromReg $pcr, $tmp, $dest
        ; If $dest is supplied, it denotes an alternative target
        ; register from $pcr.  $dest and $tmp may be the same register.
        ;
        ; MRS is safe as it is a NOP if the processor doesn't understand it. The code
        ; takes bit 4 of the CPSR (always set in 32-bit modes, always clear in 26-bit
        ; modes), shifts it to the bottom bit and inverts it, then shifts it to the
        ; top bit so it can use ASR to duplicate it into 8 bits, and then ROR#30 to
        ; turn it into &FC000003 if you are in a 26-bit bit, 0 if you are in 32-bit
        ; mode. This value can be BIC'ed with lr to strip the PSR bits if they are
        ; there, or be a NOP if they are not.
        ;
        ; Must be in a known mode (currently USR26,USR32,IRQ26,IRQ32,FIQ26,FIQ32,
        ; SVC26,SVC32,ABT32,UND32,SYS32) - future modes may have bit 4 clear, yet
        ; they won't be 26-bit.
        ASSERT (1 :SHL: 4) = (USR32_mode - USR26_mode)
$label
        LCLS    dst
        [ "$dest" <> ""
dst SETS "$dest"
        |
dst SETS "$pcr"
        ]
        [ No32bitCode
        BIC     $dst, $pcr, #ARM_CC_Mask  ; 32-bit OK: inside No32bitCode macro
        |
        [ No26bitCode
        [ $dst <> $pcr
        MOV     $dst, $pcr
        ]
        |
        [ NoARMv3
        MOV     $tmp, #0
        ]
        MRS     $tmp, CPSR
        MVN     $tmp, $tmp, LSR #4        ; bit 0 set in *26, clear in *32
        MOV     $tmp, $tmp, LSL #31       ; shift to top bit
        MOV     $tmp, $tmp, ASR #7        ; duplicate to top 8 bits
        BIC     $dst, $pcr, $tmp, ROR #30 ; remove PSR bits if in 26-bit mode
        ]
        ]
        MEND


 ] ; :LNOT: :DEF: Included_Hdr_CPU_Generic26

        OPT     OldOpt
        END

