我正在编写一个嵌入式C程序来测试我在一块FPGA板上开发的硬件IP.我在玩RISC-V GCC ASM语法时,发现了这个奇怪的问题.

这是我在C程序中编写的代码.write_targetbase_addr都声明为易失性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交叉编译器的内部工作原理不是很熟悉,所以我不知道我做错了什么.我反复判断了语法,据我所知是正确的.我正在使用-03优化标志运行.

我真的很感激你们所有人可能有的任何指导.

谢谢!

更新:我使用的是来自riscv-gnu-工具链GitrepoNewlibGCC编译器.

我遇到的问题是,我想将write_target的值存储到base_addr中.但编译后的代码似乎将base_addr存储到base_addr中.

推荐答案

问题似乎是您在此汇编指令上使用了输出约束:

// mem[base_addr] = write_target
asm volatile ( 
  "sh   %0, 0(%1)\n"
  : "=r"(write_target)
  : "r"(base_addr)
);

这就是GCC在声明中从未超过write_target的原因. 为了匹配您的风格,它需要两个寄存器输入约束,分别为write_targetbase_addr.

在没有任何输入/输出约束的情况下使用一个asm块,并将其用作汇编 routine 中使用的硬寄存器,可能会更容易.如果在字符串中嵌入\n,则可以在一条asm语句中嵌入多行.(约定使用\n\t,以匹配编译器生成的指令缩进.)

C++相关问答推荐

malloc实现:判断正确的分配对齐

编译SDL 2时缺少SDL_ttf

正在try 将文件/文件夹名从目录 struct 存储到链接列表

将常量转换为指针会增加.数据大小增加1000字节

在列表中插入Int指针(C)

C++中矢量类型定义和数据保护的高效解决方案

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

插座打开MacOS组件

为什么指针运算会产生错误的结果?

如何在提取的索引中分配空值?

将变量或参数打包到 struct /联合中是否会带来意想不到的性能损失?

C将数组传递给函数以修改数组

-Wnonnull-Compare警告不是具有误导性吗?

通过k&;r语法的c声明无效

从CentOS 7到Raspberry PI 2B的交叉编译-无法让LIBC和System Include标头一起工作

如何使用WRITE()以指针地址的十六进制形式写入标准输出

程序如何解释变量中的值

为什么一个在线编译器拒绝这个VLA代码,而本地的Apple clang却不拒绝;t?

为什么argc和argv即使在主函数之外也能工作?

段错误try 访问静态字符串,但仅有时取决于构建环境