summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala24
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala34
-rw-r--r--src/main/scala/chisel3/Driver.scala2
-rw-r--r--src/main/scala/chisel3/internal/firrtl/Emitter.scala16
-rw-r--r--src/test/scala/chiselTests/AnnotatingExample.scala146
6 files changed, 208 insertions, 18 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 5e410ebd..5d294ea9 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -395,6 +395,6 @@ class Bundle extends Aggregate {
}
private[core] object Bundle {
- val keywords = List("flip", "asInput", "asOutput", "cloneType", "toBits",
- "widthOption", "chiselCloneType")
+ val keywords = List("flip", "asInput", "asOutput", "cloneType", "chiselCloneType", "toBits",
+ "widthOption", "signalName", "signalPathName", "signalParent", "signalComponent")
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index 2cfc6c6a..9f7048cd 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -31,13 +31,14 @@ object Module {
m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs
Builder.currentModule = parent // Back to parent!
val ports = m.computePorts
- Builder.components += Component(m, m.name, ports, m._commands)
+ val component = Component(m, m.name, ports, m._commands)
+ m._component = Some(component)
+ Builder.components += component
// Avoid referencing 'parent' in top module
if(!Builder.currentModule.isEmpty) {
pushCommand(DefInstance(sourceInfo, m, ports))
m.setupInParent(childSourceInfo)
}
-
m
}
}
@@ -100,6 +101,25 @@ extends HasId {
/** Legalized name of this module. */
final val name = Builder.globalNamespace.name(desiredName)
+ /** FIRRTL Module name */
+ private var _modName: Option[String] = None
+ private[chisel3] def setModName(name: String) = _modName = Some(name)
+ def modName = _modName match {
+ case Some(name) => name
+ case None => throwException("modName should be called after circuit elaboration")
+ }
+
+ /** Keep component for signal names */
+ private[chisel3] var _component: Option[Component] = None
+
+
+ /** Signal name (for simulation). */
+ override def instanceName =
+ if (_parent == None) name else _component match {
+ case None => getRef.name
+ case Some(c) => getRef fullName c
+ }
+
/** IO for this Module. At the Scala level (pre-FIRRTL transformations),
* connections in and out of a Module may only go through `io` elements.
*/
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 3191e384..0376e067 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -55,7 +55,18 @@ private[chisel3] class IdGen {
}
}
-private[chisel3] trait HasId {
+/** Public API to access Node/Signal names.
+ * currently, the node's name, the full path name, and references to its parent Module and component.
+ * These are only valid once the design has been elaborated, and should not be used during its construction.
+ */
+trait InstanceId {
+ def instanceName: String
+ def pathName: String
+ def parentPathName: String
+ def parentModName: String
+}
+
+private[chisel3] trait HasId extends InstanceId {
private[chisel3] def _onModuleClose: Unit = {} // scalastyle:ignore method.name
private[chisel3] val _parent: Option[Module] = Builder.currentModule
_parent.foreach(_.addId(this))
@@ -95,6 +106,27 @@ private[chisel3] trait HasId {
private[chisel3] def setRef(parent: HasId, index: Int): Unit = setRef(Index(Node(parent), ILit(index)))
private[chisel3] def setRef(parent: HasId, index: UInt): Unit = setRef(Index(Node(parent), index.ref))
private[chisel3] def getRef: Arg = _ref.get
+
+ // Implementation of public methods.
+ def instanceName = _parent match {
+ case Some(p) => p._component match {
+ case Some(c) => getRef fullName c
+ case None => throwException("signalName/pathName should be called after circuit elaboration")
+ }
+ case None => throwException("this cannot happen")
+ }
+ def pathName = _parent match {
+ case None => instanceName
+ case Some(p) => s"${p.pathName}.$instanceName"
+ }
+ def parentPathName = _parent match {
+ case Some(p) => p.pathName
+ case None => throwException(s"$instanceName doesn't have a parent")
+ }
+ def parentModName = _parent match {
+ case Some(p) => p.modName
+ case None => throwException(s"$instanceName doesn't have a parent")
+ }
}
private[chisel3] class DynamicContext(moduleCompileOptions: Option[ExplicitCompileOptions] = None) {
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index 8efb529d..f9f79f35 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -112,6 +112,8 @@ object Driver extends BackendCompilationUtilities {
def emit[T <: Module](gen: () => T, moduleCompileOptions: Option[ExplicitCompileOptions] = None): String = Emitter.emit(elaborate(gen, moduleCompileOptions))
+ def emit[T <: Module](ir: Circuit): String = Emitter.emit(ir)
+
def dumpFirrtl(ir: Circuit, optName: Option[File]): File = {
val f = optName.getOrElse(new File(ir.name + ".fir"))
val w = new FileWriter(f)
diff --git a/src/main/scala/chisel3/internal/firrtl/Emitter.scala b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
index 31856541..8b94c68f 100644
--- a/src/main/scala/chisel3/internal/firrtl/Emitter.scala
+++ b/src/main/scala/chisel3/internal/firrtl/Emitter.scala
@@ -27,11 +27,7 @@ private class Emitter(circuit: Circuit) {
case e: Stop => s"stop(${e.clk.fullName(ctx)}, UInt<1>(1), ${e.ret})"
case e: Printf => s"""printf(${e.clk.fullName(ctx)}, UInt<1>(1), "${e.format}"${e.ids.map(_.fullName(ctx)).fold(""){_ + ", " + _}})"""
case e: DefInvalid => s"${e.arg.fullName(ctx)} is invalid"
- case e: DefInstance => {
- val modName = moduleMap.get(e.id.name).get
- s"inst ${e.name} of $modName"
- }
-
+ case e: DefInstance => s"inst ${e.name} of ${e.id.modName}"
case w: WhenBegin =>
indent()
s"when ${w.pred.fullName(ctx)} :"
@@ -47,8 +43,6 @@ private class Emitter(circuit: Circuit) {
// Map of Module FIRRTL definition to FIRRTL name, if it has been emitted already.
private val defnMap = collection.mutable.HashMap[(String, String), Component]()
- // Map of Component name to FIRRTL id.
- private val moduleMap = collection.mutable.HashMap[String, String]()
/** Generates the FIRRTL module declaration.
*/
@@ -89,15 +83,11 @@ private class Emitter(circuit: Circuit) {
defnMap get (m.id.desiredName, defn) match {
case Some(duplicate) =>
- moduleMap(m.name) = duplicate.name
+ m.id setModName duplicate.name
""
case None =>
- require(!(moduleMap contains m.name),
- "emitting module with same name but different contents")
-
- moduleMap(m.name) = m.name
defnMap((m.id.desiredName, defn)) = m
-
+ m.id setModName m.name
moduleDecl(m) + defn
}
}
diff --git a/src/test/scala/chiselTests/AnnotatingExample.scala b/src/test/scala/chiselTests/AnnotatingExample.scala
new file mode 100644
index 00000000..85b4b039
--- /dev/null
+++ b/src/test/scala/chiselTests/AnnotatingExample.scala
@@ -0,0 +1,146 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.core.Module
+import chisel3.internal.InstanceId
+import chisel3.testers.BasicTester
+import chisel3.NotStrict.CompileOptions
+import org.scalatest._
+
+import scala.util.DynamicVariable
+
+//scalastyle:off magic.number
+
+/**
+ * This Spec file illustrates use of Donggyu's component name API, it currently only
+ * uses three methods .signalName, .parentModName and .pathName
+ *
+ * This is also an illustration of how to implement an annotation system in chisel3
+ * A local (my) Driver and Builder are created to provide thread-local access to
+ * an annotation map, and then a post elaboration annotation processor can resolve
+ * the keys and could serialize the annotations to a file for use by firrtl passes
+ */
+
+class SomeSubMod(param1: Int, param2: Int) extends Module {
+ val io = new Bundle {
+ val in = UInt(INPUT, 16)
+ val out = SInt(OUTPUT, 32)
+ }
+ val annotate = MyBuilder.myDynamicContext.annotationMap
+
+ annotate(AnnotationKey(this, JustThisRef)) = s"SomeSubMod($param1, $param2)"
+ annotate(AnnotationKey(io.in, AllRefs)) = "sub mod io.in"
+ annotate(AnnotationKey(io.out, JustThisRef)) = "sub mod io.out"
+}
+
+class AnnotatingExample extends Module {
+ val io = new Bundle {
+ val a = UInt(INPUT, 32)
+ val b = UInt(INPUT, 32)
+ val e = Bool(INPUT)
+ val z = UInt(OUTPUT, 32)
+ val v = Bool(OUTPUT)
+ val bun = new Bundle {
+ val nested_1 = UInt(INPUT, 12)
+ val nested_2 = Bool(OUTPUT)
+ }
+ }
+ val x = Reg(UInt(width = 32))
+ val y = Reg(UInt(width = 32))
+
+ val subModule1 = Module(new SomeSubMod(1, 2))
+ val subModule2 = Module(new SomeSubMod(3, 4))
+
+
+ val annotate = MyBuilder.myDynamicContext.annotationMap
+
+ annotate(AnnotationKey(subModule2, AllRefs)) = s"SomeSubMod was used"
+
+ annotate(AnnotationKey(x, JustThisRef)) = "I am register X"
+ annotate(AnnotationKey(y, AllRefs)) = "I am register Y"
+ annotate(AnnotationKey(io.a, JustThisRef)) = "I am io.a"
+ annotate(AnnotationKey(io.bun.nested_1, AllRefs)) = "I am io.bun.nested_1"
+ annotate(AnnotationKey(io.bun.nested_2, JustThisRef)) = "I am io.bun.nested_2"
+}
+
+class AnnotatingExampleTester extends BasicTester {
+ val dut = Module(new AnnotatingExample)
+
+ stop()
+}
+
+class AnnotatingExampleSpec extends FlatSpec with Matchers {
+ behavior of "Annotating components of a circuit"
+
+ it should "contain the following relative keys" in {
+ val annotationMap = MyDriver.buildAnnotatedCircuit { () => new AnnotatingExampleTester }
+
+ annotationMap.contains("SomeSubMod.io.in") should be(true)
+ annotationMap.contains("AnnotatingExample.y") should be(true)
+
+ annotationMap("SomeSubMod.io.in") should be("sub mod io.in")
+ }
+ it should "contain the following absolute keys" in {
+ val annotationMap = MyDriver.buildAnnotatedCircuit { () => new AnnotatingExampleTester }
+
+ annotationMap.contains("AnnotatingExampleTester.dut.subModule2.io.out") should be (true)
+ annotationMap.contains("AnnotatingExampleTester.dut.x") should be (true)
+
+ annotationMap("AnnotatingExampleTester.dut.subModule2.io.out") should be ("sub mod io.out")
+ }
+}
+
+trait AnnotationScope
+case object AllRefs extends AnnotationScope
+case object JustThisRef extends AnnotationScope
+
+object AnnotationKey {
+ def apply(component: InstanceId): AnnotationKey = {
+ AnnotationKey(component, AllRefs)
+ }
+}
+case class AnnotationKey(val component: InstanceId, scope: AnnotationScope) {
+ override def toString: String = {
+ scope match {
+ case JustThisRef =>
+ s"${component.pathName}"
+ case AllRefs =>
+ s"${component.parentModName}.${component.instanceName}"
+ case _ =>
+ s"${component.toString}_unknown_scope"
+ }
+ }
+}
+
+class AnnotationMap extends scala.collection.mutable.HashMap[AnnotationKey, String]
+
+class MyDynamicContext {
+ val annotationMap = new AnnotationMap
+}
+
+object MyBuilder {
+ private val myDynamicContextVar = new DynamicVariable[Option[MyDynamicContext]](None)
+
+ def myDynamicContext: MyDynamicContext =
+ myDynamicContextVar.value getOrElse new MyDynamicContext
+
+ def processAnnotations(annotationMap: AnnotationMap): Map[String, String] = {
+ annotationMap.map { case (k,v) => k.toString -> v}.toMap
+ }
+
+ def build[T <: Module](f: => T): Map[String, String] = {
+ myDynamicContextVar.withValue(Some(new MyDynamicContext)) {
+ Driver.emit(() => f)
+ processAnnotations(myDynamicContextVar.value.get.annotationMap)
+ }
+ }
+}
+
+object MyDriver extends BackendCompilationUtilities {
+ /**
+ * illustrates a chisel3 style driver that, annotations can only processed within this structure
+ */
+ def buildAnnotatedCircuit[T <: Module](gen: () => T): Map[String, String] = MyBuilder.build(Module(gen()))
+} \ No newline at end of file