Skip to content

Commit

Permalink
Support BlackBoxes in D/I (#2438) (#2442)
Browse files Browse the repository at this point in the history
Also delete an errant println in InstanceSpec

(cherry picked from commit 3462c54)

Co-authored-by: Jack Koenig <koenig@sifive.com>
  • Loading branch information
mergify[bot] and jackkoenig authored Mar 9, 2022
1 parent 941dd7e commit 4ee545d
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 10 deletions.
34 changes: 28 additions & 6 deletions core/src/main/scala/chisel3/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ()
Expand All @@ -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))
}
}
Expand Down Expand Up @@ -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]
}
Expand All @@ -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]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down Expand Up @@ -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"))
}
Expand Down Expand Up @@ -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") {
Expand Down

0 comments on commit 4ee545d

Please sign in to comment.