使用 memcpy 和朋友进行内存映射 I/O

Mat*_*ine 5 c memory volatile memcpy memory-mapping

我正在从事一个嵌入式项目,该项目涉及内存映射 FPGA 寄存器上的 I/O。需要标记指向这些内存区域的指针,volatile以便编译器不会通过在 CPU 寄存器中缓存值来“优化”对 FPGA 的读取和写入。

在少数情况下,我们希望将一系列 FPGA 寄存器复制到缓冲区中以供进一步使用。由于寄存器映射到连续地址,这memcpy似乎是合适的,但是将我们的volatile指针作为源参数传递会给出关于丢弃volatile限定符的警告。

丢弃volatile指针的-ness 以抑制此警告是否安全(和理智)?除非编译器做了一些神奇的事情,否则我无法想象调用memcpy将无法执行实际复制的场景。另一种方法是仅使用for循环并逐字节复制,但memcpy实现可以(并且确实)根据副本的大小、对齐方式等优化副本。

too*_*ite 4

作为 FPGA 和嵌入式软件的开发人员,只有一个明确的答案:不要使用memcpy等。为了这

一些原因:

  • 不保证 memcpy 能够按任何特定顺序工作。
  • 编译器很可能用内联代码替换调用。
  • 此类访问通常需要一定的字长。memcpy并不能保证这一点。
  • 寄存器映射中的间隙可能会导致未定义的行为。

但是,您可以使用一个简单的for循环并自行复制。如果寄存器是volatile见下文),那么这是安全的。

根据您的平台,volatile单独使用可能还不够。内存区域还必须是不可缓存的并且严格排序(并且可能是非共享的)。否则,系统总线可能(并且对于某些平台而言)会重新排序访问。

此外,您可能需要 CPU 的屏障/栅栏,以免重新排序访问。请仔细阅读您的硬件规格。

如果您需要更频繁地传输更大的块,请考虑使用 DMA。如果 FPGA 使用 PCI(e),您可以使用具有分散/聚集功能的总线主控 DMA(但是,这并不容易实现;我自己就是这样做的,但可能值得付出努力)。

最好的(也是最理智的)方法实际上取决于多种因素,例如平台、所需的速度等。在所有可能的方法中,我认为最多使用mempcy()不太理智的方法之一(1):不确定这是否是语法正确,但我希望你明白我的意思)。