I'm writing an assembly macro to a C-program, and being quite new with this I have gotten stuck on something.
I'm trying to write a macro for moving data from a general purpose register to a special purpose register.
My problem is that the syntax I've found to move data from a GPR to an SPR takes a constant SPR value, while I want to use a variable one stored in another register.
# SPR is constant, rA is the value to be written
mtspr SPR, rA
I'm after something that looks like this:
# rA contains the number of the SPR, and rB the value to be moved.
AWESOMEmtspr rA, rB
Is there a reason there is no such macro available, and how would I make it myself?
Many thanks in advance.
---- Edit: ----
As it looks now I have a giant switch case in my C-code that jumps to the correct mtspr-section. I have twenty-some sections for reading and writing specifit SPR:s that each look exactly the same, but differ by a constant value.
The reason you can't do it is that the instruction architecture doesn't accept register-indirect as an addressing mode for the register parameter. Honestly, I've never seen a machine architecture that does, as the number of registers is usually fairly small, so the register is encoded as part of the instruction itself. If you really don't like the solution you've got, you can try to synthesize the instruction yourself (take the base opcode, see where the register specifier goes and OR in the appropriate value), then execute it. Depending on your OS and compiler, this may not be possible (self-modifying code is often taboo).
Does it make the code cleaner if you write the jump table in assembly? Maybe pass in the SPR specifier (assuming it's a zero-based integer, or can be coerced into one), shift it left to get the offset into the jump table, then jump into the table, which would be a sequence of
MTPSR PSRx, val
RET
MTPSR PSRx+1, val
RET
I don't know what counts as "cleaner" to you, just thought I'd throw that out. Note that you might have to pad with NOPs to get everything aligned, I don't have a PowerPC manual so I have no idea what the instruction sizes or alignment requirements are.
I found a rather elegant solution to this using the stringizer macro:
#define stringify(s) tostring(s)
#define tostring(s) #s
#define mfspr(rn) ({unsigned int rval; \
asm volatile("mfspr %0," stringify(rn) \
: "=r" (rval)); rval;})
#define mtspr(rn, v) asm volatile("mtspr " stringify(rn) ",%0" : : "r" (v))
This is from the U-Boot code for the PowerPC.
This seems like a bizarre thing to do, but if you're convinced you need to do this for some reason then you'll need to implement a jump table or sequence of conditionals whereby you test rA and jump to the appropriate hard-coded mtspr
instruction. You'll need to think about how you handle invalid SPR numbers too.