我使用的是一个嵌入式系统(基于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之间有两个指令(周期),因此它可以工作.但是在-O的情况下,有两个sw相继,并且由于在读/写操作之间,总线需要两个周期,所以总线产生错误.

这引发了这个问题: 可以将C变量限制为特定的读/写速度吗?

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

推荐答案

C没有这个功能,GCC可能也不知道RISC-V指令是如何映射到特定系统上的时钟周期的.因此,你将不得不使用一定数量的组装来获得正确的时机.

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

C++相关问答推荐

C限制限定符是否可以通过指针传递?

为什么我得到更多的256假阳性在PKZIP解密密钥验证?

在使用GTK 4 Columnview列表模型时,如何为多列添加排序函数.C编码,Linux/GNOME环境

仅在给定的大小和对齐方式下正确创建全局

C是否用0填充多维数组的其余部分?

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

使用AVX2的英特尔2022编译器的NaN问题&;/fp:FAST

I2C外设在单次交易后出现故障

C代码在字符串中删除不区分大小写的子字符串的问题

这个空指针类型的转换是有效代码还是恶意代码?

OSDev--双缓冲重启系统

C语言中奇怪的输出打印数组

无法识别C编程语言的语法,如书中所示

Makefile无法将代码刷新到ATmega328p

可以';t从A9G模块拨打电话

不兼容的整数到指针转换传递';char';到类型';常量字符*

为什么<到达*时不会转换为>?

将数组中的所有元素初始化为 struct 中的相同值

使用共享变量同步多线程 C 中的函数

C 中从 Unix 纪元时间转换的损坏