C 变量可以限制在一定的读/写速度吗?

mag*_*lum 2 c embedded assembly gcc

我正在使用一个嵌入式系统(基于 RISC-V),其中处理器连接到数据总线,数据总线又连接到 UART 模块。当数据总线被读/写时,需要两个处理器周期才能准备好新的读/写操作,否则会产生错误。

数据总线的内存映射如下:

struct WishboneBus {
    volatile uint32_t read_addr;
    volatile uint32_t write_addr;
    volatile uint32_t write_data;
    volatile uint32_t read_data;
};

#define WISHBONE_BUS ((struct WishboneBus *) (0x4000000))
Run Code Online (Sandbox Code Playgroud)

我想写这样的代码:

void wb_write(uint32_t addr, uint32_t data) {
    WISHBONE_BUS->write_data = data;
    WISHBONE_BUS->write_addr = addr;
}
Run Code Online (Sandbox Code Playgroud)

当使用 -O0 编译程序时,它会生成以下六个指令:

    WISHBONE_BUS->write_data = data;
    153c:   400007b7            lui a5,0x40000
    1540:   fd842703            lw  a4,-40(s0)
    1544:   00e7a423            sw  a4,8(a5) # 40000008 <BUS_START+0x8>
    WISHBONE_BUS->write_addr = addr;
    1548:   400007b7            lui a5,0x40000
    154c:   fdc42703            lw  a4,-36(s0)
    1550:   00e7a223            sw  a4,4(a5) # 40000004 <BUS_START+0x4>
Run Code Online (Sandbox Code Playgroud)

但使用 -Os 时,它会产生以下指令:

    WISHBONE_BUS->write_data = data;
     df8:   40000737            lui a4,0x40000
     dfc:   00b72423            sw  a1,8(a4) # 40000008 <BUS_START+0x8>
    WISHBONE_BUS->write_addr = addr;
     e00:   00a72223            sw  a0,4(a4)
Run Code Online (Sandbox Code Playgroud)

(函数调用的不相关部分被删除。)在 -O0 情况下,每个 之间有两个指令(周期)sw,因此它可以工作。但在 -Os 情况下,有两个sw相继出现,总线会产生错误,因为总线在读/写操作之间需要两个周期。

这就引发了一个问题:C 变量是否可以限制在一定的读/写速度?

我知道可以添加nop指令来完成这项工作,但所需指令的数量nop将取决于优化。我意识到我可以使用宏来解决这个问题,但我想要一个优雅的解决方案。例如,某种__attribute__((min_access_cycles(2)))或某事。

Dav*_*son 5

C 没有该功能,而且 GCC 可能不知道 RISC-V 指令如何映射到特定系统上的时钟周期。因此,您将必须使用一定量的组装来获得正确的时机。

我更喜欢尽可能少地使用汇编(例如,在内联汇编块中编写一些 NOP),这样编译器就可以更自由地进行优化。此外,调用无法内联的单独函数通常效率较低,因为编译器可能被迫将一些寄存器保存到堆栈中,并且必须将函数参数放入特定寄存器中以符合 ABI。

  • 既然你提到了优化,`asm volatile("nop" ::: );`​​(没有`memory` clobber)*仍然是有序的。“易失性”访问(类似于 OP 的结构成员),无论如何您都需要将其用于所有 MMIO 访问。因此,这应该可以很好地工作,并且仍然可以让编译器将非易失性的东西保存在它的寄存器中。(`asm("nop" :::)` 隐式是 `易失性`,因为它没有输出操作数,所以这也是正确的。https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Volatile ) (2认同)