; ARM6 PSR transfer macros

; 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

; New positions of I and F bits in 32-bit PSR

I32_bit *       1 :SHL: 7
F32_bit *       1 :SHL: 6
IF32_26Shift *  26-6

; Processor mode numbers

USR26_mode      *       2_00000
FIQ26_mode      *       2_00001
IRQ26_mode      *       2_00010
SVC26_mode      *       2_00011
USR32_mode      *       2_10000
FIQ32_mode      *       2_10001
IRQ32_mode      *       2_10010
SVC32_mode      *       2_10011
ABT32_mode      *       2_10111
UND32_mode      *       2_11011

; New register names

r13_abort       RN      13
r14_abort       RN      14
lr_abort        RN      14

r13_undef       RN      13
r14_undef       RN      14
lr_undef        RN      14

        MACRO
        mrs     $cond, $rd, $psrs
        LCLA    psrtype
psrtype SETA    -1
 [ "$psrs" = "CPSR" :LOR: "$psrs" = "CPSR_all"
psrtype SETA    0 :SHL: 22
 ]
 [ "$psrs" = "SPSR" :LOR: "$psrs" = "SPSR_all"
psrtype SETA    1 :SHL: 22
 ]
        ASSERT  psrtype <> -1
        ASSERT  $rd <> 15
        &       Cond_$cond :OR: 2_00000001000011110000000000000000 :OR: psrtype :OR: ($rd :SHL: 12)
        MEND

        MACRO
        msr     $cond, $psrl, $op2a, $op2b
        LCLA    psrtype
        LCLS    op2as
        LCLA    op
        LCLA    shift
psrtype SETA    -1
 [ "$psrl" = "CPSR" :LOR: "$psrl" = "CPSR_all"
psrtype SETA    (0:SHL:22) :OR: (1:SHL:19) :OR: (1:SHL:16)
 ]
 [ "$psrl" = "CPSR_flg"
psrtype SETA    (0:SHL:22) :OR: (1:SHL:19) :OR: (0:SHL:16)
 ]
 [ "$psrl" = "CPSR_ctl"
psrtype SETA    (0:SHL:22) :OR: (0:SHL:19) :OR: (1:SHL:16)
 ]
 [ "$psrl" = "SPSR" :LOR: "$psrl" = "SPSR_all"
psrtype SETA    (1:SHL:22) :OR: (1:SHL:19) :OR: (1:SHL:16)
 ]
 [ "$psrl" = "SPSR_flg"
psrtype SETA    (1:SHL:22) :OR: (1:SHL:19) :OR: (0:SHL:16)
 ]
 [ "$psrl" = "SPSR_ctl"
psrtype SETA    (1:SHL:22) :OR: (0:SHL:19) :OR: (1:SHL:16)
 ]
        ASSERT  psrtype <> -1
 [ ("$op2a" :LEFT: 1) = "#"
 ; Immediate operand

op2as   SETS    "$op2a" :RIGHT: ((:LEN: "$op2a")-1)
op      SETA    $op2as

  [ "$op2b" = ""
  ; Rotate not specified in immediate operand
shift   SETA    0
        WHILE   (op :AND: &FFFFFF00)<>0 :LAND: shift<16
op      SETA    ((op:SHR:30):AND:3):OR:(op:SHL:2)
shift   SETA    shift + 1
        WEND
        ASSERT  (op :AND: &FFFFFF00)=0
  |
  ; Rotate of immediate operand specified explicitly
        ASSERT  (($op2b):AND:&FFFFFFE1)=0
shift   SETA    ($opt2b):SHR:1
  ]
op      SETA    (shift :SHL: 8) :OR: op :OR: (1:SHL:25)
 |

 ; Not an immediate operand
  [ "$op2b" = ""
  ; Unshifted register
op      SETA    ($op2a) :OR: (0:SHL:25)
  |
        ! 1, "Shifted register not yet implemented in this macro!"
  ]
 ]
        &       Cond_$cond :OR: 2_00000001001000001111000000000000 :OR: op :OR: psrtype
        MEND

; SetMode newmode, reg1, regoldpsr
;
; Sets processor mode to constant value newmode
; using register reg1 as a temporary.
; If regoldpsr is specified, then this register
; on exit holds the old PSR before the mode change
; reg1 on exit always holds the new PSR after the mode change

;        MACRO
;        SetMode $newmode, $reg1, $regoldpsr
; [ "$regoldpsr"=""
;        mrs     AL, $reg1, CPSR_all
;        BIC     $reg1, $reg1, #&1F
;        ORR     $reg1, $reg1, #$newmode
;        msr     AL, CPSR_all, $reg1
; |
;        mrs     AL, $regoldpsr, CPSR_all
;        BIC     $reg1, $regoldpsr, #&1F
;        ORR     $reg1, $reg1, #$newmode
;        msr     AL, CPSR_all, $reg1
; ]
;        MEND

        MACRO
        mrc     $cond, $coproc, $op, $rd, $crn, $crm, $info
        &       Cond_$cond :OR: 2_00001110000100000000000000010000 :OR: ($coproc :SHL: 8) :OR: ($op :SHL: 21) :OR: ($rd :SHL: 12) :OR: ($crn :SHL: 16) :OR: $crm :OR: ($info :SHL: 5)
        MEND

        MACRO
        mcr     $cond, $coproc, $op, $rd, $crn, $crm, $info
        &       Cond_$cond :OR: 2_00001110000000000000000000010000 :OR: ($coproc :SHL: 8) :OR: ($op :SHL: 21) :OR: ($rd :SHL: 12) :OR: ($crn :SHL: 16) :OR: $crm :OR: ($info :SHL: 5)
        MEND

	END