如何解决内联汇编器和位域访问
我想在嵌入式汇编器中设置以下位字段。
EVSYS->Channel[2].CHINTFLAG.bit.EVD = 1
结构为:
typedef union {
struct {
uint8_t OVR:1;
uint8_t EVD:1;
uint8_t :6;
} bit; uint8_t reg;
} EVSYS_CHINTFLAG_Type;
它适用于以下情况:
#define VUSB_RESET_IRQ() \
asm volatile( \
"mov r5,%[value9]\n\t" \
"orr r5,r5,#0x40\n\t" \
"strb r5,[%[addr9]]" \
: : [value9] "r"(EVSYS->Channel[2].CHINTFLAG.reg),\
[addr9] "r"(&(EVSYS->Channel[2].CHINTFLAG.reg)) \
: "r5","memory");
但这可以在汇编程序中更好地完成,因为带有.EVD的gcc O3是:
156: EVSYS->Channel[2].CHINTFLAG.bit.EVD = 1;
200002CA ldr r2,[pc,#28]
200002CC ldrb.w r3,[r2,#54]
200002D0 orr r3,r3,#2
200002D4 strb.w r3,#54]
我的手写内联是:
155: VUSB_RESET_IRQ();
200002CC ldr r3,#44]
200002CE ldr r1,#48]
200002D0 ldrb.w r2,[r3,#54]
200002D4 mov r5,r2
200002D6 orr r5,#64
200002DA strb r5,[r1]
编辑: 我将代码更改为此,并编译为所需的asm:
#define VUSB_RESET_IRQ() \
asm volatile( \
"orr %[out],%[value],#1<<1\n\t" \
: [out] "=r"(EVSYS_CHANNEL_CHINTFLAG_2) \
: [value] "r"(EVSYS_CHANNEL_CHINTFLAG_2) \
: "memory");
解决方法
您的问题是在asm模板中包含了无用的mov
,并对strb
的寻址模式进行了硬编码。这迫使GCC将指针具体化到寄存器中,并且出于某种原因,它选择在asm之前不将其用于ldrb。 asm模板中的mov
纯粹是浪费:您已经在寄存器中要求值了。
只需使用"+r"(value9)
操作数和orr %[value9],#0x2
。如果不需要,请不要对任何寄存器进行硬编码,这样可以避免产生任何麻烦。
或者使用单独的"=r"(EVSYS->Channel[2].CHINTFLAG.reg)
输出,使编译器可以选择将orr
与单独的目的地一起使用,以便原始值仍在寄存器中。
(马上得到正确的答案:第二位是#1<<1
,而不是#1<<6
。ARM位域是从最低位到最高位排序的,正如我们从GCC输出中看到的那样)
有关编写不烂的嵌入式汇编的更多信息,请参见https://stackoverflow.com/tags/inline-assembly/info。
或者更好的是,根本不要使用内联asm
https://gcc.gnu.org/wiki/DontUseInlineAsm
正如您已经演示的那样,GCC已经进行了有效的组装,因此零收益。实际上,净收益是负面的:即使使用高效的内联汇编,您仍将无法克服诸如常数传播和CSE之类的优化。 (如果/当您需要击败这些优化时,使用强制转换volatile*
,而不是asm volatile
。)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。