[英]RISC-V inline assembly
我对内联汇编很陌生,所以我需要你的帮助来确保我正确使用它。 我需要在使用 Risc-v 工具链编译的 C 代码中添加汇编代码。 请考虑以下代码:
int bar = 0xFF00;
int main(){
volatile int result;
int k;
k = funct();
int* ptr;
ptr = &bar;
asm volatile (".insn r 0x33, 0, 0, a4, a5, a3":
"=m"(*ptr), "=r"(result):
[a5] "m"(*ptr), [a3] "r"(k) :
);
}
...
我想要做的是bar = bar+k
。 实际上,我想更改bar
所在的内存位置的内容。但是我编写的代码获取了bar
的地址并将其添加到k
。 有人知道问题出在哪里吗?
不幸的是,您误解了语法。
在汇编程序字符串中,您可以使用%0
或%1
引用参数,其中数字是传递给asm
指令的第 n:th 个参数。 或者,您可以使用符号名称%[myname]
,它引用[myname]"r"(k)
形式的参数。
请注意,符号名称与使用数字相同,名称本身并不意味着任何东西。 在您的示例中,给人的印象是您正在强制代码使用特定的处理器寄存器。 (如果你真的需要使用它,还有另一种语法。)
例如,如果您编写如下内容:
int bar = 0xFF00;
int main(){
volatile int result;
int k;
k = funct();
int* ptr;
ptr = &bar;
asm volatile (".insn r 0x33, 0, 0, %[res], %[res], %[ptr]":
[res]"+r"(result) : [ptr]"r"(ptr));
}
IAR 编译器将发出以下内容。 如您所见,已为a0
分配了result
变量(使用符号名称res
),为a1
分配了变量ptr
(此处,符号名称与变量名称相同)。
\ 000014 0001'2503 lw a0, 0x0(sp)
\ 000018 0000'05B7 lui a1, %hi(bar)
\ 00001C 0005'8593 addi a1, a1, %lo(bar)
\ 000020 00B5'0533 .insn r 0x33, 0, 0, a0, a0, a1
\ 000024 00A1'2023 sw a0, 0x0(sp)
您可以在“IAR C/C++ Development Guide Compiling and linking for RISC-V”一书的“Assembler Language Interface”一章中阅读有关 IAR 内联汇编语法的更多信息。 这本书以 PDF 格式提供,您可以从 IAR Embedded Workbench 中访问它。
根据您的问题中提供的代码片段,我尝试使用 IAR C/C++ Compiler for RISC-V V3.10 编写以下代码:
int funct();
int funct() { return 0xA5; }
int bar = 0xFF00;
int main() {
int k = funct();
int* ptr = &bar;
#if defined(__ICCRISCV__)
__asm volatile (".insn r 0x33, 0, 0, a3, a3, a4"
: "=a3"(*ptr)
: "a3"(*ptr), "a4"(k)
: "memory" );
#endif
}
在这种情况下, ADD
指令是寄存器到寄存器指令。 在这种情况下, a3
被用作输入和输出, .insn
指令生成的指令是: add a3,a3,a4
,实际上是*ptr = *ptr + k
。
IAR 编译器允许在内联汇编中显式选择寄存器,如此处所述。
正如 @PeterCordes 在评论中指出的那样,GCC 不能直接引用要使用的寄存器,因为它提供了一组不同的约束,因此这里可能需要一个更通用的解决方案。
memory
clobber 不是强制性的,尽管它很有用,因为它警告编译器全局内存将受到指令的影响。
此外,在可移植性方面, asm
关键字在 C++ 中得到了更正式的支持。 尽管许多 C 编译器会接受它,但如果指定了严格的一致性,有些编译器会立即拒绝它。 因此,最兼容的选择是__asm
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.