
Chisel/FIRRTL Hardware Compiler Framework - xvilka
https://www.chisel-lang.org/
======
raxrbx64
I really wanted to like Chisel but after using it for an actual chip design,
I’ve realized it leaves a lot to be desired – mainly relating to speed and
readability.

For starters, it doesn’t seem to scale well. For a moderately complex design,
it takes on the order of several minutes to generate Verilog code. When trying
to work in a tight iteration debug loop this very much hinders productivity.
In addition, it tends to eat up memory, too.

This is more of a scala/sbt thing, but typically the Chisel verilog generator
is run via sbt which seems to only be able to run one thing at a time, so
generating multiple (independent) modules described in the same project is not
parallelizable without some finagling.

One thing I’ve noticed is, in an effort to support stable flattening and
unflattening bundles to bit-vectors, the Chisel frontend will spend a large
amount of its time doing reflection to get (bundle) class member names and
sorting them (This I found after running it through a profiler – I apologize I
don’t have those results handy).

The standard config environment for Chisel, CDE, makes things hard to
understand because configuration for a design isn’t all kept in one place, but
might be partially modified at any point in the code. This negatively impacts
readability because one has to dive through and essentially understand the
run-time call-stack in order to properly assemble the configuration in their
head to diagnose why a particular value is set a certain way. (Reminds me of
CSS, actually).

Also, CDE is essentially a layered switch case statement, which means it has
O(n) lookup time which is also a big perf hit. In addition, each layer that
does not contain a value throws an exception which also impacts performance
when a large number of config lookups are happening in a design.

~~~
seldridge
Thanks for taking a look at Chisel and FIRRTL!

(Coming from a Chisel/FIRRTL dev...) Couple of clarifying comments:

CDE[^1] is really a Rocket Chip[^2] specific design decision meant to suit the
configuration needs of system-on-chip generation (or: it's a Scala library
which actually doesn't depend on Chisel and could be useful in unrelated
projects). Also, SiFive should have fixed the issues with exceptions a long
while ago (stack traces are still a thing, though).

Chisel gets _a lot_ of criticism due to the (necessary) complexities of Rocket
Chip. However, don't let that dissuade you from using it for a separate
digital design project. None of the Rocket Chip complexity comes into play
there.

Compilation time is something that we really care about and are seeking to
make better. Minute-long Verilog generation times are something you would only
see for mammoth design like Rocket Chip (generating MBs of Verilog).
Nonetheless, we have some ideas on how to improve this via actual
optimizations or meta-optimizations like grouping compiler transformations
together that are safe to do so.

We also are really trying to make the Verification easier. One of these is
effort on better testing via "Testers2"[^3] (name is TBD). The second is on
improving the readability of the generated Verilog, e.g., emission of case
statements [^4], emission of else-if[^5] (now supported!), etc. If you have
suggestions we'd be happy to take a look (code examples of "I got this, but
I'd like that" would be a huge plus, too!).

Regardless, thanks for taking the time to check it out.

[^1]: [https://github.com/chipsalliance/api-config-
chipsalliance](https://github.com/chipsalliance/api-config-chipsalliance)

[^2]: [https://github.com/chipsalliance/rocket-
chip](https://github.com/chipsalliance/rocket-chip)

[^3]: [https://github.com/ucb-bar/chisel-testers2](https://github.com/ucb-
bar/chisel-testers2)

[^4]:
[https://github.com/freechipsproject/chisel3/issues/1198](https://github.com/freechipsproject/chisel3/issues/1198)

[^5]:
[https://github.com/freechipsproject/firrtl/pull/1204](https://github.com/freechipsproject/firrtl/pull/1204)

------
_nhynes
I used Chisel to make a relatively simple memory encryption engine AXI
component for FPGA. In my experience, the typedness and composability of
Modules makes it significantly more productive than directly writing Verilog.
There's an escape hatch, too: interfacing with vendored IP and hard macros is
straightforwrd using `BlackBox` (DI is useful for mocking these in tests). My
only wish is that Scala properly supported macros.

One of my favorite components of the ecosystem is [https://github.com/ucb-
bar/chisel-testers2](https://github.com/ucb-bar/chisel-testers2), which
replaces the peekpoke tester and makes it easier to test asynchronous IO.

~~~
Nullabillity
> My only wish is that Scala properly supported macros.

The documentation isn't great, but Scala has a very flexible macro system
([https://docs.scala-
lang.org/overviews/macros/overview.html](https://docs.scala-
lang.org/overviews/macros/overview.html)).

------
323454
I've had great fun using Chisel to write customizable hardware implementations
of machine learning operations. If anyone is interested in this kind of stuff
/ working in Chisel, feel free to email me tom at tensil dot ai

~~~
seldridge
And if this is interesting, Tom gave a great talk at the 2018 Chisel Community
Conference on his experiences at that time:
[https://youtu.be/x_fzoxGpZ_g](https://youtu.be/x_fzoxGpZ_g)

------
tonmoy
I had looked at Chisel a couple of years ago, so I don’t remember much. From
the example on the front page, I don’t understand how the generate part is
different from the generate block in Verilog. The reduce filter function usage
is cool and all, but also can be done with generate and for loop in Verilog as
well

~~~
seldridge
Thanks for looking into Chisel!

Great question! However, this is an _incredibly_ difficult question to answer
as it relies on comparing language power. Paul Graham's "Beating the Averages"
essay gets into this with the "Blub Paradox" [^1]. (tl;dr: a programmer versed
in one programming language can evaluate less powerful languages, but not more
powerful languages.)

The FIR filter example shown is parametric. Verilog is _also_ parametric.
However, Chisel, because it's embedded in Scala, gives you other programming
paradigms/features that Verilog/VHDL do not have (or vendor tools do not
support): object oriented programming, functional programming, parametric
polymorphism, first class function support, etc.

The example of the front page could, instead of taking a `Seq[UInt]`, take a
type parameter and be parametric for an arbitrary Chisel datatype (`UInt`,
`SInt`, `FixedPoint`, etc.). Something like this just isn't possible with
Verilog/VHDL. Analogously, Python and assembly both can describe for loops,
but there are better dimensions for comparison.

Problematically, if shown advanced features like parametric polymorphism too
early (e.g., on the front page of the website) potential users will get
confused and turn away. If shown an example too simple, but recognizable,
users will see no benefits. Alternatively, Chisel does address SystemVerilog
pain points. Michael Taylor does a nice job of elucidating these in Section 5
of [^2].

As this question comes up a lot, I've tried to iterate on an answer on SO
which may also be a useful read [^3].

If you have any suggestions on better ways to get this across, any feedback is
welcome, too.

[^1]: [http://www.paulgraham.com/avg.html](http://www.paulgraham.com/avg.html)

[^2]:
[http://cseweb.ucsd.edu/~mbtaylor/papers/Taylor_DAC_BaseJump_...](http://cseweb.ucsd.edu/~mbtaylor/papers/Taylor_DAC_BaseJump_STL_2018.pdf)

[^3]: [https://stackoverflow.com/questions/53007782/what-
benefits-d...](https://stackoverflow.com/questions/53007782/what-benefits-
does-chisel-offer-over-classic-hardware-description-languages)

------
teleforce
It seems that FIRRTL is designed to be the LLVM of hardware programming. If
Scala is not your cup of tea, the co-designer of FIRRTL, Patrick Li has
designed a new optionally type programming language Stanza that is more
expressive for this kind of work. FYI, the designers of FIRRTL then went to
start Jitx, a circuit design automation company using Stanza to perform
circuit design automation. Alternatively, if you prefer a more established
language than Stanza, dlang can be a great substitute for Scala:
[https://dconf.org/2017/talks/marques.html](https://dconf.org/2017/talks/marques.html)

------
panpanna
I'm not a huge fan of chisel.

I decided to give it a serious chance, allocated a few weeks to learn Scala
and chisel and had some test projects to try it on.

In the end I gave up not really having seen the benefits of chisel over
systemverilog or even vhdl. The riscv design that was the posterchild of
chisel efficiency was coded in pure verilog by someone who knew his trade and
the verilog version looks so much cleaner.

If I were to describe chisel in one word it would be "arrogance".

------
seldridge
One of the Chisel/FIRRTL devs here available to answer any questions.

tl;dr: Chisel/FIRRTL is trying to be "LLVM for circuits".

Concretely, Chisel is a domain specific language for describing hardware in
Scala. The Chisel front-end generates circuit IR (Flexible Intermediate
Representation for RTL/FIRRTL), FIRRTL IR is then transformed/customized by
the middle-end FIRRTL compiler, and finally emitted via a Verilog backend (and
then fed into FPGA/ASIC tooling).

It's not High Level Synthesis, just powerful hardware description. You get all
the features of Scala (object-oriented programming, functional programming,
first class functions, parametric polymorphism) to write programs that
generate circuits. Sadly, the last 50 years of software engineering is
traditionally not available to hardware designers in classic languages like
Verilog or VHDL. Chisel/FIRRTL is one solution to that.

We just released Chisel 3.2 and FIRRTL 1.2 which was a massive update. Notable
additions include:

\- Asynchronous Reset/Reset Inference:
[https://github.com/freechipsproject/chisel3/pull/1011](https://github.com/freechipsproject/chisel3/pull/1011)

\- BoringUtils (synthesizable cross module references):
[https://github.com/freechipsproject/chisel3/pull/718](https://github.com/freechipsproject/chisel3/pull/718)

\- Strongly Typed Enums:
[https://github.com/freechipsproject/chisel3/pull/892](https://github.com/freechipsproject/chisel3/pull/892)

\- Refactor of Chisel and FIRRTL as Stages of Phases:
[https://github.com/freechipsproject/firrtl/pull/1005](https://github.com/freechipsproject/firrtl/pull/1005)
(and others)

\- Aspect Oriented Programming:
[https://github.com/freechipsproject/chisel3/pull/1077](https://github.com/freechipsproject/chisel3/pull/1077)

\- Lots of documentation improvements: new website, dramatically increased
Scaladoc

Going forward, we're trying to get the release cadence up and are pushing to
make the verification problem easier. Others have mentioned Testers2 which is
one effort in that area. A code coverage/assertion library is another effort.

~~~
moring
How do Chisel/FIRRTL handle inference of built-in primitives like synchronous
RAM blocks in FPGAs?

I have built my own HDL, which is basically "cleaner Verilog" and not a
generator-style approach like Chisel, and gets compiled to Verilog. One big
problem I had was how to describe RAM blocks with synchronous read/write
ports, or even worse, RAM blocks with two independent ports which are both
synchronous read/write (i.e. BlockRAM in Xilinx FPGAs).

My intention was to make the HDL more powerful than just providing BlockRAM as
a built-in module that can be instantiated, because this way the "assignment"
of the read/write port, which determines clock/enable logic, can be merged
into other synchronous blocks using the same clock and enable signals (nested
if-statements), thus be more readable. But I never found an easy way to
"extract" the BlockRAM's output register and enable out of a statement block,
short of writing a full primitive inference system myself (which I tried to
avoid).

Without such extraction, I could only convert the statement to a Verilog
statement and rely on the inference from Xilinx's tools. I ended up with
"patterns" that the hardware developer has to use, very similar to Xilinx's
primitive instantiation templates, which would be compiled to the appropriate
patterns in Verilog. Naturally this takes several tries until Xilinx's tools
recognize what I intended to build. In retrospect, providing built-in
submodules would have been easier.

~~~
seldridge
For non-BRAM/SRAM primitives that you explicitly want to use, your best bet
would be a blackbox. However, for memory, Chisel has built in memory hardware
types `Mem` (synchronous write/asynchronous read) and `SyncReadMem`
(synchronous write/synchronous read). A read or a write access to these infer
a port.

On the FIRRTL side, there's a dedicated pass `ReplSeqMems` that will replace
sequential memories with a blackbox and configuration file. The intent here is
that the configuration file (describing info like width, depth, number of
ports, etc.) can then be used as input to an SRAM generator.

For FPGAS, (and I may be wrong here), I think that without `ReplSeqMems`, when
using `SyncReadMem`, things will automatically get inferred to BRAM for Xilinx
tools. However, the same approach to `ReplSeqMems` could be used to replace
memories with the correct template for a specific FPGA vendor tool.

------
rowanG077
Why should I use this instead of Clash?

~~~
seldridge
Thanks for your question.

There are some different design decisions between Chisel and Clash (and one or
the other may work better for you!). Chisel is an embedded domain specific
language in Scala that uses added hardware primitives to build a circuit graph
and emit FIRRTL IR. Clash is a Haskell derivative that (in my limited
understanding) reads a Haskell program, but interprets it using hardware
semantics, eventually emitting Verilog. They are both hardware description
languages and not HLS (c-to-gates).

The Chisel ecosystem is larger, currently. This is primarily due to UC
Berkeley/SiFive projects (Rocket Chip RISC-V SoC generator, BOOM out-of-order
processor, Hwacha vector accelerator, etc.).

One meta-difference is FIRRTL. Chisel/FIRRTL is trying to be a hardware
compiler framework, analogous to LLVM, but for circuits. Chisel is only the
front-end. You can interface other front-ends with or write your own front-end
for FIRRTL (currently Yosys can target FIRRTL IT for Verilog -> FIRRTL IR).
You then have a simple circuit IR to Target, but get access to all the
existing FIRRTL transforms and have a path to Verilog for FPGA/ASIC.
Relatedly, you can inject custom FIRRTL transforms into the FIRRTL compiler
(one example being to add run-time fault injectors:
[https://github.com/IBM/chiffre](https://github.com/IBM/chiffre)).

All that said... Host language matters. If you're comfortable with Haskell (or
Python), use what works! And for new/existing languages, targeting FIRRTL IR
is an option.

More resources:

\- [https://clash-lang.readthedocs.io/en/latest/faq.html](https://clash-
lang.readthedocs.io/en/latest/faq.html)

\-
[https://stackoverflow.com/q/27472473/3870549](https://stackoverflow.com/q/27472473/3870549)

