-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Calyx-FIRRTL] Add fud2 support for FIRRTL-written primitives + externalized memory simulation #1898
Conversation
…with primitives. I will work on adding a new state tomorrow
There's a good chance I might make a big change to this branch, in which case I'll close this PR out for now. Apologies in advance! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!!! Super cool that this is working, and really nice work plumbing it all the way through the build tool and all that nonsense. This was unavoidable, but it's too bad that it required you to duplicate the fud2 Verilog states for another "style" (doubling the total Verilog variants to 4), but that's the way that it is!
Generally, I suggest we revisit this post-deadline and see what we can do to unify the two styles. But I strongly endorse cutting all corners temporarily to just make stuff work in the near term.
Another thing to put on the list as a post-deadline task: let's add your very helpful "usage" notes here to a new documentation page about the FIRRTL backend!
calyx-opt/src/passes/well_formed.rs
Outdated
// Main component cannot use `ref` cells | ||
if comp.name == ctx.entrypoint { | ||
if ctx.bc.emit_primitive_extmodules && comp.name == ctx.entrypoint { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll write a tiny bit more about this elsewhere, but what about using ctx.bc.synthesis_mode
? (That is, the --synthesis
flag to the Calyx compiler.) This flag already has the effect of disabling the readmemh
/writememh
"built-in testbench," which sorta implies that it is appropriate when you want "just the hardware" and nothing else. It seems like it would be safe to allow ref
in that case, because you're saying that you don't expect to use the compiled code with our little tb.sv
anyway? And there's a chance this would cause less test disruption…
fud2/graph.pdf
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps this was committed by mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for catching this 😅
fud2/src/main.rs
Outdated
e.var("testbench", &format!("{}/tb.sv", e.config_val("rsrc")?))?; | ||
Ok(()) | ||
}); | ||
let testbench_mem_externalized_setup = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is a suggestion purely about naming stuff: what if we came up with a single, short, made-up word that refers to this "externalized memory" concept? Even if it's less explanatory than mem_externalized
or mem-external
or other variants, being made-up will make it easier to grep for and to recognize the connections between these things.
Anything could work, but I propose refmem
(avoiding "externalized" to avoid confusion with the @external
annotation, which we are actually not using). So this would be called testbench_refmem_setup
.
fud2/src/main.rs
Outdated
let verilog_mem_external = bld.state("verilog-mem-external", &["sv"]); | ||
let verilog_noverify_mem_external = | ||
bld.state("verilog-noverify-mem-external", &["sv"]); // Need to use alternative testbench. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under my proposed naming convention, these states would be named something like verilog_refmem
and verilog_noverify_refmem
or whatever.
fud2/src/main.rs
Outdated
verilog_noverify, | ||
simulator, | ||
|e, input, output| { | ||
e.build("icarus-compile", input, output)?; | ||
Ok(()) | ||
}, | ||
); | ||
bld.op( | ||
"icarus-mem-external", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And this would be icarus-refmem
or whatever.
); | ||
|
||
let firrtl_primitives_setup = bld.setup("FIRRTL with primitives", |e| { | ||
e.rule("external-to-ref", "sed 's/@external([0-9]*)/ref/g' $in | sed 's/@external/ref/g' > $out")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The awesome power of sed!!!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's definitely up there in my list of favorite commands 😄
@@ -220,6 +304,13 @@ fn build_driver() -> Driver { | |||
verilog_noverify, | |||
firrtl_compile, | |||
); | |||
bld.op( | |||
"firrtl-with-primitives-noverify", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand why, but it is annoying we have to duplicate these FIRRTL compilers for the "noverify" variants! Otherwise, the Verilog will work with only Icarus or Verilator but not both. The real solution here, of course, is to somehow make our extra checks work in Icarus so we don't need this distinction… but that is a problem for another day.
tools/firrtl/generate-testbench.py
Outdated
with open(calyx_program) as f: | ||
for line in f: | ||
if ("ref" in line) and "comb_mem_d1" in line: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to admit that this is a very hacky way to extract the memory declarations from a Calyx program, but it will do for a v1.0! At some point, it would be nice to actually parse the Calyx syntax to extract these things… maybe with yet another custom backend. But don't let that stop you from forging ahead with this string-matching version for now!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree 😅 If I weren't pressed for time I definitely would've written a backend for this. I'll add it to my TODOs to fix this up after next week!
I wrote a little more about what to do (again, post-deadline) about the |
Thanks a lot @sampsyo for the review! I'm sorry I forgot to let you know that this PR still contains WIP, I should've closed out the PR but somehow thought the changes I'd need to make are minimal (haha). Nevertheless your feedback is extremely helpful!! I came up with an idea last night about how I can avoid making extra states in the fud2 setup while integrating my testbench generation script, so I'll spend a bit of time trying it out. If it doesn't work I'll defer to the multiple states setup for now and make the changes you suggested! Either way I'll make another comment when I'm done. |
I added full In my testing, I got to run some tests from the base If I can get another round of checking of this PR, I'd super appreciate it! |
This reverts commit fab34ab.
…since FIRRTL optimizes it away
Things generally look good here! I could be wrong, but it looks like a few unrelated changes might have gotten mixed up with this PR? See, for example, the I wouldn't worry about splitting this into smaller PRs—there are many FIRRTL-related things in here, and maybe we should just go ahead and merge the important ones? (And perhaps make ourselves a little to-do list of the small things to clean up afterward?) |
@sampsyo Really sorry for the mess! It seems like what happened is that a couple of days ago I (1) merged the The other smaller issue is that I have to update my testbench generation script to produce the new/correct signature for |
Got it; makes sense, and no worries!! It seems extremely reasonable to leave this PR here so that the eval repo can reference the exact commit with all of the caveats. What you suggest here sounds exactly right:
Namely, please do whatever's easiest/simplest, but one option could be to |
@sampsyo Awesome!! Thanks for the suggestion :) Will close this PR now accordingly! |
Sorry that the writeup is very long! There was a lot I wanted to verbalize... The
Simulating with externalized memories
section was also meant to be a potential FAQ so it's ok to be skipped.General
Currently, we have two "modes" of translating Calyx to FIRRTL with respect to primitives: (1) using
extmodule
in FIRRTL that uses the pre-existing Verilog implementation of primitives, (2) translating to FIRRTL implementations of primitives using a FIRRTL template and theprimitive-uses
backend. Previously, fud2 only supported (1) because I didn't have (2) implemented. This PR extends fud2 by allowing FIRRTL to be generated and simulated in both options.I tried to make this code-clone-free as possible, but please let me know of more improvements I can make!! Also, I'm not the biggest fan of the namings I'm using (ex.
verilog-mem-external
and others), so I'm more than happy to get suggestions on that front too.Simulating with externalized memories
I'd like to elaborate a bit on why there are weirdly so many moving parts in this PR, hopefully to answer potential questions like: "Why did you add so many states and transitions to fud2?", "What the heck is
externalized_mem_tb.sv
?".FIRRTL does not have a mechanism to dump memory contents a la
writememh
, which is how@external
memories are retrieved in simulation (implemented in the Verilog backend). Since we can't dump memory contents, we need to actually externalize the memory by turning its ports inside out. The problem with this is that the current Verilog testbench does not supportmain
components with externalized memories. So, I wrote an adapted testbench (externamized_mem_tb.sv
) that supportsmain
components with externalized memories, and also feed in the Verilog implementation ofstd_mem_d1
. That's whattestbench_mem_externalized_setup
does. I had to add a bunch of states and transitions to fud2 because (currently) this new testbench should be used if and only if we are simulating (2): FIRRTL with FIRRTL primitive implementations.Lastly, I'd like to try to answer this potential question:
This was causing a type error in the FIRRTL, since
clk
(that had the@clock
attribute) had typeClock
whereasmem_clk
(which didn't have@clock
) had typeUInt<1>
, andmem_clk
hadclk
supplied into it.@sampsyo suggested we replace
@external
withref
because (a)ref
cells get around this problem (it doesn't produce amem_clk
port in the first place), (b)ref
is much more general than@external
(and it might be good to haveref
simply subsume@external
sometime in the future). I'll try to make an issue about (b) soon, I just hope I can explain things well 😅That being said, I think my current changes for
calyx-opt/src/passes/well_formed.rs
are not quite it, since I didn't want to break the CI build. It would be nice if I can limit that conditional to just when thefirrtl
andprimitive-uses
backends are used, but I wasn't sure how to effectively do that... Suggestions would be very appreciated!Usage
To generate + simulate (1) FIRRTL with Verilog primitive implementations, you can continue using
--to firrtl
and--through firrtl
.To generate (2) FIRRTL with FIRRTL primitive implementations, please use
--to firrtl-with-primitives
.ex)
To simulate (2) FIRRTL with FIRRTL primitive implementations, you can use
--through firrtl-with-primitives
.ex)
Below is the fud2 graph that got generated when I ran the above command with
-m graph
:Sorry if it's hard to read, but I hope the picture helps conceptualize what's going on! Please let me know if you have any questions, or let me know of any suggestions!!!