Commit 71306206 authored by Jeffrey Lee's avatar Jeffrey Lee

Add new PSR manipulation macros, optimised for 32bit machines

Detail:
  Many of our existing PSR manipulation macros (specifically, ones used for changing mode or controlling interrupts) are based around the code sequences you'd typically use on a 26bit system. Although this has worked well in terms of producing a 32bit version of the OS, it's also left us with macros that can be sub-optimal for 32bit machines, or are inconvenient to use due to the potential of corrupting other PSR flags
  This change adds a new set of macros which are designed and optimised for 32bit-only targets, but can still fall back to 26/32bit neutral or 26bit-only configurations
  hdr/CPU/Generic32:
  - Add the new macros (SEI, CLI, SetModeSEI, SetModeCLI & variants).
  - Improve existing SetMode macro to add 26bit compatibility, and to add an extra optimisation for pre-ARMv6 (emit single MSR if IRQ state is known)
  - Improve SCPSR to allow the source mode to be any 32bit mode
  - Fix conditional 26bit/32bit neutral SCPSR - the 32bit check TEQ corrupts NZCV so we can't do conditional execution on $cond after it (and we've already branched on the opposite condition anyway)
  - Fix 26bit/32bit neutral SCPSR to preserve NZCV when following the MSR code path
  - Make CLRPSR and SETPSR just call through to SCPSR - in terms of output the first two have no advantages over SCPSR
  - Update WritePSRc documentation to reflect that it can now be used in any (non-USR) source mode
  hdr/CPU/Generic26:
  - Update WritePSRc documentation to match Generic32
Admin:
  Tested on Raspberry Pi
  Output of new macros manually checked for various machine types (RPi, Tungsten, All, 26)


Version 2.65. Tagged as 'HdrSrc-2_65'
parent 15c9ad3f
/* (2.64)
/* (2.65)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 2.64
#define Module_MajorVersion_CMHG 2.65
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 05 Jun 2016
#define Module_Date_CMHG 12 Jun 2016
#define Module_MajorVersion "2.64"
#define Module_Version 264
#define Module_MajorVersion "2.65"
#define Module_Version 265
#define Module_MinorVersion ""
#define Module_Date "05 Jun 2016"
#define Module_Date "12 Jun 2016"
#define Module_ApplicationDate "05-Jun-16"
#define Module_ApplicationDate "12-Jun-16"
#define Module_ComponentName "HdrSrc"
#define Module_ComponentPath "castle/RiscOS/Sources/Programmer/HdrSrc"
#define Module_FullVersion "2.64"
#define Module_HelpVersion "2.64 (05 Jun 2016)"
#define Module_LibraryVersionInfo "2:64"
#define Module_FullVersion "2.65"
#define Module_HelpVersion "2.65 (12 Jun 2016)"
#define Module_LibraryVersionInfo "2:65"
......@@ -448,15 +448,17 @@ $label TEQ$cond.P $regtog, pc
]
MEND
; *************************************************
; *** WritePSRc - Set the PSR control bits to ***
; *** an absolute value. ***
; *** Sets I,F,M[0:1], corrupts NZVC. ***
; *** Preserves 32-bitness. ***
; *** Only use in IRQ26/32,FIQ26/32,SVC26/32 ***
; *** Ignored in USR modes, illegal in others ***
; *** Use instead of TEQP PC,#$value ***
; *************************************************
; ***************************************************
; *** 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
......
......@@ -93,14 +93,33 @@ r13_und RN 13
r14_und RN 14
lr_und RN 14
[ :LNOT: No32bitCode
; 32 bit versions of the macros in Generic26
GBLA CPU32_bits
GBLA CPU32_set
GBLA CPU32_clr
; ***************************************************
; *** IFto32 - Convert I/F/IF/FI string to ***
; *** I32_bit+F32_bit flags in variable psr32 ***
; ***************************************************
MACRO
$psr32 IFto32 $if
LCLS upper
upper SETS :UPPERCASE: "$if"
[ "$upper" = "I"
$psr32 SETA I32_bit
ELIF "$upper" = "F"
$psr32 SETA F32_bit
ELIF "$upper" = "IF" :LOR: "$upper" = "FI"
$psr32 SETA I32_bit+F32_bit
|
! 1, "Unsupported interrupt flags"
]
MEND
[ :LNOT: No32bitCode
; 32 bit versions of the macros in Generic26
; ***************************************************
; *** PSRto32 - Convert a PSR constant to a ***
; *** 32-bit PSR value in variable psr32 ***
......@@ -140,49 +159,7 @@ $label MSR$cond CPSR_f, #0
; ***********************************************
MACRO
$label CLRPSR $bits, $regtmp, $cond, $oldpsr
LCLS srcreg
[ "$oldpsr"=""
srcreg SETS "$regtmp"
|
srcreg SETS "$oldpsr"
]
CPU32_bits PSRto32 $bits ; Map to 32 bit PSR
[ NoARMv3
$label
[ "$cond"<>"" :LAND: "$cond"<>"AL"
LCLS rcc
rcc SETS :REVERSE_CC:"$cond"
B$rcc %FT02 ; Go round when $cond-itional
]
MOV $srcreg, pc ; Snapshot 26-bit PSR
MRS $srcreg, CPSR ; Snapshot 32-bit PSR, or NOP pre ARMv3
TEQ r0, r0 ; Set Z
MSR CPSR_f, #0 ; Clear Z if ARMv3 or later
BNE %FT01
BIC $regtmp, $srcreg, #$bits
TEQP $regtmp, #0
B %FT02
01
[ (CPU32_bits :AND: &F0000000) <> 0 :LAND: (CPU32_bits :AND: &F0) <> 0
; Can't be expressed as a single ARM immediate constant
BIC $regtmp, $srcreg, #CPU32_bits :AND: &F0000000
BIC $regtmp, $regtmp, #CPU32_bits :AND: &0FFFFFFF
|
BIC $regtmp, $srcreg, #CPU32_bits
]
somemsr AL, CPSR, $regtmp, CPU32_bits
02
|
$label MRS$cond $srcreg, CPSR
[ (CPU32_bits :AND: &F0000000) <> 0 :LAND: (CPU32_bits :AND: &F0) <> 0
; Can't be expressed as a single ARM immediate constant
BIC$cond $regtmp, $srcreg, #CPU32_bits :AND: &F0000000
BIC$cond $regtmp, $regtmp, #CPU32_bits :AND: &0FFFFFFF
|
BIC$cond $regtmp, $srcreg, #CPU32_bits
]
somemsr $cond, CPSR, $regtmp, CPU32_bits, unsafe
]
$label SCPSR 0, $bits, $regtmp, $cond, $oldpsr
MEND
; **************************************************
......@@ -380,6 +357,10 @@ $label SCPSR $set, $clr, $regtmp, $cond, $oldpsr
LCLS srcreg
CPU32_set PSRto32 $set
CPU32_clr PSRto32 $clr
[ :LNOT: No32bitCode :LAND: ((CPU32_set :OR: CPU32_clr) :AND: 3) <> 0
; If 32bit modes are supported and we're changing mode, make sure we clear bits 2 and 3 of the mode so we can safely switch from ABT/UND/SYS to SVC/IRQ/etc.
CPU32_clr SETA CPU32_clr :OR: 12
]
[ "$oldpsr"=""
srcreg SETS "$regtmp"
|
......@@ -401,34 +382,34 @@ rcc SETS :REVERSE_CC:"$cond"
MSR CPSR_f, #0 ; Clear Z if ARMv3 or later
BNE %FT01
[ (($set) :OR: ($clr)) = ARM_CC_Mask
TEQ$cond.P pc, #$set ; All change, so skip the clear operation
TEQP pc, #$set ; All change, so skip the clear operation
|
ORR$cond $regtmp, $srcreg, #($set) :OR: ($clr)
TEQ$cond.P $regtmp, #$clr
ORR $regtmp, $srcreg, #($set) :OR: ($clr)
TEQP $regtmp, #$clr
]
B %FT02
01
[ (CPU32_set :AND: &F0000000) <> 0 :LAND: (CPU32_set :AND: &F0) <> 0
ORR$cond $regtmp, $srcreg, #CPU32_set :AND: &F0000000
ORR$cond $regtmp, $regtmp, #CPU32_set :AND: &0FFFFFFF
ORR $regtmp, $srcreg, #CPU32_set :AND: &F0000000
ORR $regtmp, $regtmp, #CPU32_set :AND: &0FFFFFFF
srcreg SETS "$regtmp"
|
[ CPU32_set <> 0
ORR$cond $regtmp, $srcreg, #CPU32_set
ORR $regtmp, $srcreg, #CPU32_set
srcreg SETS "$regtmp"
]
]
[ (CPU32_clr :AND: &F0000000) <> 0 :LAND: (CPU32_clr :AND: &F0) <> 0
BIC$cond $regtmp, $srcreg, #CPU32_clr :AND: &F0000000
BIC$cond $regtmp, $regtmp, #CPU32_clr :AND: &0FFFFFFF
BIC $regtmp, $srcreg, #CPU32_clr :AND: &F0000000
BIC $regtmp, $regtmp, #CPU32_clr :AND: &0FFFFFFF
srcreg SETS "$regtmp"
|
[ CPU32_clr <> 0
BIC$cond $regtmp, $srcreg, #CPU32_clr
BIC $regtmp, $srcreg, #CPU32_clr
srcreg SETS "$regtmp"
]
]
somemsr $cond, CPSR, $srcreg, CPU32_set:OR:CPU32_clr, unsafe
somemsr AL, CPSR, $srcreg, CPU32_set:OR:CPU32_clr:OR:&F0000000
02
|
$label MRS$cond $srcreg, CPSR
......@@ -545,49 +526,7 @@ $label MSR$cond CPSR_f, #C_bit
; ************************************************
MACRO
$label SETPSR $bits, $regtmp, $cond, $oldpsr
LCLS srcreg
[ "$oldpsr"=""
srcreg SETS "$regtmp"
|
srcreg SETS "$oldpsr"
]
CPU32_bits PSRto32 $bits ; Map to 32 bit PSR
[ NoARMv3
$label
[ "$cond"<>"" :LAND: "$cond"<>"AL"
LCLS rcc
rcc SETS :REVERSE_CC:"$cond"
B$rcc %FT02 ; Go round when $cond-itional
]
MOV $srcreg, pc ; Snapshot 26-bit PSR
MRS $srcreg, CPSR ; Snapshot 32-bit PSR, or NOP pre ARMv3
TEQ r0, r0 ; Set Z
MSR CPSR_f, #0 ; Clear Z if ARMv3 or later
BNE %FT01
ORR $regtmp, $srcreg, #$bits
TEQP $regtmp, #0
B %FT02
01
[ (CPU32_bits :AND: &F0000000) <> 0 :LAND: (CPU32_bits :AND: &F0) <> 0
; Can't be expressed as a single ARM immediate constant
ORR $regtmp, $srcreg, #CPU32_bits :AND: &F0000000
ORR $regtmp, $regtmp, #CPU32_bits :AND: &0FFFFFFF
|
ORR $regtmp, $srcreg, #CPU32_bits
]
somemsr AL, CPSR, $regtmp, CPU32_bits
02
|
$label MRS$cond $srcreg, CPSR
[ (CPU32_bits :AND: &F0000000) <> 0 :LAND: (CPU32_bits :AND: &F0) <> 0
; Can't be expressed as a single ARM immediate constant
ORR$cond $regtmp, $srcreg, #CPU32_bits :AND: &F0000000
ORR$cond $regtmp, $regtmp, #CPU32_bits :AND: &0FFFFFFF
|
ORR$cond $regtmp, $srcreg, #CPU32_bits
]
somemsr $cond, CPSR, $regtmp, CPU32_bits, unsafe
]
$label SCPSR $bits, 0, $regtmp, $cond, $oldpsr
MEND
; **************************************************
......@@ -691,15 +630,17 @@ $label MRS$cond $srcreg, CPSR
]
MEND
; *************************************************
; *** WritePSRc - Set the PSR control bits to ***
; *** an absolute value. ***
; *** Sets I,F,M[0:1], corrupts NZVC. ***
; *** Preserves 32-bitness. ***
; *** Only use in IRQ26/32,FIQ26/32,SVC26/32 ***
; *** Ignored in USR modes, illegal in others ***
; *** Use instead of TEQP PC,#$value ***
; *************************************************
; ***************************************************
; *** 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
......@@ -893,30 +834,172 @@ op SETA ($op2a) :OR: (0:SHL:25)
]
MEND
; This next group of macros (SetMode, SExx, CLxx, and combinations) are
; optimised for 32bit architectures:
;
; * 32bit-only processor modes (e.g. SYS) are fully supported
; * Except for the T bit (assumed to be 0), only the indicated PSR fields will be touched (e.g. NZCV always preserved)
; * They assemble down to one instruction (CPS or MRS) wherever possible
; * Due to the limits of CPS this means they're all unconditional
; * For the one-instruction MRS form you'll have to provide 'hints' for the current mode/IF bits. But even though you're specifying the mode + interrupt flags, these macros are still better than WritePSRc (for ARMv6+)
; * When building 26/32bit neutral or 26bit-only versions:
; * The saved PSR will be the CPSR if MRS supported, else it's a saved PC (same rules as SavePSR, WritePSRc, etc.)
; * The SetMode macros will preserve the 32bit-ness of the host, unless asked to switch into a 32bit-only mode (e.g. SYS)
;
; Note the side-effects of SEI/SEF/CLI/CLF. The macros assume that if IRQ state
; is being altered, FIQs are enabled, and if FIQ state is being altered, IRQs
; are disabled. This is based on the premise that it's unsafe/unreliable to
; have FIQs disabled while IRQs are enabled (RISC OS generally assumes FIQs are
; enabled, so if you have FIQs disabled but IRQs enabled it would be easy for
; an IRQ handler to come along and do something which enables FIQs).
; ****************************************************
; *** SetMode - sets processor mode to constant ***
; *** value newmode using register regtmp as a ***
; *** temporary. ***
; *** If $irqs is provided it's expected to be the ***
; *** current I32+F32 flags ***
; *** $regtmp only required if 26bit support ***
; *** required, or no $irqs provided. ***
; ****************************************************
MACRO
SetMode $newmode, $regtmp, $oldpsr
[ NoARMv6
[ "$oldpsr"=""
SetMode $newmode, $regtmp, $oldpsr, $irqs
[ :LNOT: NoARMv6
[ "$oldpsr"<>""
MRS $oldpsr, CPSR
]
CPS #$newmode
ELIF No26bitCode :LOR: ($mode > SVC32_mode)
[ "$oldpsr"<>""
MRS $oldpsr, CPSR
]
[ "$irqs" <> ""
MSR CPSR_c, #$newmode + $irqs
ELIF "$oldpsr"=""
MRS $regtmp, CPSR
BIC $regtmp, $regtmp, #M32_bits
ORR $regtmp, $regtmp, #$newmode
MSR CPSR_c, $regtmp
|
MRS $oldpsr, CPSR
BIC $regtmp, $oldpsr, #M32_bits
ORR $regtmp, $regtmp, #$newmode
MSR CPSR_c, $regtmp
MSR CPSR_c, $regtmp
]
|
[ "$oldpsr"<>""
; Use SCPSR for 26/32bit-friendly PSR manipulation
SCPSR ($newmode :AND: 3), ($newmode :AND: 3) :EOR: 3, $regtmp, , $oldpsr
]
MEND
; *************************************************
; *** SEI - Disable IRQs, may enable FIQs ***
; *** SEF - Disable FIQs, may disable IRQs ***
; *** SEIF - Disable IRQs+FIQs ***
; *** If $mode is provided (preferred) then it ***
; *** must be the current 32bit processor mode. ***
; *** $regtmp only required if 26bit support ***
; *** required, or no $mode provided. ***
; *************************************************
MACRO
SE$op $mode, $regtmp, $oldpsr
CPU32_bits IFto32 $op
[ :LNOT: NoARMv6
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
CPS #$newmode
CPSID $op
ELIF ("$mode" <> "") :LAND: (No26bitCode :LOR: (($mode + 0) > SVC32_mode))
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
MSR CPSR_c, #$mode+(CPU32_bits :OR: I32_bit)
|
; Use SETPSR for 26/32bit-friendly PSR manipulation
SETPSR CPU32_bits :SHL: IF32_26Shift, $regtmp, , $oldpsr
]
MEND
; *************************************************
; *** CLI - Enable IRQs, may enable FIQs ***
; *** CLF - Enable FIQs, may disable IRQs ***
; *** CLIF - Enable IRQs+FIQs ***
; *** If $mode is provided (preferred) then it ***
; *** must be the current 32bit processor mode. ***
; *** $regtmp only required if 26bit support ***
; *** required, or no $mode provided. ***
; *************************************************
MACRO
CL$op $mode, $regtmp, $oldpsr
CPU32_bits IFto32 $op
[ :LNOT: NoARMv6
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
CPSIE $op
ELIF ("$mode" <> "") :LAND: (No26bitCode :LOR: (($mode + 0) > SVC32_mode))
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
MSR CPSR_c, #$mode+I32_bit+F32_bit-(CPU32_bits :OR: F32_bit)
|
; Use CLRPSR for 26/32bit-friendly PSR manipulation
CLRPSR CPU32_bits :SHL: IF32_26Shift, $regtmp, , $oldpsr
]
MEND
; ***************************************************************
; *** SetModeSEI - Set mode + disable IRQs, may enable FIQs ***
; *** SetModeSEF - Set mode + disable FIQs, may disable IRQs ***
; *** SetModeSEIF - Set mode + disable IRQs+FIQs ***
; *** $regtmp only required if 26bit support required ***
; ***************************************************************
MACRO
SetModeSE$op $mode, $regtmp, $oldpsr
CPU32_bits IFto32 $op
[ :LNOT: NoARMv6
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
CPSID $op, #$mode
ELIF No26bitCode :LOR: ($mode > SVC32_mode)
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
MSR CPSR_c, #$mode+(CPU32_bits :OR: I32_bit)
|
LCLA clear_bits
LCLA set_bits
set_bits SETA ($mode :AND: 3) + (CPU32_bits :SHL: IF32_26Shift)
clear_bits SETA 3 :AND: :NOT: set_bits
SCPSR &$set_bits, &$clear_bits, $regtmp, , $oldpsr
]
MEND
; **************************************************************
; *** SetModeCLI - Set mode + enable IRQs, may enable FIQs ***
; *** SetModeCLF - Set mode + enable FIQs, may disable IRQs ***
; *** SetModeCLIF - Set mode + enable IRQs+FIQs ***
; *** $regtmp only required if 26bit support required ***
; **************************************************************
MACRO
SetModeCL$op $mode, $regtmp, $oldpsr
CPU32_bits IFto32 $op
[ :LNOT: NoARMv6
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
CPSIE $op, #$mode
ELIF No26bitCode :LOR: ($mode > SVC32_mode)
[ "$oldpsr" <> ""
MRS $oldpsr, CPSR
]
MSR CPSR_c, #$mode+I32_bit+F32_bit-(CPU32_bits :OR: F32_bit)
|
LCLA clear_bits
LCLA set_bits
set_bits SETA $mode :AND: 3
clear_bits SETA (3 :AND: :NOT: set_bits) + (CPU32_bits :SHL: IF32_26Shift)
SCPSR &$set_bits, &$clear_bits, $regtmp, , $oldpsr
]
MEND
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment