Clock and reset domains in the RTL dialect

Having to pass around clk and rstn like they’re just normal wires is one of the many pet peeves I have with SystemVerilog. I don’t want to repeat it in the RTL dialect – there must be a better way.

Clocks and resets are not normal wires

Of course, they are just very high fan-out wires which have to go everywhere. They differ from “normal” wires which carry signals significantly:

  • They are needed virtually everywhere! All (standard) sequential logic needs them. They make virtually no difference at the functional level except to cause bugs.
  • Synthesis engines need to recognize them and treat them specially. ASIC synthesis engines have significant complexity in designing clock trees. FPGA synthesizers need to map them to special clock networks. I’m not sure what – specifically – they do for reset logic but it’s my understanding that if you do a poor job designing your reset logic, your timing performance will suffer.
  • As a result of the above, you really don’t want to mess with the clock signal. It’s a rookie mistake to muck with a clock signal (e.g. naïvely divide it). Many people have gotten burned by tools not recognizing their custom logic on clocks. FPGAs (at least) have hardened circuitry to work with clocks which designers should pretty much always be using.

Designers (esp. ASIC/SoC designers) think of things like clock domains, reset domains, and power domains. While the power domain is out-of-scope for CIRCT (at least for now), it provides a good model: it is implicitly everywhere and special logic needs to be added at the boundaries of different power domains (e.g. situations where one domain was off but is powering up, different voltages, etc.)

Explicit clock and reset domains

I propose that we create an explicit notion of clock and reset domains.

Ubiquity

The model should be a symbol so we don’t have to pass it around everywhere. Operations can have an attribute which specifies the symbol of the clock and reset domains to which it is assigned. Said attributes should be inherited. No more clock and reset arguments!

Clock and reset domain relationship

We cannot assume that clock and reset domains will always be the same as it is common to reset one part of a design separately from the others regardless of the clock domains in which they reside. However, given that resets are often synchronously de-asserted (and really should always be to avoid metastability), it is reasonable to model a reset domain as belonging to a clock domain.

I think we should model clock domains as a flat set and a tree of reset domains under each one. This won’t cover all possible cases but it should cover the most common cases.

Thoughts?

Hey John,

I completely agree with your observation and motivations, but I don’t think that we should standardize anything like this in the RTL dialect.

FIRRTL went down a similar path, where it has clock, reset, async reset types. These have been useful, but don’t cover the full gamut of behaviors one might want to model for higher level types, for example some domains might want to model clock frequency and many other things.

I think this is best left to higher level dialects than the RTL dialect. Particularly as you go about modeling clock domains, such things are even more complicated, and various clients will want to have support for multiple domains in a single module. I don’t think this complexity (and the wide design space) is appropriate in the RTL dialect.

That said, some parts of this (custom clock types etc) should fit just fine as custom types in RTL ports, so I don’t see a problem with using piece of the RTL dialect with such concepts.

-Chris

Yeah, you’re right this is non-standard, experimental idea and we probably shouldn’t put this in the standard RTL dialect. It also would only serve to clean up the IR, which isn’t what users see. It’s probably best to put it in a future, higher level dialect.

I’d put this in the bucket of front-end language design for now.

Two interesting data points for how different front-end languages worked with this:

Chisel3

Chisel has a small type hierarchy of hardware modules (these will become firrtl.FModuleOp):

  1. RawModule: A module without a clock and reset
  2. MultiIOModule: A module with an implicit clock and reset

Clocked hardware objects (registers, assert statements, etc.) are passed the implicit clock and reset and error if no implicit clock and reset are found. You can then change the implicit clock and reset in some scope using: withClock, withReset, and withClockAndReset. See: documentation.

SpinalHDL

(I have less knowledge here, but will try to explain what I know…)

SpinalHDL uses a notion of an Area which is like an anonymous hardware module (which it calls a Component from the VHDL notion). There’s then a, ClockDomain, which is a parameter to a ClockArea that lets you set all the properties you want about clocks, resets, etc. including some physical design-level concerns like the actual frequency for that area. See: documentation.

Nice!

Perhaps we should create an experimental dialect to expose shared features (like this) up to languages.