summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormergify[bot]2022-03-09 20:40:25 +0000
committerGitHub2022-03-09 20:40:25 +0000
commit4ee545d7706a2d2ba59902fb86a4393287327a9a (patch)
tree657ed76babbc56ac2edc6b49f221f474783c77d3
parent941dd7ee76cadacbdd10b3d10d267f5d58a7ed4e (diff)
Support BlackBoxes in D/I (#2438) (#2442)
Also delete an errant println in InstanceSpec (cherry picked from commit 3462c54c018a52a377f1c89121b6ed99c5b0ae1d) Co-authored-by: Jack Koenig <koenig@sifive.com>
-rw-r--r--core/src/main/scala/chisel3/Module.scala34
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala7
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Examples.scala7
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala69
4 files changed, 107 insertions, 10 deletions
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index ed323504..84139630 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -248,8 +248,14 @@ package internal {
}
// Maps proto ports to module clone's ports
private[chisel3] lazy val ioMap: Map[Data, Data] = {
- val name2Port = getPorts.elements
- getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ getProto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case protoBB: BlackBox =>
+ Map(protoBB._io.get -> getPorts.elements("io"))
+ case _ =>
+ val name2Port = getPorts.elements
+ getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ }
}
// This module doesn't actually exist in the FIRRTL so no initialization to do
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
@@ -267,7 +273,17 @@ package internal {
case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad")
}
// Set both the record and the module to have the same instance name
- record.setRef(ModuleCloneIO(getProto, instName), force = true) // force because we did .forceName first
+ val ref = ModuleCloneIO(getProto, instName)
+ record.setRef(ref, force = true) // force because we did .forceName first
+ getProto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case _: BlackBox =>
+ // Override the io Bundle's ref so that it thinks it is the top for purposes of
+ // generating FIRRTL
+ record.elements("io").setRef(ref, force = true)
+ case _ => // Do nothing
+ }
+
this.setRef(Ref(instName))
}
}
@@ -329,8 +345,8 @@ package internal {
* @note These are not true Data (the Record doesn't correspond to anything in the emitted
* FIRRTL yet its elements *do*) so have some very specialized behavior.
*/
- private[chisel3] class ClonePorts(elts: Data*)(implicit compileOptions: CompileOptions) extends Record {
- val elements = ListMap(elts.map(d => d.instanceName -> d.cloneTypeFull): _*)
+ private[chisel3] class ClonePorts(elts: (String, Data)*)(implicit compileOptions: CompileOptions) extends Record {
+ val elements = ListMap(elts.map { case (name, d) => name -> d.cloneTypeFull }: _*)
def apply(field: String) = elements(field)
override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type]
}
@@ -351,12 +367,18 @@ package internal {
// Fake Module to serve as the _parent of the cloned ports
// We don't create this inside the ModuleClone because we need the ref to be set by the
// currentModule (and not clonePorts)
- val clonePorts = new ClonePorts(proto.getModulePorts: _*)
+ val clonePorts = proto match {
+ // BlackBox needs special handling for its pseduo-io Bundle
+ case b: BlackBox =>
+ new ClonePorts(proto.getChiselPorts :+ ("io" -> b._io.get): _*)
+ case _ => new ClonePorts(proto.getChiselPorts: _*)
+ }
clonePorts.bind(PortBinding(cloneParent))
clonePorts.setAllParents(Some(cloneParent))
cloneParent._portsRecord = clonePorts
// Normally handled during Module construction but ClonePorts really lives in its parent's parent
if (!compileOptions.explicitInvalidate) {
+ // FIXME This almost certainly doesn't work since clonePorts is not a real thing...
pushCommand(DefInvalid(sourceInfo, clonePorts.ref))
}
if (proto.isInstanceOf[Module]) {
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index bc94f95d..60290f83 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -10,7 +10,7 @@ import scala.annotation.implicitNotFound
import scala.collection.mutable.HashMap
import chisel3._
import chisel3.experimental.dataview.{isView, reify, reifySingleData}
-import chisel3.internal.firrtl.{Arg, ILit, Index, Slot, ULit}
+import chisel3.internal.firrtl.{Arg, ILit, Index, ModuleIO, Slot, ULit}
import chisel3.internal.{throwException, AggregateViewBinding, Builder, ChildBinding, ViewBinding, ViewParent}
/** Represents lookup typeclass to determine how a value accessed from an original IsInstantiable
@@ -123,8 +123,8 @@ object Lookupable {
def unrollCoordinates(res: List[Arg], d: Data): (List[Arg], Data) = d.binding.get match {
case ChildBinding(parent) =>
d.getRef match {
- case arg @ (_: Slot | _: Index) => unrollCoordinates(arg :: res, parent)
- case other => err(s"Unroll coordinates failed for '$arg'! Unexpected arg '$other'")
+ case arg @ (_: Slot | _: Index | _: ModuleIO) => unrollCoordinates(arg :: res, parent)
+ case other => err(s"unrollCoordinates failed for '$arg'! Unexpected arg '$other'")
}
case _ => (res, d)
}
@@ -135,6 +135,7 @@ object Lookupable {
val next = (coor.head, d) match {
case (Slot(_, name), rec: Record) => rec.elements(name)
case (Index(_, ILit(n)), vec: Vec[_]) => vec.apply(n.toInt)
+ case (ModuleIO(_, name), rec: Record) => rec.elements(name)
case (arg, _) => err(s"Unexpected Arg '$arg' applied to '$d'! Root was '$start'.")
}
applyCoordinates(coor.tail, next)
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
index aff0a771..fa26cbde 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
@@ -47,6 +47,13 @@ object Examples {
val addOneDef = Seq.fill(3)(Definition(new AddOne))
out := in + 1.U
}
+ @instantiable
+ class AddOneBlackBox extends BlackBox {
+ @public val io = IO(new Bundle {
+ val in = Input(UInt(32.W))
+ val out = Output(UInt(32.W))
+ })
+ }
@instantiable
class AddTwo extends Module {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 407a7237..8d8f7ea5 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -43,6 +43,29 @@ class InstanceSpec extends ChiselFunSpec with Utils {
val (chirrtl, _) = getFirrtlAndAnnos(new Top)
chirrtl.serialize should include("inst i0 of AddOne")
}
+ it("0.3: BlackBoxes should be supported") {
+ class Top extends Module {
+ val in = IO(Input(UInt(32.W)))
+ val out = IO(Output(UInt(32.W)))
+ val io = IO(new Bundle {
+ val in = Input(UInt(32.W))
+ val out = Output(UInt(32.W))
+ })
+ val definition = Definition(new AddOneBlackBox)
+ val i0 = Instance(definition)
+ val i1 = Instance(definition)
+ i0.io.in := in
+ out := i0.io.out
+ io <> i1.io
+ }
+ val chirrtl = getFirrtlAndAnnos(new Top)._1.serialize
+ chirrtl should include("inst i0 of AddOneBlackBox")
+ chirrtl should include("inst i1 of AddOneBlackBox")
+ chirrtl should include("i0.in <= in")
+ chirrtl should include("out <= i0.out")
+ chirrtl should include("i1.in <= io.in")
+ chirrtl should include("io.out <= i1.out")
+ }
}
describe("1: Annotations on instances in same chisel compilation") {
it("1.0: should work on a single instance, annotating the instance") {
@@ -338,7 +361,6 @@ class InstanceSpec extends ChiselFunSpec with Utils {
mark(i.syncReadMem, "SyncReadMem")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos.foreach { x => println(x.serialize) }
annos should contain(MarkAnnotation("~Top|Top/i:HasMems>mem".rt, "Mem"))
annos should contain(MarkAnnotation("~Top|Top/i:HasMems>syncReadMem".rt, "SyncReadMem"))
}
@@ -717,6 +739,51 @@ class InstanceSpec extends ChiselFunSpec with Utils {
annos should contain(e)
}
}
+
+ it("7.4: should work on Views of BlackBoxes") {
+ @instantiable
+ class MyBlackBox extends BlackBox {
+ @public val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ @public val innerView = io.viewAs
+ @public val foo = io.in.viewAs[UInt]
+ @public val bar = io.out.viewAs[UInt]
+ }
+ class Top extends RawModule {
+ val foo = IO(Input(UInt(8.W)))
+ val bar = IO(Output(UInt(8.W)))
+ val i = Instance(Definition(new MyBlackBox))
+ val outerView = i.io.viewAs
+ i.foo := foo
+ bar := i.bar
+ mark(i.foo, "i.foo")
+ mark(i.bar, "i.bar")
+ mark(i.innerView.in, "i.innerView.in")
+ mark(outerView.out, "outerView.out")
+ }
+ val inst = "~Top|Top/i:MyBlackBox"
+ val expectedAnnos = List(
+ s"$inst>in".rt -> "i.foo",
+ s"$inst>out".rt -> "i.bar",
+ s"$inst>in".rt -> "i.innerView.in",
+ s"$inst>out".rt -> "outerView.out"
+ )
+ val expectedLines = List(
+ "i.in <= foo",
+ "bar <= i.out"
+ )
+ val (chirrtl, annos) = getFirrtlAndAnnos(new Top)
+ val text = chirrtl.serialize
+ for (line <- expectedLines) {
+ text should include(line)
+ }
+ for (e <- expectedAnnos.map(MarkAnnotation.tupled)) {
+ annos should contain(e)
+ }
+ }
+
}
describe("8: @instantiable and @public should compose with CloneModuleAsRecord") {