In the SSAT instruction description it says:
ASR #32 Arithmetic right shift by 32 bits, permitted only for encoding A1. Encoded as sh = 1, immsh = 0b00000.
ASR #32 Arithmetic right shift by 32 bits, permitted only for encoding A1.
Encoded as sh = 1, immsh = 0b00000.
What does that mean?
Isn't ASR #32 the same as ASR #31?
I understand that it shifts (with "sign extension") the whole 32-bit value out and leaves only the sign extension bits
that are "copies" of the highest bit of the original value.
What am I missing here?
There's a difference in the flags set. The carry bit depends on the last bit shifted out so 0x80000000 ASR #31 will be 0xFFFFFFFF with carry clear whereas 0x80000000 ASR #32 will have the carry bit set.
Ah of course. Thanks.
No problem you're welcome - and you can award the points to yourself instead if you can think of a single vaguely useful use for the difference or either of the variants!
I'd like to add a hint: Use the ASR as operand2; perhaps with AND, ORR, BIC, EOR, ADD, SUB or another instruction. It's sometimes useful to get bit31 into the carry flag when doing math and needing to test the sign. -But beware; the rest of the instruction might also update the flags, including the carry flag.
It just tends to multiply the result by two in the process.
I was first thinking of long shift together with RRX, then I thought about how, and realized, it wouldn't work.
Now that I've been going through the instructions in case PC is used as the destination I realize that about half of the instructions look like once-in-a-lifetime instructions.
I think only compiler writers can find some use for them.
Maybe the instruction set architects took this too seriously:
http://web.mit.edu/humor/Computers/extended.opcodes
Long shift is easy; I've prepared a document about it (which is in the queue to being published; I just need to finish the ones before that one first).
-Starting from the msb end, it goes something like ... [A/L]SRS : RRX : RRX : RRX : RRX : ... : RRX
Notice: The condition codes do not need to be updated by RRX!
If you need to shift by larger amounts than just 1, then it's a good idea to use LSR and BFI only; this means you'll need to start from the lsb end.
I've found good use for them on a Cortex-M, for instance the ADD, where PC is the destination.
This can be used to synchronize an interrupt to a Timer Counter on the exact clock cycle (and daith mentions a couple of other use cases too).
-If you're in a situation, where every clock cycle is important (this usually happens when you need your device to run on very low frequencies in order to save power - or when you need to do high-speed I/O on a device), then it's important to have the "strange options", where you can find a solution to an otherwise unsolvable problem.
Starting from the msb end, it goes something like ... [A/L]SRS : RRX : RRX : RRX : RRX : ... : RRX
That's what I thought - longer shifts won't work.
BTW, nice post (the Cortex-M0 tricks).
I was rather thinking about uqadd16, uxtab, qdadd, and the like.
Not used in every program.
Well I was thinking of something simple like testing the top two bits of a register. (I haven't tested this)
MOVS r0, r1, ASR #31
BHI starts_11 ; Z clear C set
BMI starts_10
BCS starts_01
... starts_00
using MVNS you can test for 01 first.
p.s. I don't think this sort of thing makes for happy colleagues though it might ensure a living for years to come.
That definitely qualifies for a cool trick. If you want to avoid branching, you could combine it with the sbcs instruction like SBCS r3,r3,r3 after a BMI.
(or of course use conditional execution). Using it as a mask for a conditional AND would probably also be useful.
... MVNS r0,r1,asr#31 might also prove useful, if you need to invert the sign.