简体   繁体   中英

(GNU inline assembly) How to use a register which not assigned from nor copy to the C variables?

I'm writing inline assembly statements using a GNU-based toolchain, and there are three instructions within the inline assembly to update a single bit of a system register. The steps will be:

  1. move(read) a system register to a general register
  2. 'AND' it with the variable value from C code
  3. move(write) back to the system register just read

in the instruction set I'm using, the inline assembly syntax is like this:

unsigned int OV_TMP = 0xffefffff;
asm volatile ( "mfsr %0, $PSW\n\t"
               "and %0, %0, %1\n\t"
               "mtsr %0, $PSW"
               :  : "r"(OV_TMP) : );

%1 is the register which I want to forward the value of OV_TMP into.

%0 is the problem for me, and my problem is : How to write the inline assembly code once there is a register used internally and is not assigned from nor copy to the C variables in the C code?

The thing to consider here is that, from the compiler's perspective, the register is assigned-to by the inline assembly, even if you don't use it again later. That is, you're generating the equivalent of:

register unsigned int OV_TMP = 0xffefffff, scratch;

scratch = magic() & OV_TMP;
more_magic(scratch);
/* and then don't re-use scratch for anything from here on */

The magic and/or more_magic steps cannot be moved or combined away because of the volatile , so the compiler cannot simply delete the written-but-unused register.

The mfsr and mtsr look like powerpc instructions to me, and I would probably do the and step in C code (see footnote); but the following should generally work:

unsigned int OV_TMP = 0xffefffff, scratch;
asm volatile("mfsr %0, $PSW\n\t"
             "and %0, %0, %1\n\t"
             "mtsr %0, $PSW"
             : "=&r"(scratch) : "r"(OV_TMP));

Here the "=&r" constraint says that the output operand ( %0 ) is written before the input operand ( %1 ) is read.


Footnote: As far as I know (which is not very far, I've only ever done a tiny bit of ppc assembly) there's no need to keep the mfsr and mtsr instructions a specific distance apart, unlike certain lock-step sequences on other processors. If so, I would write something more like this:

 static inline unsigned int read_psw() { unsigned int result; asm volatile("mfsr %0, $PSW" : "=r"(result)); return result; } static inline void write_psw(unsigned int value) { asm volatile("mtsr %0, $PSW" :: "r"(value)); } #define PSW_FE0 0x00100000 /* this looks like it's FE0 anyway */ ... write_psw(read_psw() & ~PSW_FE0); /* some appropriate comment here */ 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM