Naming
Name Collisions & Shadowing
When translating from Verilog/VHDL, signal, port, and module names may collide with names already in scope: Scala keywords, DFHDL built-ins, or your own design classes. This section is the single place that covers how to detect and resolve all such collisions.
General recommendation: Instantiate designs with new
Always instantiate a child design with new DesignName(...):
1 | |
The new keyword forces resolution to the class constructor, so the instantiation can never be captured by a value, a port, or a DFHDL built-in function that happens to share the name. Writing Adder(WIDTH = 16) relies on Scala 3 universal apply methods, which resolve by name and can therefore be shadowed. Using new everywhere removes the entire class of instantiation collisions before it appears, so it is the recommended form throughout this documentation.
Additional recommendation: Capitalize design-class names
On top of new, a naming convention keeps the two namespaces visually distinct:
- Name design classes with a
Capitalized(PascalCase) name. - Name ports and variables with
camelCasenames.
Because the two casings can never be identical, a design class and a value will never shadow each other. This is the preferred convention for new designs.
1 2 3 4 5 6 7 8 | |
Caveat: direct Verilog/VHDL translation that preserves original names
When you translate an existing Verilog/VHDL design and deliberately preserve the original names (so the generated HDL matches the source), you cannot always apply the Capitalized convention, since the original names may already collide. These cases need the targeted resolutions below.
Scala reserved keywords
Scala keywords cannot be used directly as identifiers. Escape them with backticks:
val, var, def, type, class, object, trait, enum, match, case, if, else, for, while, do, return, throw, try, catch, finally, yield, import, export, new, this, super, true, false, null, then, end, given, using, extension, with, abstract, final, override, sealed, lazy, private, protected
1 2 3 | |
DFHDL built-in names
import dfhdl.* brings DFHDL built-in functions and types into scope. If a user-defined class has the same name as a built-in, the built-in shadows the class. Built-ins that commonly collide with Verilog module names:
abs, clog2, max, min, all, Bit, Bits, UInt, SInt
1 2 3 4 5 6 7 | |
This is the general new recommendation applied to a built-in collision. Following it from the start makes this collision a non-issue.
Design-class name shared with a value name
A design class may share its name with a port or variable in scope. This is not a collision that needs resolving: Scala keeps types and terms in separate namespaces, so the class stays reachable and the value keeps its name.
1 2 3 4 5 6 7 8 9 10 11 12 | |
| Generated Verilog | |
|---|---|
1 2 3 4 5 | |
The port keeps the name stage and the child module is still instantiated from the class of the same name. The one form that goes wrong is the bare apply, and only because the value wins the term position:
1 | |
It fails in a way worth recognizing, because it usually stays silent until something downstream reads a member off it:
1 | |
That is stage(WIDTH) having quietly become a bit-select on the port. Always instantiating with new, per the general recommendation, removes the whole class of problems and needs no renaming and no annotation.
Resolution Patterns
Backtick escaping
For Scala keywords used as signal names:
1 2 | |
@setName annotation
@hw.annotation.setName applies to a port, variable, or DFHDL method, and sets the name that construct carries in the generated HDL. Use it when the Scala-side identifier must differ from the HDL name you need to emit:
1 2 3 4 | |
| Generated Verilog | |
|---|---|
1 2 3 | |
The same annotation applies to a design class, where it sets the emitted module name. This is what lets a translation follow Scala naming style on the Scala side while still emitting the original Verilog module name. It works on top-level classes too, where Scala's own @targetName is rejected (the DFHDL compiler plugin reads the annotation, not the Scala backend):
1 2 3 4 5 | |
Not for names that merely look alike
A port sharing a name with a design class needs no annotation and no rename, since types and terms live in separate namespaces. See Design-class name shared with a value name. Reach for @hw.annotation.setName when you need a different HDL name, not when two Scala names collide.