我正在编写一个嵌入式C程序来测试我在FPGA板上开发的硬件IP。我在使用RISC-V GCC ASM语法时发现了这个奇怪的问题。
这是我在C程序中编写的代码。write_target
和base_addr
都声明为volatile uint32_t。
// write_target = 0x1F9
asm volatile (
"li %0, 0x1F9\n"
: "=r"(write_target)
);
// base_addr = 0x1040_6000
asm volatile (
"lui %0, %1"
: "=r" (base_addr)
: "i" (66566)
);
// base_addr = 0x1040_6000 + 0x0
asm volatile (
"addi %0, %1, %2\n"
: "=r"(base_addr)
: "r"(base_addr), "i"(0)
);
// mem[base_addr] = write_target
asm volatile (
"sh %0, 0(%1)\n"
: "=r"(write_target)
: "r"(base_addr)
);
当我查看编译后的转储文件时,我看到它已被编译为以下内容:
800031e6: 1f900793 li a5,505 // a5 = 0x1F9 = d'505
800031ea: f6f42423 sw a5,-152(s0) // mem[s0-152] = 505
800031ee: 104067b7 lui a5,0x10406 // a5 = 0x10406 = d'66566
800031f2: f6f42623 sw a5,-148(s0) // mem[s0-148] = 0x10406
800031f6: f6c42783 lw a5,-148(s0) // a5 = mem[s0-148]
800031fa: 00078793 mv a5,a5 // a5 = a5
800031fe: f6f42623 sw a5,-148(s0) // mem[s0-148] = 0x10406
80003202: f6c42783 lw a5,-148(s0) // a5 = mem[s0-148]
80003206: 00f79023 sh a5,0(a5) # 10406000 <_tbss_end+0x10406000>
// mem[a5] = a5
我不明白为何会出现这种情况。我不太熟悉RISC-V GCC交叉编译器的内部工作原理,所以我不知道我做错了什么。我反复检查了语法,据我所知,它是正确的。我正在运行-O3优化标志。
我真的很感激你们所有人的指导。
谢谢你,谢谢
更新:我正在使用riscv-gnu-toolchain Git repo中的Newlib gcc编译器。
我遇到的问题是,我想将write_target
的值存储到base_addr
中。但编译后的代码似乎将base_addr
存储到base_addr
中。
1条答案
按热度按时间oewdyzsn1#
问题似乎是你在这个汇编指令上使用了一个输出约束:
这就是为什么GCC从不将
write_target
传递给语句的原因。为了匹配您的风格,它需要两个寄存器输入约束,分别为write_target
和base_addr
。使用一个没有任何输入/输出约束的
asm
块,以及在汇编程序中使用的硬寄存器的clobbers可能更容易。如果将\n
嵌入到字符串中,则可以在一个asm
语句中嵌入多行。(惯例是使用\n\t
,以匹配编译器生成的指令缩进。