【问题标题】:Using memcpy and friends with memory-mapped I/O在内存映射 I/O 中使用 memcpy 和朋友
【发布时间】:2015-09-11 09:51:07
【问题描述】:

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

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

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

【问题讨论】:

  • 我首先会担心将memcpy 用于MMIO。数据是否必须以任何特定顺序写入?会不会有副作用?你写的 MMIO 部分是否像记忆一样?
  • 你提出了非常有效的观点,我必须与 FPGA 人员再次核对,但是 AFAIK,不,不,是的。
  • 使用memcpy 写入一组 MMIO 寄存器对我来说仍然感觉“错误”。 AFAIK,大多数需要移动大量数据的外设都使用 DMA 或重复读取寄存器。我在外设上使用memcpy 的唯一情况是,MMIO 上的内存地址范围是否真的由 RAM 支持(但在这种情况下,为什么首先需要使用volatile?编译器内存屏障就足够了)。

标签: c memory volatile memcpy memory-mapping


【解决方案1】:

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

一些原因:

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

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

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

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

如果您需要更频繁地传输较大的块,请考虑使用 DMA。如果 FPGA 使用 PCI(e),您可以使用带有 scatter/gather 的 busmaster DMA(但是,这并不容易实现;我自己做过,但可能值得努力)。

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

【讨论】:

    【解决方案2】:

    绝对不安全。无法保证 memcpy 将以何种顺序复制数据,以及一次复制多少字节。

    【讨论】:

    • 如果顺序不重要(FPGA 将在读取期间将相同的值保存在寄存器中),为什么这很重要?
    • 我不会说它绝对不安全。只要被复制到的 MMIO 地址范围符合 memcpy 的预期(即作为内存),就可以了。
    猜你喜欢
    • 2016-05-27
    • 2011-01-19
    • 2017-06-08
    • 1970-01-01
    • 2016-11-16
    • 2017-05-17
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    相关资源
    最近更新 更多