Skip to content
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

Implement module prefix API #2155

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

jared-barocsi
Copy link
Contributor

@jared-barocsi jared-barocsi commented Oct 7, 2021

Contributor Checklist

  • Did you add Scaladoc to every public function/method?
  • Did you add at least one test demonstrating the PR?
  • Did you delete any extraneous printlns/debugging code?
  • Did you specify the type of improvement?
  • Did you add appropriate documentation in docs/src?
  • Did you state the API impact?
  • Did you specify the code generation impact?
  • Did you request a desired merge strategy?
  • Did you add text to be included in the Release Notes for this change?

Type of Improvement

  • new feature/API

API Impact

Adds new API

Backend Code Generation Impact

No impact

Desired Merge Strategy

Squash and merge

Release Notes

Implement Module Prefix API

  • Adds a new object, withModulePrefix(prefix), that prefixes all instantiated modules within its scope with the prefix argument
  • Can be nested either directly in itself, or within modules created in its scope

Reviewer Checklist (only modified by reviewer)

  • Did you add the appropriate labels?
  • Did you mark the proper milestone (Bug fix: 3.3.x, [small] API extension: 3.4.x, API modification or big change: 3.5.0)?
  • Did you review?
  • Did you check whether all relevant Contributor checkboxes have been checked?
  • Did you mark as Please Merge?

Copy link
Contributor

@jackkoenig jackkoenig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks great, nice clean implementation!

Comment on lines 153 to 169

/** Elaborates a Chisel module into a circuit, but return that circuit in module form
* @param gen a call-by-name Chisel module
*/
def construct[T <: RawModule](gen: => T): T = {
val phase = new ChiselPhase {
override val targets = Seq( Dependency[chisel3.stage.phases.Checks],
Dependency[chisel3.stage.phases.Elaborate] )
}

phase
.transform(Seq(ChiselGeneratorAnnotation(() => gen), NoRunFirrtlCompilerAnnotation))
.collectFirst {
case DesignAnnotation(a) => a.asInstanceOf[T]
}
.get
}
Copy link
Contributor

@jackkoenig jackkoenig Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/** Elaborates a Chisel module into a circuit, but return that circuit in module form
* @param gen a call-by-name Chisel module
*/
def construct[T <: RawModule](gen: => T): T = {
val phase = new ChiselPhase {
override val targets = Seq( Dependency[chisel3.stage.phases.Checks],
Dependency[chisel3.stage.phases.Elaborate] )
}
phase
.transform(Seq(ChiselGeneratorAnnotation(() => gen), NoRunFirrtlCompilerAnnotation))
.collectFirst {
case DesignAnnotation(a) => a.asInstanceOf[T]
}
.get
}

This is a very large public API to add just for testing. If we want to add this, we need to be pretty thoughtful about it and with the current architecture of Chisel3, not much value comes from having references to elaborated module objects. Although arguably that should change, that's well beyond the scope of this PR.

@@ -23,6 +23,7 @@ import chisel3.internal.{firrtl => cir, ErrorLog}
import chisel3.stage.CircuitSerializationAnnotation.FirrtlFileFormat

import java.io.{StringWriter, PrintWriter}
import chisel3.Module
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import chisel3.Module

Related to comment about `ChiselStage.construct

@@ -200,4 +200,43 @@ class ModuleSpec extends ChiselPropSpec with Utils {
val s = Source.fromFile("generated/PlusOne.v").mkString("")
assert(s.contains("assign io_out = io_in + 32'h1"))
}

property("withModulePrefix should prefix modules within it") {
val m = ChiselStage.construct(new Module {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val m = ChiselStage.construct(new Module {
val m = elaborateAndGetModule(new Module {

Related to deletion of ChiselStage.construct, chiselTests.ChiselRunners already defines what you need here: elaborateAndGetModule

}

property("withModulePrefix should support nested module prefixing") {
val m = ChiselStage.construct(new Module {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val m = ChiselStage.construct(new Module {
val m = elaborateAndGetModule(new Module {

Related to deletion of ChiselStage.construct, chiselTests.ChiselRunners already defines what you need here: elaborateAndGetModule

@@ -88,6 +88,8 @@ object Module extends SourceInfoDoc {
def reset: Reset = Builder.forcedReset
/** Returns the current Module */
def currentModule: Option[BaseModule] = Builder.currentModule
/** Returns the current nested module prefix */
def currentPrefix: String = Builder.getModulePrefix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def currentPrefix: String = Builder.getModulePrefix
def currentModulePrefix: String = Builder.getModulePrefix

Just to avoid confusion with other uses of "prefix" which is usually referring to the intra-Module component prefixing rather than the global namespace Module prefixing.


property("withModulePrefix should prefix modules within it") {
val m = ChiselStage.construct(new Module {
val io = IO(new Bundle { })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val io = IO(new Bundle { })

io is no longer needed, please delete from all the added Modules.

})

m.child.nestedChild.name should be ("FooBarModule")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is a generator, people may want to have generated prefixes, including empty ones. I believe this works but can you add a test showing that an empty prefix (withModulePrefix("")) does not change the resulting modules names?

core/src/main/scala/chisel3/Module.scala Show resolved Hide resolved
@jackkoenig jackkoenig added this to the 3.5.0 milestone Oct 8, 2021
@jackkoenig jackkoenig added the Feature New feature, will be included in release notes label Oct 8, 2021
Copy link
Contributor

@mwachs5 mwachs5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any desire to "flush" the prefixing? Or is "nested" the only option?

Eg given:

Module TestHarness
   Module DUT
     Module A
     Module B
   Module VIP

If I say I want everything in TestHarness to be prefixed "TestHarness", e.g. I want TestHarnessVIP, it seems there is no way to "reset" the prefixes for DUT using withPrefix. Is there any other API to "clear out" the prefix stack? So that I don't end up with TestHarnessDUT?

}
})

m.child.nestedChild.name should be ("FooBarModule")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you please add a test which includes a SeqMem and run the ReplSeqMem? What is the prefixing behavior for the seq mems?

And also please add a test for blackbox/inline black box, which should NOT get prefixes applied

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with all of the tests. I'll note that prefixing of SyncReadMems is going to be tricky. I think maybe we should add a test for it but have it as ignore right now because I'm not yet sure how we should handle it.

@mwachs5
Copy link
Contributor

mwachs5 commented Jun 21, 2022

Discussed this again with @jackkoenig . The main limitation of this PR as it is is that we lose the "what is the prefix (ad-hoc namespace)" and "what is the leaf name" distinction. I'd suggest we do one of (in increasing order of complexity / design thought required):

  1. make some convention that names can be . - separated into .fir, and lowered later to concatenate these names (minor firrtl spec expansion). Then make this PR use . to separate the prefixes
  2. Add a first class concept of "prefix" to firrtl spec and pass the prefix in directly
  3. Add a first class concept of "namespace" to firrtl spec and stop using prefix as ad-hoc namespace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature, will be included in release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants