-
Notifications
You must be signed in to change notification settings - Fork 615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support separately elaborating definition and instance in ChiselStage #2512
Conversation
core/src/main/scala/chisel3/experimental/hierarchy/core/Instance.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/chisel3/experimental/hierarchy/core/Instance.scala
Outdated
Show resolved
Hide resolved
src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
Outdated
Show resolved
Hide resolved
src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Do you think this can be backported to 3.5?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update tests according to our feedback. Also, we should record in the PR description future work to create an API to instantiate a previously-defined Definition, which is not passing the Definition via an argument to the Top of the second elaboration call.
|
||
// If there is a repeat module definition, FIRRTL emission will fail | ||
val firrtl = (new ChiselStage).emitFirrtl( | ||
gen = new Testbench(dutDef), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now, the only way to instantiate a definition from a previous elaboration is to pass it as an argument to the top module in the next elaboration. This means that we must support a better API (e.g. like Instantiate), prior to release.
src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
Outdated
Show resolved
Hide resolved
src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
Outdated
Show resolved
Hide resolved
src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
Show resolved
Hide resolved
@mwachs5 @azidar not sure if it needs to be handled in this PR, but what should we do if there are multiple "previously elaborated" definitions with the same name? There doesn't seem to be a way to catch that right now. Like if I make two cc @sequencer this is what we were discussing in chisel meeting |
Yes. Currently Builder will handle the name confliction and rename to Queue_1 Queue_2. But in the Stage API there is no way to resolve the naming issue. |
Can we error? |
I can make But that will totally prohibit passing in more than 1 definition of the same module type, which is probably not what we want long term. |
Another option is to only allow for a single |
It's not just the Definition of the same module type, that definition can't instantiate anything (e.g. a Queue) with Module or Instance that are going to be used in a larger context. So far we handle this with annotations e.g. nested Module prefixing annotation. Maybe this is a good reason to keep pushing on the chisel prefixing API vs relying on annotations for this, but I don't think it really changes this PR. |
R.e. multiple imported definitions with the same name, from discussion with @azidar, for this PR we should:
|
I chatted with @seldridge a bit here, and we are thinking we are going to make "Namespaces" a more first-class citizen sooner or later. But not sure it's what we want to solve in this PR |
val existingMod = Builder.components.map { | ||
case c: DefModule if c.id == definition.proto => Some(c) | ||
case c: DefBlackBox if c.name == definition.proto.name => Some(c) | ||
case _ => None | ||
}.flatten |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jack previously pointed out that this is a linear search. Would it be worthwhile to change Builder.components
from an ArrayBuffer
to a HashMap
for better lookup speed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think its worthwhile unless you can measure the speedup; your lookup function would be complicated because you'd have to find the DefBlackBox
case anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good to me, slight suggestion for better failing require error messages!
core/src/main/scala/chisel3/experimental/hierarchy/core/Instance.scala
Outdated
Show resolved
Hide resolved
Looks good! Do you want me to label with |
if (importedDefinitionNames.distinct.length < importedDefinitionNames.length) { | ||
val duplicates = importedDefinitionNames.diff(importedDefinitionNames.distinct).mkString(", ") | ||
throwException(s"Expected distinct imported Definition names but found duplicates for: $duplicates") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if two different definitions have a same sub module(Queue) which has a same name? will it conflict?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you mean by "conflict". The top-level module should be able to access the submodules uniquely, since the Definition
s are now forced to have unique names.
The submodules also won't conflict in the Builder
, since each Definition
is built in a separate call to ChiselStage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could in theory pass in all the Modules as definitions from the first elaboration, then potential conflicts could be detected/avoided. If yo only pass in the top level definition you'd likely have issues in firrtl/verilog linking later which is still only hypothetical
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think the question is how we would have to do linking. @sequencer and @mwachs5 make good points, where we won't be able to link easily, without renaming conflict names when combining the Verilog. We could avoid this by adding submodule names to the duplicates.
This is probably the best intermediate solution, because it guarantees no name conflicts.
Yes please! @azidar can you please mark the "changes requested" as resolved if your concerns have been addressed? |
I'm changing this to a draft PR since, after some discussion, I think it makes more sense to solidify what we're doing with namespaces/prefix API and apply that to our multiple-definition-elaboration scheme. Still working on test cases for submodule name conflicts; will push those soon! |
dutDef0_rtl should include("module AddOne(") | ||
dutDef0_rtl should include("module AddTwoMixedModules(") | ||
val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddTwoMixedModules_1.v").getLines.mkString | ||
dutDef1_rtl should include("module AddOne_2(") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@azidar is this expected to skip to AddOne_2
instead of AddOne_1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@debs-sifive I think what is happening is AddTwoMixedModules
made an AddOne
(the Definition) and an AddOne_1
(the Instance) in the first dutDef0. They may get deduped later but as far as Chisel is concerned you have two names taken up in the namespace by the time you get to
dutDef1`
… (backport #2512) (#2520) * Support separately elaborating definition and instance in ChiselStage (#2512) (cherry picked from commit a0aa4d1) # Conflicts: # core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala # core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala # core/src/main/scala/chisel3/internal/Builder.scala * fixing imports (#2522) Co-authored-by: Deborah Soung <debs@sifive.com>
Contributor Checklist
docs/src
?Type of Improvement
TECH DEBT
Need to improve the API to instantiate previously-defined
Definition
s in the future (right now, we are passing in aDefinition
into theTop
of the second generator call). Tracked in #2514Need to improve the code that handles module name collisions. Right now I am making a bunch of
ImportedDefinitionAnnotation
s on the importedDefinition
and all of its submodules; this list ofAnnotation
s must get passed around between elaboration stages to ensure no name collisions. Long-term solution may require the support of namespaces in FIRRTL.API Impact
None.
Backend Code Generation Impact
None.
Desired Merge Strategy
Release Notes
Support for separately elaborating a Definition and Instance.
Reviewer Checklist (only modified by reviewer)
3.4.x
, [small] API extension:3.5.x
, API modification or big change:3.6.0
)?Please Merge
?