summaryrefslogtreecommitdiff
path: root/core/src/main/scala/chisel3/RawModule.scala
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/scala/chisel3/RawModule.scala')
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala115
1 files changed, 82 insertions, 33 deletions
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 12b6a76a..f2ce4c70 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -43,25 +43,20 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
val compileOptions = moduleCompileOptions
- private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
- for (port <- getModulePorts) {
- port._computeName(None, None).orElse(names.get(port)) match {
- case Some(name) =>
- if (_namespace.contains(name)) {
- Builder.error(
- s"""Unable to name port $port to "$name" in $this,""" +
- " name is already taken by another port!"
- )
- }
- port.setRef(ModuleIO(this, _namespace.name(name)))
- case None =>
- Builder.error(
- s"Unable to name port $port in $this, " +
- "try making it a public field of the Module"
- )
- port.setRef(ModuleIO(this, "<UNNAMED>"))
+ // This could be factored into a common utility
+ private def canBeNamed(id: HasId): Boolean = id match {
+ case d: Data =>
+ d.binding match {
+ case Some(_: ConstrainedBinding) => true
+ case _ => false
}
- }
+ case b: BaseModule => true
+ case m: MemBase[_] => true
+ // These names don't affect hardware
+ case _: VerificationStatement => false
+ // While the above should be comprehensive, since this is used in warning we want to be careful
+ // to never accidentally have a match error
+ case _ => false
}
private[chisel3] override def generateComponent(): Option[Component] = {
@@ -74,8 +69,24 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
namePorts(names)
// Then everything else gets named
+ val warnReflectiveNaming = Builder.warnReflectiveNaming
for ((node, name) <- names) {
- node.suggestName(name)
+ node match {
+ case d: HasId if warnReflectiveNaming && canBeNamed(d) =>
+ val result = d._suggestNameCheck(name)
+ result match {
+ case None => // All good, no warning
+ case Some((oldName, oldPrefix)) =>
+ val prevName = buildName(oldName, oldPrefix.reverse)
+ val newName = buildName(name, Nil)
+ val msg = s"[module ${this.name}] '$prevName' is renamed by reflection to '$newName'. " +
+ s"Chisel 3.6 removes reflective naming so the name will remain '$prevName'."
+ Builder.warningNoLoc(msg)
+ }
+ // Note that unnamable things end up here (eg. literals), this is supporting backwards
+ // compatibility
+ case _ => node.suggestName(name)
+ }
}
// All suggestions are in, force names to every node.
@@ -83,26 +94,26 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
id match {
case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling
case id: InstanceClone[_] => id.setAsInstanceRef()
- case id: BaseModule => id.forceName(None, default = id.desiredName, _namespace)
- case id: MemBase[_] => id.forceName(None, default = "MEM", _namespace)
- case id: stop.Stop => id.forceName(None, default = "stop", _namespace)
- case id: assert.Assert => id.forceName(None, default = "assert", _namespace)
- case id: assume.Assume => id.forceName(None, default = "assume", _namespace)
- case id: cover.Cover => id.forceName(None, default = "cover", _namespace)
- case id: printf.Printf => id.forceName(None, default = "printf", _namespace)
+ case id: BaseModule => id.forceName(default = id.desiredName, _namespace)
+ case id: MemBase[_] => id.forceName(default = "MEM", _namespace)
+ case id: stop.Stop => id.forceName(default = "stop", _namespace)
+ case id: assert.Assert => id.forceName(default = "assert", _namespace)
+ case id: assume.Assume => id.forceName(default = "assume", _namespace)
+ case id: cover.Cover => id.forceName(default = "cover", _namespace)
+ case id: printf.Printf => id.forceName(default = "printf", _namespace)
case id: Data =>
if (id.isSynthesizable) {
id.topBinding match {
case OpBinding(_, _) =>
- id.forceName(Some(""), default = "T", _namespace)
+ id.forceName(default = "_T", _namespace)
case MemoryPortBinding(_, _) =>
- id.forceName(None, default = "MPORT", _namespace)
+ id.forceName(default = "MPORT", _namespace)
case PortBinding(_) =>
- id.forceName(None, default = "PORT", _namespace)
+ id.forceName(default = "PORT", _namespace)
case RegBinding(_, _) =>
- id.forceName(None, default = "REG", _namespace)
+ id.forceName(default = "REG", _namespace)
case WireBinding(_, _) =>
- id.forceName(Some(""), default = "WIRE", _namespace)
+ id.forceName(default = "_WIRE", _namespace)
case _ => // don't name literals
}
} // else, don't name unbound types
@@ -136,7 +147,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
// Generate IO invalidation commands to initialize outputs as unused,
// unless the client wants explicit control over their generation.
val invalidateCommands = {
- if (!compileOptions.explicitInvalidate) {
+ if (!compileOptions.explicitInvalidate || this.isInstanceOf[ImplicitInvalidate]) {
getModulePorts.map { port => DefInvalid(UnlocatableSourceInfo, port.ref) }
} else {
Seq()
@@ -150,7 +161,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
implicit val sourceInfo = UnlocatableSourceInfo
- if (!parentCompileOptions.explicitInvalidate) {
+ if (!parentCompileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) {
for (port <- getModulePorts) {
pushCommand(DefInvalid(sourceInfo, port.ref))
}
@@ -166,6 +177,9 @@ trait RequireSyncReset extends Module {
override private[chisel3] def mkReset: Bool = Bool()
}
+/** Mix with a [[RawModule]] to automatically connect DontCare to the module's ports, wires, and children instance IOs. */
+trait ImplicitInvalidate { self: RawModule => }
+
package object internal {
import scala.annotation.implicitNotFound
@@ -175,6 +189,41 @@ package object internal {
/** Marker trait for modules that are not true modules */
private[chisel3] trait PseudoModule extends BaseModule
+ /* Check if a String name is a temporary name */
+ def isTemp(name: String): Boolean = name.nonEmpty && name.head == '_'
+
+ /** Creates a name String from a prefix and a seed
+ * @param prefix The prefix associated with the seed (must be in correct order, *not* reversed)
+ * @param seed The seed for computing the name (if available)
+ */
+ def buildName(seed: String, prefix: Prefix): String = {
+ // Don't bother copying the String if there's no prefix
+ if (prefix.isEmpty) {
+ seed
+ } else {
+ // Using Java's String builder to micro-optimize appending a String excluding 1st character
+ // for temporaries
+ val builder = new java.lang.StringBuilder()
+ // Starting with _ is the indicator of a temporary
+ val temp = isTemp(seed)
+ // Make sure the final result is also a temporary if this is a temporary
+ if (temp) {
+ builder.append('_')
+ }
+ prefix.foreach { p =>
+ builder.append(p)
+ builder.append('_')
+ }
+ if (temp) {
+ // We've moved the leading _ to the front, drop it here
+ builder.append(seed, 1, seed.length)
+ } else {
+ builder.append(seed)
+ }
+ builder.toString
+ }
+ }
+
// Private reflective version of "val io" to maintain Chisel.Module semantics without having
// io as a virtual method. See https://github.com/freechipsproject/chisel3/pull/1550 for more
// information about the removal of "val io"