PSR manipulation macros: The next generation
Jeffrey Lee (213) 6048 posts |
Looking at some code which makes heavy use of MSR for PSR manipulation, I’m left wondering what can be done to give us a set of modern PSR manipulation macros – macros optimised for 32bit machines (running in 32bit mode), and which are fully capable of using the CPS instruction when targeting ARMv6+ (I’d previously done some tests to confirm that CPS is faster than MSR when used for enabling/disabling interrupts, but an extra test just now suggests that it’s faster for switching processor mode as well). Note – I’m only really talking about the macros for manipulating the control field. And people unsure where the current macros are can find them here (32bit and 26/32bit neutral) and here (26bit-only) Fundamentally, I think the problems with the current PSR manipulation macros are two-fold:
Since code which uses FIQs is rare, I think we only really have two fields of the PSR which we care about: the I bit and the mode bits. And when manipulating the PSR we’ll either be setting those fields to a new (constant) value, or we’ll be preserving them (either by not changing their value, or by setting them to their current value). We can assume FIQs are always enabled, and we can assume we’re not in Thumb mode, so if the F or T bits need to be written then we can assume they can take the value zero. So a potential CPS and MSR optimised macro would be as follows: ; Set I and M fields of PSR, according to $fields ; May clear F+T bits, other bits preserved ; $current can be optionally provided as the current control field value (recommended) ; $regtmp needed if 26bit support needed, or current PSR needed but not provided MACRO UpdPSRc $fields, $new, $current, $regtmp [ NoARMv6 ; Generate a single CPS instruction ; (logic not shown, could be CPSIE/CPSID/CPS) ELIF No26bitCode :LAND: (("$current" <> "") :LOR: ($fields = M32_bits+I32_bit)) MSR CPSR_c, #$new :OR: ($current :AND: :NOT: $fields) | ; Use read-modify-write sequence like SCPSR ; (logic not shown, and SCPSR can't be used directly since it accepts a 26bit PSR) ] MEND E.g. Does anyone have any thoughts on this? To me it feels a bit verbose, but potentially we could create more friendly wrappers for the common cases (e.g. separate enable & disable IRQ macros, where $current and $regtmp would be the only parameters) Another option I can think of would be to add an extra parameter to SCPSR which allows you to specify the current PSR value, and start using SCPSR in more places – but SCPSR is itself a bit nasty since its interface deals with the 26bit PSR format, and the set and clear masks must be exclusive. There’d also be the question of how much of the PSR the “current PSR value” has to be – just the control field, or the entire thing? |
Sprow (202) 1158 posts |
I believe the origin of the macros was starting from the 26 bit view, and retrospectively creating 32 bit versions with the same conditions. eg. SETV in a 26 bit world just did a CMP of the PC, but because the PC wasn’t zero and < 64MB, you ended up clearing Z and C too. The 32 bit versions had to faithfully mimic that presumably because someone did a mini audit and found many cases where the side effects of SETV were relied upon, or at least too many to be bother fixing up. Some of them are clearly inspired by the BBC Micro, I assume some of the original engineers were still around for both, as there’s SEC CLC PHPSEI PLP in there! Also, since the objective was to make 32 and 26 bit neutral source the macros are of course limited to the 6 bits of flags in R15 (NZCV + 2 mode bits) so if you want to switch to SYS32 mode you’re screwed. Aside: on a couple of occasions I’ve noted there’s no M32_bit definition in Generic32 when for example you want to TST for 32 bit.
You chose the wrong weekend to make that comment, as I’ve just been making extensive use of the FIQ options in the existing macros to great effect. I think it’d be shortsighted to drop support for the F bit, though they could be given 2nd class (less optimal?) macro output, for the sake of 1 bit. In general though the minimal set
the current mix is pretty close to that, but you’re quite right there’s no way to hint that you either don’t care about other bits or know what their state is already so the macros end up doing lots of (potentially unnecessary) read-modify-write steps. |
Jeffrey Lee (213) 6048 posts |
I did actually have implementations for SEI and CLI macros, until I realised that we needed something similar for changing the processor mode, and also a macro which can change interrupt masks and processor mode at the same time. With FIQ thrown into the mix, and since CPS is the instruction that we want to make the best use of, perhaps we need the following set of macros:
That’s a lot of macros, but it helps keep things short and sweet; each macro would need a max of three params – the (sometimes optional) mode, the (optional) temp register, and the (optional) register to return the previous PSR in. And maybe there’s some magic in objasm we can use to reduce the number of macro definitions needed (I know it supports condition code suffixes on macros, not sure if it extends to generic suffixes). For when the macros are generating 26bit-compatible code, we’ll probably want them to assume they’re running on a 32bit CPU (on a 32bit OS) if any of the 32bit-only modes are specified. Otherwise it should be possible for them to preserve the 32bit-ness, like WritePSRc. I’m not sure if it’s officially stated anywhere, but I get the general impression that the only time it’s safe to disable FIQs is if IRQs are also disabled. Otherwise you risk having an IRQ fire and block your FIQ routine for longer than is acceptable, or even worse, an IRQ routine could call a SWI which inadvertently enables FIQs. This is why I’m allowing some of the macros to have side-effects of enabling FIQs or disabling IRQs. But if you think that’s a bad idea, it’s easy enough to require the user to specify the current IRQ/FIQ state as part of the current mode hint. NZCV I’m ignoring for now – I don’t think we have much reason to replace the current set of macros we’re using for those. Similarly I’m not looking to replace PHPSEI or PLP. |
Jeffrey Lee (213) 6048 posts |
Answer: Yes, it’s perfectly happy with generic macro suffixes. So we could potentially get by with a “SE$opt” macro for CPSID-style behaviour, a “CL$opt” macro for CPSIE, and SetMode for plain CPS. |