5

I'm working on an embedded project which involves I/O on memory-mapped FPGA registers. Pointers to these memory regions need to be marked volatile so the compiler does not "optimize out" reads and writes to the FPGA by caching values in CPU registers.

In a few cases, we want to copy a series of FPGA registers into a buffer for further use. Since the registers are mapped to contiguous addresses, memcpy seems appropriate, but passing our volatile pointer as the source argument gives a warning about discarding the volatile qualifier.

Is it safe (and sane) to cast away the volatile-ness of the pointer to suppress this warning? Unless the compiler does something magical, I can't imagine a scenario where calling memcpy would fail to perform an actual copy. The alternative is to just use a for loop and copy byte by byte, but memcpy implementations can (and do) optimize the copy based on size of the copy, alignment, etc.

Matt Kline
  • 10,149
  • 7
  • 50
  • 87
  • I would be worried about using `memcpy` for MMIO in the first place. Does the data have to be written in any particular order? Will there be side effects? Does the MMIO section you're writing to act like memory? – tangrs Jun 25 '15 at 00:37
  • You raise very valid points that I'll have to double-check with the FPGA guys, but AFAIK, no, no, and yes. – Matt Kline Jun 25 '15 at 00:39
  • 1
    Writing to a bank of MMIO registers with `memcpy` still feels "wrong" to me though. AFAIK, most peripherals that need to move large amounts of data employ DMA or by repeatedly reading a register. The only case I'd use `memcpy` on a peripheral is if the memory address range on the MMIO is really backed by RAM (but in this case, why did you need to use `volatile` in the first place? A compiler memory barrier would have sufficed). – tangrs Jun 25 '15 at 00:48
  • This isn't safe for all the reasons in comments/answers, most importantly, I experienced memcpy to write several times the same data. – Alexis Feb 23 '22 at 12:37

2 Answers2

4

As a developer of both: FPGA and embedded software, there is just one clear answer: do not use memcpy et al. for this

Some reasons:

  • There is no guarantee memcpy will work in any specific order.
  • The compiler might very well replace the call with inline code.
  • Such acceses often require a certain word-size. memcpy does not guarantee that.
  • Gaps in the register map might result in undefined behaviour.

You can, however, use a simple for loop and copy yourself. This is safe, if the registers are volatile (see below).

Depending on your platform, volatile alone might not be sufficient. The memory area has also to be non-cachable and strictily ordered (and - possibly - non-shared). Otherwise the system busses might (and will for some platforms) reorder accesses.

Furthermore, you might need barriers/fences for your CPU not to reorder accesses. Please read your hardware-specs very carefully about this.

If you need to transfer larger blocks more often, think about using DMA. If the FPGA uses PCI(e), you could use busmaster DMA with scatter/gather for instance (however, this is not easily implemented; did that myself, but might be worth the effort).

The best (and most sane) approach depends actually on multiple factors, like platform, required speed, etc. Of all possible approaches, I would deem using mempcy() one of the lesser sane(1) at best (1): not sure if that is correct grammar, but I hope you got my point).

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • How about the std::copy that accepts volatile? I don't care about the order and the size of each store, I do care about the exact number of bytes written. – Alexis Feb 23 '22 at 12:35
0

Absolutely not safe. There is no guarantee whatsoever in which order memcpy will copy the data, and how many bytes are copied at a time.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 1
    If order is unimportant (the FPGA will hold the same values in the registers for the duration of the read), why does this matter? – Matt Kline Jun 25 '15 at 00:41
  • I wouldn't say it's *absolutely* not safe. As long as the MMIO address range that's being copied to acts as `memcpy` expects it to (i.e. as memory), it might be fine. – tangrs Jun 25 '15 at 00:44