Skip to content

spec: DMA memcpy accelerator - #931

Open
nicole-graus wants to merge 6 commits into
spec/mainfrom
spec/dma-memcpy
Open

spec: DMA memcpy accelerator#931
nicole-graus wants to merge 6 commits into
spec/mainfrom
spec/dma-memcpy

Conversation

@nicole-graus

@nicole-graus nicole-graus commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Description

Specifies the DMA memcpy table added by #874. It has one row per eight copied bytes (one on the tail), rows chained over a new DMA_NEXT bus, ECALL number -3. Adds the ADDNW template (ADD without 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 timestamp as a Word, as every other chapter does.

@nicole-graus
nicole-graus changed the base branch from main to spec/main August 11, 2026 20:04
@erik-3milabs

Copy link
Copy Markdown
Collaborator

Quick review:

  1. As mentioned during yesterday's meeting, this chip was implemented to adhere to the EF's standardization efforts.
    Consider linking the standard (https://github.com/eth-act/zkevm-standards/tree/main/standards/accelerated-memory-operations) in the accelerator's description.
  2. I don't know whether 'DMA' is the right name for this: DMA refers to a category of operations, while this is just one of them.

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 erik-3milabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

@erik-3milabs erik-3milabs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first batch of comments; I'll review the remainder on Monday

Comment thread spec/dma.typ

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"

Comment thread spec/dma.typ
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread spec/dma.typ
#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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what does the following mean:

... the semantics the symbol must keep and how it must win linking

?

Comment thread spec/dma.typ
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread spec/dma.typ
= Assumptions
#render_chip_assumptions(chip, config)

The obligations on `src`, `dst` and `count` concern the _first_ row of a copy sequence only:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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.

Comment thread spec/dma.typ

#let config = load_config()
#let chip = load_chip("src/dma.toml", config)
#let dma = raw(chip.name)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming the chip from dma to memmove; that more accurately describes what this chip actually does.

Comment thread spec/dma.typ
Comment on lines +19 to +20
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]]])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this chip does memmove, not (just) memcpy (which does not work for overlapping data ranges)

Comment thread spec/dma.typ
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`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `A2` contains `count`.
- `A2` contains `count`; the number of bytes to copy.

Comment thread spec/dma.typ

@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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no return value? it is a void* function.

Comment thread spec/dma.typ
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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants