I think it would be great to have some common tooling/infrastructure to facilitate flattening out such nested types. For things like a simulator or a synthesizer, I’m pretty sure that aggregating signals into structs/bundles/interfaces is more of a “debug information” kind of thing, rather than something the tool can directly leverage. My guess is that the dialects at a low level of abstraction (cables and drivers/gates rather than interfaces and producers/consumers) would want to have somewhat flat and simple types. But at a higher level it’d be great to have such bi-directional aggregates around – to help emit better SV and maybe catch directionality errors?
Aggregates in the RTL Dialect
Regarding whether the RTL dialect should depend on the SV dialect types, I’d argue that the SV type system is actually not very good at anything beyond simple multi-dimensional wires. Interfaces have gained some tool support recently, and they do offer a form of bidirectionality and signal bundling, but nesting interfaces is not well-supported. Also, the concept of modport
s is geared towards testing and verification (e.g. regular input/output modports, plus an all-input “bus checker” modport), and in the context of an SSA RTL dialect with proper def-use it’s not even quite clear how you would wire up an interface with three modports (who’s the third party?). In practice I would expect interfaces to always have two exactly complementary modports; seems like overkill if all we want is to have aggregation alongside the notion of a producer-consumer relationship.
In my opinion FIRRTL’s concept of bundles and bidirectionality would be a better fit for the RTL dialect. The concept of “here’s an aggregation of wires” and “expect these to flow in the opposite sense of traffic” seems to me to be more succinct and have less “surface area”.
FIRRTL Bundles in LLHD
As @mikeurbach mentioned, I’ve started to look into a lowering from FIRRTL to LLHD:
LLHD currently does not support bidirectional structs/bundles, in order to keep simulation and hand-off to a synthesizer easy. SystemVerilog interfaces pose a similar issue as FIRRTL bundles, due to their bidirectional nature. Although FIRRTL seems to take this a step further by allowing nested bundles/flips – SV has some support for nested interfaces in the standard, but I doublt that is well-supported in commercial tools.
The Moore compiler currently flattens out SystemVerilog interfaces when emitting LLHD, which can be a bit nasty if there are arrays of interfaces. I figure with nested interfaces this would become even more involved. Currently the following SystemVerilog (copy-paste into www.llhd.io):
module foo (
bar.in x,
bar.out y[3:0]
);
endmodule
interface bar;
logic [31:0] data;
logic valid;
logic ready;
modport in (input data, valid, output ready);
modport out (output data, valid, input ready);
endinterface
Translates to the following LLHD:
entity @foo (
i32$ %x.data,
i1$ %x.valid,
[4 x i1]$ %y.ready
) -> (
i1$ %x.ready,
[4 x i32]$ %y.data,
[4 x i1]$ %y.valid
) {
...
}
LLHD has an added level of nasty by separating inputs from outputs – although I intend to get rid of that in favor of some "input"
/"output"
annotation as you do in the SV dialect.
Considering a nested FIRRTL bundle, like something along the following lines:
firrtl.circuit "foo" {
firrtl.module @foo(%x: !firrtl.flip<bundle<
payload: bundle<
req: uint<32>,
rsp: flip<uint<4>>>,
valid: uint<1>,
ready: flip<uint<1>>) {
...
}
}
We probably want some FIRRTL-to-FIRRTL pass which gets rid of the bundles, and resolves the subfield
ops accordingly, as you guys already discussed on Discourse:
firrtl.circuit "foo" {
firrtl.module @foo(
%x.payload.req: !firrtl.flip<uint<32>>,
%x.payload.rsp: uint<4>,
%x.payload.valid: !firrtl.flip<uint<1>>,
%x.payload.ready: !firrtl.uint<1>
) {
...
}
}
It would be great to have such a “single-flip-no-bundles” representation of FIRRTL. This should then be a pretty straightforward conversion to LLHD:
entity @foo (
i4$ %x.payload.rsp,
i1$ %x.payload.ready
) -> (
i32$ %x.payload.req,
i1$ %x.payload.valid
) {
...
}
When converting to an SV dialect, one could simply not do that transformation, to leverage the higher-level correspondence of bundles to interfaces.