Been working on understanding powerpc a bit more over the weekend.. and FINALLY had nutted out what happens when using the instruction rlwimi
so.. rlwimi - rotate left word immediate then mask insert
using the following example:
rlwimi r6, r5, 3, 0, 29
Assuming r5 = 0x1122 3344 (binary = 0001 0001 0010 0010 0011 0011 0100 0100)
and r6 = 0x4433 2211 (binary = 0100 0100 0011 0011 0010 0010 0001 00
01)
1) Rotate r5 left by 3bits
before rotation: 0001 0001 0010 0010 0011 0011 0100 0100
After rotation:
1000 1001 0001 0001 1001 1010 0010 0000
hex value is now: 0x8911 9A20
2) The mask to use is 0,29, which means every bit from 0 to 29 is set to 1. In PPC, the MSB is bit 0, and LSB is bit 31.
So this mask would be: 1111 1111 1111 1111 1111 1111 1111 1100
hex value is 0xFFFF FFFC
3) Next, for every bit set as 1 in the MASK, this will REPLACE the bit of R6 with the bit in R5. Any 0 bits in the mask means the bit in R6 is left alone.
Looking at the above, only bit 30 and 31 are preserved in R6, all other bits will be replaced with whats stored in R5.
So we end up with:
1000 1001 0001 0001 1001 1010 0010 0001
So finally we end up with: 8911 9A21
This.. has 100% driven me crazy trying to understand. I had to have it written down or would go crazy.
Now.. whys this so important? This kind of command is used extensively through the E38 operating system, along with GMs kernel so its important to understand it well. This is used alot for the CAN regsiters, interrupts and external flash handling routines.
A common example which came up frequently was the following:
r6,r7,0x5,0x1f,0x1f
where:
r7 = 0
r6 = some important register (Like interrupts or canbus)
since r7 is 0, it could be rotated an unlimited times and makes no difference. Its funny that the compiler occasionally sets the 'rotation bit' to something like seen here as 5, since rotating 0 by 5 is still 0!
Next, this sets a mask of bit 31 to 31. This means we have 0000 0000 0000 0000 0000 0000 0000 0001
Since r7 is 0, this means every bit that is a 1 in the above mask will set the same bit in r6 as 0, thus in this case its bit 31.
This is essentially a simple way of setting/disabling specific bits in a register. In C is should be: r6 |= ((r7<<5) & mask)
I think I got that above c calc correct.. but regardless... it makes SO much more sense with it written out nicely.