Skip to content

[WIP, PoC] implementation of RFC 74 "Structured VCD"#1670

Draft
alikates wants to merge 3 commits into
amaranth-lang:mainfrom
alikates:main
Draft

[WIP, PoC] implementation of RFC 74 "Structured VCD"#1670
alikates wants to merge 3 commits into
amaranth-lang:mainfrom
alikates:main

Conversation

@alikates

@alikates alikates commented Jul 6, 2026

Copy link
Copy Markdown

Initial proof of concept implementation of RFC 74 "Structured VCD".

It needs a version of pyvcd with the new vhdl_record and vhdl_array scope types. I have a fork here.

This is mainly me slamming my head against the wall until it kind of works.

Keep in mind that right now this only works for individual signals passed through the traces argument of write_vcd. I guess I'll need to edit the fragment traversal part to also extract the slice signals from the actual design.

The changes mainly consist on recursively traversing the struct/array members, extending the scope with the name of the parent and adding it to the trace_names dict. As I said, I'll need to implement adding the design signals to signal_names, but the algorithm is probably the same.

This can be tested with:

frag = Fragment()
a = Signal(data.StructLayout({
        "b": 4,
        "c": data.StructLayout({
            "d": 3,
            "e": 4,
        })
    }))
w = Signal(data.StructLayout({
    "x": 4,
    "y": data.ArrayLayout(3, 3)
}))
sim = Simulator(frag)
with sim.write_vcd("test.vcd", "test.gtkw", traces=(a, w,)):
    sim.run()

Surfer is sometimes having issues reading the VCDs. Here are some screenshots of how the previous tests is rendered in both Surfer and GTKWave:

image image

@alikates

alikates commented Jul 9, 2026

Copy link
Copy Markdown
Author

So, I've tried with a struct signal in an Elaboratable and seems to be working fine too.

I've also checked how Verilator does things, and seems like they just use a module scope for the structs. Of course this is completely valid given the VCD spec, so I'm wondering if there was any reason with the early versions of Amaranth why it was decided to flatten the struct signals (maybe performance?). Please let me know if there is or I'm missing something.

In fact this PoC just does that, prevents flattening of the signals and passes the correct scope to PyVCD.

With respect to the scope types, I guess vhdl_record and vhdl_array are more appropriate in this case instead of using module like Verilator does. But given that the RFC mentions a possible compatibility issue, I wonder if it wouldn't be better to just switch between both options depending on the compatibility flag. So in the end the vhdl_* types are only useful to differentiate between module and struct scopes, but are not needed to get the structured/hierarchical VCDs.

@whitequark

Copy link
Copy Markdown
Member

I'm wondering if there was any reason with the early versions of Amaranth why it was decided to flatten the struct signals (maybe performance?)

I'm not sure I remember exactly. @wanda-phi, do you?

@wanda-phi

Copy link
Copy Markdown
Member

I'm wondering if there was any reason with the early versions of Amaranth why it was decided to flatten the struct signals (maybe performance?)

I'm not sure I remember exactly. @wanda-phi, do you?

no idea, sorry

@whitequark

Copy link
Copy Markdown
Member

@alikates I think the reason was probably that we tried to stay 100% VCD-compliant and not use non-standard records. I thought for a bit that the goal was to emit the same signals as when doing Verilog export, but I don't think there's actually direct correspondence, even the names don't match.

(I still haven't found time to review the PR, sorry. It has been another heatwave here.)

@alikates

Copy link
Copy Markdown
Author

What I meant is that by using module scope type (which is defined in the spec), we could achieve a similar result as with vhdl_*. Obviously there's a semantic difference but in practice the viewers are going to show the same structure. The only difference that I've noticed is GTKWave showing a different symbol in the scope view.

(I still haven't found time to review the PR, sorry. It has been another heatwave here.)

No worries, take care!

@alikates

Copy link
Copy Markdown
Author

So now there's an awkward situation where structs look good, but interface members are still flattened. Not sure what it would take to match how structs are handled, but it might be worth of a separate RFC/implementation.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants