spec: DMA memcpy accelerator - #931
Conversation
…nation, end-detection and row-count arguments
…the unit address increments
|
Quick review:
Do you want us to perform an in-depth analysis next? We might be able to find some optimizations (which could be very beneficial, given that this chip is expected to see a large volume of traffic). |
erik-3milabs
left a comment
There was a problem hiding this comment.
first batch of comments; I'll review the remainder on Monday
|
|
||
| The #dma chip copies a range of bytes from one location in memory to another, that is, it performs a `memcpy`. | ||
| #footnote([Linux man-page on `memcpy`; man7.org. #link("https://man7.org/linux/man-pages/man3/memcpy.3.html")[[src]]]) | ||
| The guest performs such a copy with a RISC-V loop --- per copied doubleword a load, a store, two pointer increments and a branch, each of them a `CPU` row (@cpu) together with its memory operations. |
There was a problem hiding this comment.
Well, not any more. 😄
Rephrase to indicate that this is how this would be done if this chip did NOT exist, i.e., if you were to have the CPU do this "manually"
| The #dma chip copies a range of bytes from one location in memory to another, that is, it performs a `memcpy`. | ||
| #footnote([Linux man-page on `memcpy`; man7.org. #link("https://man7.org/linux/man-pages/man3/memcpy.3.html")[[src]]]) | ||
| The guest performs such a copy with a RISC-V loop --- per copied doubleword a load, a store, two pointer increments and a branch, each of them a `CPU` row (@cpu) together with its memory operations. | ||
| This accelerator replaces all of that with a single row per eight copied bytes. |
There was a problem hiding this comment.
I'd recommend rewriting this in higher-level terms; after all, the reader does not immediately know how a CPU row compares to one of these rows.
| #footnote([Linux man-page on `memcpy`; man7.org. #link("https://man7.org/linux/man-pages/man3/memcpy.3.html")[[src]]]) | ||
| The guest performs such a copy with a RISC-V loop --- per copied doubleword a load, a store, two pointer increments and a branch, each of them a `CPU` row (@cpu) together with its memory operations. | ||
| This accelerator replaces all of that with a single row per eight copied bytes. | ||
| An accelerated `memcpy` is expected to conform to the Ethereum Foundation's Accelerated Memory Operations standard, which fixes the semantics the symbol must keep and how it must win linking. |
There was a problem hiding this comment.
The standard is set, right? In that case, it either conforms or it does not. Either we can get rid of "expected", or the entire sentence can be removed.
There was a problem hiding this comment.
Also, what does the following mean:
... the semantics the symbol must keep and how it must win linking
?
| This accelerator replaces all of that with a single row per eight copied bytes. | ||
| An accelerated `memcpy` is expected to conform to the Ethereum Foundation's Accelerated Memory Operations standard, which fixes the semantics the symbol must keep and how it must win linking. | ||
| #footnote([Accelerated Memory Operations; eth-act/zkevm-standards. #link("https://github.com/eth-act/zkevm-standards/tree/main/standards/accelerated-memory-operations")[[src]]]) | ||
| Both obligations fall on the guest-side stub and on the link, outside this chapter; what the standard asks of the chip itself is that it assume no particular alignment of `dst`, `src` or `count`, which @dma:c:tail guarantees by choosing the width from `count` alone. |
There was a problem hiding this comment.
I would move the analysis of why this adheres to the eth spec to a separate subsection somewhere at the bottom; this is the chapter header and things should be as concrete/short as reasonably possible here.
| = Assumptions | ||
| #render_chip_assumptions(chip, config) | ||
|
|
||
| The obligations on `src`, `dst` and `count` concern the _first_ row of a copy sequence only: |
There was a problem hiding this comment.
"obligations" => "assumptions"
"On the first row they are discharged by the register file, outside
this chapter."
Don't understand what that is supposed to mean. Consider rephrasing.
|
|
||
| #let config = load_config() | ||
| #let chip = load_chip("src/dma.toml", config) | ||
| #let dma = raw(chip.name) |
There was a problem hiding this comment.
Consider renaming the chip from dma to memmove; that more accurately describes what this chip actually does.
| The #dma chip copies a range of bytes from one location in memory to another, that is, it performs a `memcpy`. | ||
| #footnote([Linux man-page on `memcpy`; man7.org. #link("https://man7.org/linux/man-pages/man3/memcpy.3.html")[[src]]]) |
There was a problem hiding this comment.
this chip does memmove, not (just) memcpy (which does not work for overlapping data ranges)
| That is to say, | ||
| - `A0` contains the address of the first byte to write, | ||
| - `A1` contains the address of the first byte to read, and | ||
| - `A2` contains `count`. |
There was a problem hiding this comment.
| - `A2` contains `count`. | |
| - `A2` contains `count`; the number of bytes to copy. |
|
|
||
| @dma:c:read_dst, @dma:c:read_src and @dma:c:read_count read these three registers. | ||
| Each of them writes back the value that was read, so the copy leaves the registers untouched; | ||
| the guest is responsible for producing `memcpy`'s return value. |
There was a problem hiding this comment.
there is no return value? it is a void* function.
| A copy of $n$ bytes is therefore laid out as $floor(n \/ 8)$ eight-byte rows, followed by $n mod 8$ one-byte rows, followed by one terminal row. | ||
|
|
||
| Because a row is the unit in which this chip charges for a copy, an unbounded `count` would let a single guest instruction append an unbounded number of rows to the trace. | ||
| @dma:c:bound therefore proves $#`count` < 257$ on the first row of every sequence, which caps a sequence at $39$ rows --- attained at $n = 255$, not at $n = 256$, since a byte short of the bound trades one eight-byte row for seven one-byte rows. |
There was a problem hiding this comment.
Why limit the chip to copying 256 bytes at a time? We have the IS_HALF and IS_B20 range checks that can assert count < 65536 or even count < 1048576 at a smaller cost than calling the LT chip.
Description
Specifies the
DMAmemcpy table added by #874. It has one row per eight copied bytes (one on the tail), rows chained over a newDMA_NEXTbus,ECALLnumber -3. Adds theADDNWtemplate (ADDwithout wraparound) used for the address updates, and lists -3 in the ECALL overview.One deliberate deviation from #874's Rust: 31 columns rather than 32, because the spec models
timestampas aWord, as every other chapter does.