代码之家  ›  专栏  ›  技术社区  ›  magnusmaehlum

一个C变量是否可以被限制在一定的读/写速度?

  •  0
  • magnusmaehlum  · 技术社区  · 2 年前

    我使用的是嵌入式系统(基于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))
    

    我想写这样的代码:

    void wb_write(uint32_t addr, uint32_t data) {
        WISHBONE_BUS->write_data = data;
        WISHBONE_BUS->write_addr = addr;
    }
    

    当使用-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>
    

    但是使用-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)
    

    (函数调用的非相关部分将被删除。) 在-O0的情况下,每个之间有两个指令(周期) sw ,所以它有效。但在-Os的情况下,有两个 sw 并且总线产生错误,因为总线在读/写操作之间需要两个周期。

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

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

    1 回复  |  直到 2 年前
        1
  •  2
  •   David Grayson    2 年前

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

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

    推荐文章