Naming Cookbook
- I still have _T signals, can this be fixed?
- I have so many wires with the same name, like
x
,x_1
andx_2
. How can I make them easier to understand? - How can I get better names for code generated by
when
clauses? - I still see _GEN signals, can this be fixed?
- How do I make my modules have more stable names instead of 'Module_1' and 'Module_42'?
- How would I write my own
typeName
for my data types? - I don't want to override
typeName
over and over! Is there any easy way to generate atypeName
? - Can I name my bundles in FIRRTL, so I don't generate extremely long bundle types?
- Why do I keep seeing _stripped suffixing everywhere in my FIRRTL? I didn't specify that in my
aliasName
. - I want to add some hardware or assertions, but each time I do all the signal names get bumped!
- I want to force a signal (or instance) name to something, how do I do that?
- How can I omit the prefix in certain parts of the code?
- I am still not getting the name I want. For example, inlining an instance changes my name!
I still have _T signals, can this be fixed?
See the next answer!
I have so many wires with the same name, like x
, x_1
and x_2
. How can I make them easier to understand?
Signals with _T
names or names that Chisel has to uniquify
often are intermediate values generated within loops, function calls, or when
predicates.
They can also be consumed by verification statements like assert
or prints
.
In these cases, the compiler plugin often can't find a good prefix for the generated
intermediate signals and can't name them at all or has to make up a unique name for them.
We recommend you manually insert calls to prefix
to clarify these cases:
import chisel3.experimental.prefix
class ExamplePrefix extends Module {
Seq.tabulate(2) { i =>
Seq.tabulate(2) { j =>
prefix(s"loop_${i}_${j}"){
val x = WireInit((i*0x10+j).U(8.W))
dontTouch(x)
}
}
}
}
// Generated by CIRCT firtool-1.94.0
module ExamplePrefix(
input clock,
reset
);
wire [7:0] loop_0_0_x = 8'h0;
wire [7:0] loop_0_1_x = 8'h1;
wire [7:0] loop_1_0_x = 8'h10;
wire [7:0] loop_1_1_x = 8'h11;
endmodule
How can I get better names for code generated by when
clauses?
The prefix
API can help with code inside when
clauses:
class ExampleWhenPrefix extends Module {
val in = IO(Input(UInt(4.W)))
val out = IO(Output(UInt(4.W)))
out := DontCare
Seq.tabulate(2) { i =>
val j = i + 1
prefix(s"clause_${j}") {
when (in === j.U) {
val foo = Reg(UInt(4.W))
foo := in + j.U(4.W)
out := foo
}
}
}
}
// Generated by CIRCT firtool-1.94.0
module ExampleWhenPrefix(
input clock,
reset,
input [3:0] in,
output [3:0] out
);
reg [3:0] clause_1_foo;
reg [3:0] clause_2_foo;
always @(posedge clock) begin
clause_1_foo <= in + 4'h1;
clause_2_foo <= in + 4'h2;
end // always @(posedge)
assign out = in == 4'h2 ? clause_2_foo : clause_1_foo;
endmodule
I still see _GEN signals, can this be fixed?
_GEN
signals are usually generated from the FIRRTL compiler, rather than the Chisel library. We are working on
renaming these signals with more context-dependent names, but it is a work in progress. Thanks for caring!
How do I make my modules have more stable names instead of 'Module_1' and 'Module_42'?
This is an example of the module instability problem, which results from several modules all sharing the exact same name. To fix this, you must add more specificity to your Module
's name to avoid these name collisions.
This can be done by leveraging the desiredName
and typeName
APIs.
desiredName
is for indicating the names of Modules
(e.g. influenced by the parameters passed in), and typeName
is useful for modules which are type-parameterized by subclasses of Data
. Overriding desiredName
can reduce or even eliminate name collisions. For instance, suppose your module looks like the following:
class MyModule[T <: Data](gen: T) extends Module {
// ...
}
We can override desiredName
of the module to include the type name of the gen
parameter like so:
class MyModule[T <: Data](gen: T) extends Module {
override def desiredName = s"MyModule_${gen.typeName}"
}
Any instances of your MyModule
will now have Verilog module names containing the type parameter.
val foo = Module(new MyModule(UInt(4.W))) // MyModule_UInt4 // MyModule_UInt4
val bar = Module(new MyModule(Vec(3, UInt(4.W)))) // MyModule_Vec3_UInt4
Note that all base Chisel util modules, like Queue
, already implement desiredName
like this:
val fooQueue = Module(new Queue(UInt(8.W), 4)) // Verilog module would be named 'Queue4_UInt8' // Verilog module would be named 'Queue4_UInt8'
val barQueue = Module(new Queue(SInt(12.W), 3)) // ... and 'Queue3_SInt12' // ... and 'Queue3_SInt12'
val bazQueue = Module(new Queue(Bool(), 16)) // ... and 'Queue16_Bool'
How would I write my own typeName
for my data types?
If you're using your own user-defined Bundle
, you can increase the specificity of its own typeName
by overriding it. All Data
types have a simple default implementation of typeName
(which is simply its class name), but you can override this yourself:
class MyBundle[T <: Data](gen: T, intParam: Int) extends Bundle {
// Generate a stable typeName for this Bundle. Two 'words' are present
// in this implementation: the bundle's name plus its integer parameter
// (something like 'MyBundle9')
// and the generator's typeName, which itself can be composed of 'words'
// (something like 'Vec3_UInt4')
override def typeName = s"MyBundle${intParam}_${gen.typeName}"
// ...
}
Now if you use your MyBundle
in a module like a Queue
:
val fooQueue = Module(new Queue(new MyBundle(UInt(4.W), 3), 16)) // Queue16_MyBundle3_UInt4
The suggested pattern for typeName
, and subsequently desiredName
, is to fold single integer-like parameters with the name itself (for example, Queue4
, UInt3
, MyBundle9
) to form 'words' and separate these 'words' with underscores (Queue4_UInt3
, FooBundle_BarType4
).
Bundles
that have multiple integer arguments aren't presently addressed by any of the built-in modules, and so implementing a descriptive and sufficiently differentiable typeName
for such Bundles
is left as an exercise to the reader. However, integers should not occur with an underscore before them at the very end of the typeName
(e.g. MyBundle_1
) because this is the same syntax used for duplicates, and so would cause confusion. Having to disambiguate modules all named Queue32_MyBundle_4_1
, Queue32_MyBundle_4_2
, Queue32_MyBundle_4_3
, and so on would be undesirable, indeed!
I don't want to override typeName
over and over! Is there any easy way to generate a typeName
?
Yes, with the experimental HasAutoTypename
trait. This trait can be mixed into your Bundle
s to automatically generate a tuple-like typeName
for them, based on the constructor parameters of that Bundle
. Let's look at the previous examples:
class MyBundle[T <: Data](gen: T, intParam: Int) extends Bundle {
override def typeName = s"MyBundle_${gen.typeName}_${intParam}"
// ...
}
new MyBundle(UInt(8.W), 3).typeName
// res7: String = "MyBundle_UInt<8>_3"
Auto-generated typeName
s take the form of {Bundle Name}_{Parameter Value 1}_{Parameter Value 2}_{...}
, and so our MyBundle
can be equivalently expressed with:
import chisel3.experimental.HasAutoTypename
class MyBundle[T <: Data](gen: T, intParam: Int) extends Bundle with HasAutoTypename {
// ...
// Note: No `override def typeName` statement here
}
new MyBundle(UInt(8.W), 3).typeName
// res9: String = "MyBundle_UInt<8>_3"
Can I name my bundles in FIRRTL, so I don't generate extremely long bundle types?
Yes, using the HasTypeAlias
trait. FIRRTL has a construct to alias a bundle type with a type alias like so:
circuit Top :
type MyBundle = { foo : UInt<8>, bar : UInt<1>}
module Top :
//...
These can be automatically emitted from Chisel by mixing HasTypeAlias
into a user-defined Record
, and implementing a field named aliasName
with a RecordAlias(...)
instance.
import chisel3.experimental.{HasTypeAlias, RecordAlias}
class AliasedBundle extends Bundle with HasTypeAlias {
override def aliasName = RecordAlias("MyAliasedBundle")
val foo = UInt(8.W)
val bar = Bool()
}
Let's see what happens when we generate FIRRTL using this Bundle
:
emitFIRRTL(new Module {
val wire = Wire(new AliasedBundle)
})
// res10: String = """FIRRTL version 4.1.0
// circuit _18_Anon :
// type MyAliasedBundle = { foo : UInt<8>, bar : UInt<1>}
//
// layer Verification, bind, "verification" :
// layer Assert, bind, "verification/assert" :
// layer Assume, bind, "verification/assume" :
// layer Cover, bind, "verification/cover" :
// public module _18_Anon : @[naming.md 232:28]
// input clock : Clock @[naming.md 232:28]
// input reset : UInt<1> @[naming.md 232:28]
//
// wire wire : MyAliasedBundle @[naming.md 233:18]
//
// """
HasTypeAlias
also supports nested bundles, too:
class Child extends Bundle with HasTypeAlias {
override def aliasName = RecordAlias("ChildBundle")
val x = UInt(8.W)
}
class Parent extends Bundle with HasTypeAlias {
override def aliasName = RecordAlias("ParentBundle")
val child = new Child
}
emitFIRRTL(new Module {
val wire = Wire(new Parent)
})
// res11: String = """FIRRTL version 4.1.0
// circuit _22_Anon :
// type ChildBundle = { x : UInt<8>}
// type ParentBundle = { child : ChildBundle}
//
// layer Verification, bind, "verification" :
// layer Assert, bind, "verification/assert" :
// layer Assume, bind, "verification/assume" :
// layer Cover, bind, "verification/cover" :
// public module _22_Anon : @[naming.md 255:28]
// input clock : Clock @[naming.md 255:28]
// input reset : UInt<1> @[naming.md 255:28]
//
// wire wire : ParentBundle @[naming.md 256:18]
//
// """
Why do I keep seeing _stripped suffixing everywhere in my FIRRTL? I didn't specify that in my aliasName
.
You're using an Input(...)
or Output(...)
in conjunction with an aliased Record
that contains a Flipped(...)
. These flipped values are stripped by Input
and Output
which fundamentally changes the type of the parent Record
:
class StrippedBundle extends Bundle with HasTypeAlias {
override def aliasName = RecordAlias("StrippedBundle")
val flipped = Flipped(UInt(8.W))
val normal = UInt(8.W)
}
emitFIRRTL(new Module {
val in = IO(Input(new StrippedBundle))
})
// res12: String = """FIRRTL version 4.1.0
// circuit _26_Anon :
// type StrippedBundle_stripped = { flipped : UInt<8>, normal : UInt<8>}
//
// layer Verification, bind, "verification" :
// layer Assert, bind, "verification/assert" :
// layer Assume, bind, "verification/assume" :
// layer Cover, bind, "verification/cover" :
// public module _26_Anon : @[naming.md 273:28]
// input clock : Clock @[naming.md 273:28]
// input reset : UInt<1> @[naming.md 273:28]
// input in : StrippedBundle_stripped @[naming.md 274:14]
//
// skip
//
// """
Note how the bundle type doesn't contain a flip flipped : UInt<8>
field, and the alias gains a "_stripped"
suffix! This Bundle
type is no longer the same as the one we wrote in Chisel, so we have to distinguish it as such.
By default, the suffix appended to Record
names is "_stripped"
. This can be defined by users with an additional string argument passed to RecordAlias(alias, strippedSuffix)
:
class CustomStrippedBundle extends Bundle with HasTypeAlias {
override def aliasName = RecordAlias("StrippedBundle", "Foo")
val flipped = Flipped(UInt(8.W))
val normal = UInt(8.W)
}
emitFIRRTL(new Module {
val in = IO(Input(new CustomStrippedBundle))
})
// res13: String = """FIRRTL version 4.1.0
// circuit _30_Anon :
// type StrippedBundleFoo = { flipped : UInt<8>, normal : UInt<8>}
//
// layer Verification, bind, "verification" :
// layer Assert, bind, "verification/assert" :
// layer Assume, bind, "verification/assume" :
// layer Cover, bind, "verification/cover" :
// public module _30_Anon : @[naming.md 291:28]
// input clock : Clock @[naming.md 291:28]
// input reset : UInt<1> @[naming.md 291:28]
// input in : StrippedBundleFoo @[naming.md 292:14]
//
// skip
//
// """
I want to add some hardware or assertions, but each time I do all the signal names get bumped!
This is the classic "ECO" problem, and we provide descriptions in explanation. In short, we recommend wrapping all additional logic in a prefix scope, which enables a unique namespace. This should prevent name collisions, which are what triggers all those annoying signal name bumps!
I want to force a signal (or instance) name to something, how do I do that?
Use the .suggestName
method, which is on all classes which subtype Data
.
How can I omit the prefix in certain parts of the code?
You can use the noPrefix { ... }
to strip the prefix from all signals generated in that scope.
import chisel3.experimental.noPrefix
class ExampleNoPrefix extends Module {
val in = IO(Input(UInt(2.W)))
val out = IO(Output(UInt(5.W)))
val add = noPrefix {
// foo will not get a prefix
val foo = RegNext(in + 1.U)
foo + in
}
out := add
}
// Generated by CIRCT firtool-1.94.0
module ExampleNoPrefix(
input clock,
reset,
input [1:0] in,
output [4:0] out
);
reg [1:0] foo;
always @(posedge clock)
foo <= in + 2'h1;
assign out = {3'h0, foo + in};
endmodule
I am still not getting the name I want. For example, inlining an instance changes my name!
In cases where a FIRRTL transform renames a signal/instance, you can use the forcename
API:
import chisel3.util.experimental.{forceName, InlineInstance}
class WrapperExample extends Module {
val in = IO(Input(UInt(3.W)))
val out = IO(Output(UInt(3.W)))
val inst = Module(new Wrapper)
inst.in := in
out := inst.out
}
class Wrapper extends Module with InlineInstance {
val in = IO(Input(UInt(3.W)))
val out = IO(Output(UInt(3.W)))
val inst = Module(new MyLeaf)
forceName(inst, "inst")
inst.in := in
out := inst.out
}
class MyLeaf extends Module {
val in = IO(Input(UInt(3.W)))
val out = IO(Output(UInt(3.W)))
out := in
}
// Generated by CIRCT firtool-1.94.0
module MyLeaf(
input [2:0] in,
output [2:0] out
);
assign out = in;
endmodule
module WrapperExample(
input clock,
reset,
input [2:0] in,
output [2:0] out
);
MyLeaf inst (
.in (in),
.out (out)
);
endmodule
This can be used to rename instances and non-aggregate typed signals.