From 9927231bc42f2405151f67e26396f686f2bfaa46 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 17 Oct 2020 22:47:50 -0700 Subject: [PATCH 1/5] Support lazy-iobinders --- .../chipyard/src/main/scala/ChipTop.scala | 15 +- .../src/main/scala/HarnessBinders.scala | 79 ++--- .../chipyard/src/main/scala/IOBinders.scala | 282 ++++++++++-------- .../chipyard/src/main/scala/TestHarness.scala | 7 +- .../src/main/scala/BridgeBinders.scala | 16 +- .../firechip/src/main/scala/FireSim.scala | 4 +- 6 files changed, 214 insertions(+), 189 deletions(-) diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index 1cef2180..e7456d80 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -23,12 +23,10 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) * drive clock and reset generation */ -class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunctions { - // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) - val iocells = ArrayBuffer.empty[IOCell] - +class ChipTop(implicit p: Parameters) extends LazyModule + with HasTestHarnessFunctions with HasIOBinders { // The system module specified by BuildSystem - val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") + lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") // The implicitClockSinkNode provides the implicit clock and reset for the System val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) @@ -45,13 +43,6 @@ class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunc val implicit_clock = implicitClockSinkNode.in.head._1.clock val implicit_reset = implicitClockSinkNode.in.head._1.reset - - // Note: IOBinders cannot rely on the implicit clock/reset, as this is a LazyRawModuleImp - val (_ports, _iocells, _portMap) = ApplyIOBinders(lazySystem, p(IOBinders)) - // We ignore _ports for now... - iocells ++= _iocells - portMap ++= _portMap - // Connect the implicit clock/reset, if present lazySystem.module match { case l: LazyModuleImp => { l.clock := implicit_clock diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index e5cfacfb..c5b95f75 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -1,7 +1,7 @@ package chipyard.harness import chisel3._ -import chisel3.experimental.{Analog} +import chisel3.experimental.{Analog, BaseModule} import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} @@ -31,42 +31,42 @@ case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalRefer Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil) ) - object ApplyHarnessBinders { - def apply(th: HasHarnessSignalReferences, sys: LazyModule, map: Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]], portMap: Map[String, Seq[Data]]) = { + def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters) = { val pm = portMap.withDefaultValue(Nil) - map.map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } + p(HarnessBinders).map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } } } -class OverrideHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { +class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Seq[Any]) => (T, S, Seq[U]) => Seq[Any])(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) extends Config((site, here, up) => { case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { - val pts = ports.collect({case p: S => p}) + val pts = ports.collect({case p: U => p}) require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") - t match { - case system: T => fn(system, th, pts) + val upfn = up(HarnessBinders, site)(tag.runtimeClass.toString) + th match { + case th: S => + t match { + case system: T => composer(upfn)(system, th, pts) + case _ => Nil + } case _ => Nil } }) ) }) -class ComposeHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { - case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> - ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { - val pts = ports.collect({case p: S => p}) - require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") - t match { - case system: T => up(HarnessBinders, site)(tag.runtimeClass.toString)(system, th, pts) ++ fn(system, th, pts) - case _ => Nil - } - }) - ) -}) +class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any]) + (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) + extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => fn) + +class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any]) + (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) + extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => (t, th, p) => upfn(t, th, p) ++ fn(t, th, p)) + class WithGPIOTiedOff extends OverrideHarnessBinder({ - (system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => { + (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Analog]) => { ports.foreach { _ <> AnalogConst(0) } Nil } @@ -74,7 +74,7 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({ // DOC include start: WithUARTAdapter class WithUARTAdapter extends OverrideHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { UARTAdapter.connect(ports)(system.p) Nil } @@ -82,14 +82,14 @@ class WithUARTAdapter extends OverrideHarnessBinder({ // DOC include end: WithUARTAdapter class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ - (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { + (system: HasPeripherySPIFlashModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p) Nil } }) class WithSimBlockDevice extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) } Nil @@ -97,7 +97,7 @@ class WithSimBlockDevice extends OverrideHarnessBinder({ }) class WithBlockDeviceModel extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } } Nil @@ -105,7 +105,7 @@ class WithBlockDeviceModel extends OverrideHarnessBinder({ }) class WithLoopbackNIC extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { n => withClockAndReset(n.clock, th.harnessReset) { @@ -117,7 +117,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({ }) class WithSimNetwork extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) } Nil @@ -125,7 +125,7 @@ class WithSimNetwork extends OverrideHarnessBinder({ }) class WithSimAXIMem extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MemPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) @@ -139,7 +139,7 @@ class WithSimAXIMem extends OverrideHarnessBinder({ }) class WithBlackBoxSimMem extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MemPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => val memSize = p(ExtMem).get.master.size @@ -154,7 +154,7 @@ class WithBlackBoxSimMem extends OverrideHarnessBinder({ }) class WithSimAXIMMIO extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MMIOPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) => val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p)) @@ -168,26 +168,27 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({ }) class WithTieOffInterrupts extends OverrideHarnessBinder({ - (system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => { + (system: HasExtInterruptsModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UInt]) => { ports.foreach { _ := 0.U } Nil } }) class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ - (system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveSlaveAXI4Port, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { ports.foreach({ p => p := DontCare; p.bits.tieoff() }) Nil } }) class WithSimDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { + implicit val p: Parameters = GetSystemParameters(system) ports.map { case d: ClockedDMIIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } - val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) + val dtm = Module(new SimDTM).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) case j: JTAGIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } @@ -198,7 +199,7 @@ class WithSimDebug extends OverrideHarnessBinder({ }) class WithTiedOffDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { ports.map { case j: JTAGIO => j.TCK := true.B.asClock @@ -224,7 +225,7 @@ class WithTiedOffDebug extends OverrideHarnessBinder({ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) @@ -234,7 +235,7 @@ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ }) class WithSimSerial extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) @@ -245,14 +246,14 @@ class WithSimSerial extends OverrideHarnessBinder({ }) class WithTraceGenSuccess extends OverrideHarnessBinder({ - (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { + (system: TraceGenSystemModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Bool]) => { ports.map { p => when (p) { th.success := true.B } } Nil } }) class WithSimDromajoBridge extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + (system: CanHaveTraceIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } Nil } diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 4a31e2c0..b083b5c0 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -1,17 +1,17 @@ package chipyard.iobinders import chisel3._ -import chisel3.util.experimental.{BoringUtils} import chisel3.experimental.{Analog, IO, DataMirror} import freechips.rocketchip.config._ -import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} +import freechips.rocketchip.diplomacy._ import freechips.rocketchip.devices.debug._ import freechips.rocketchip.jtag.{JTAGIO} import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.{SimAXIMem} import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} import freechips.rocketchip.util._ +import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters} import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem} import sifive.blocks.devices.gpio._ @@ -28,6 +28,12 @@ import chipyard.GlobalResetSchemeKey import scala.reflect.{ClassTag} +object IOBinderTypes { + type IOBinderTuple = (Seq[Data], Seq[IOCell]) + type IOBinderFunction = (Boolean, =>Any) => ModuleValue[IOBinderTuple] +} +import IOBinderTypes._ + // System for instantiating binders based // on the scala type of the Target (_not_ its IO). This avoids needing to // duplicate harnesses (essentially test harnesses) for each target. @@ -40,21 +46,30 @@ import scala.reflect.{ClassTag} // You can add your own binder by adding a new (key, fn) pair, typically by using // the OverrideIOBinder or ComposeIOBinder macros -case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]]( - Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil)) +case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]]( + Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil) ) -object ApplyIOBinders { - def apply(sys: LazyModule, map: Map[String, (Any) => (Seq[Data], Seq[IOCell])]): - (Iterable[Data], Iterable[IOCell], Map[String, Seq[Data]]) = { - val lzy = map.map({ case (s,f) => s -> f(sys) }) - val imp = map.map({ case (s,f) => s -> f(sys.module) }) - val unzipped = (lzy.values ++ imp.values).unzip - val ports: Iterable[Data] = unzipped._1.flatten - val cells: Iterable[IOCell] = unzipped._2.flatten - val portMap: Map[String, Seq[Data]] = map.keys.map(k => k -> (lzy(k)._1 ++ imp(k)._1)).toMap - (ports, cells, portMap) - } +abstract trait HasIOBinders { this: LazyModule => + val lazySystem: LazyModule + private val iobinders = p(IOBinders) + // Note: IOBinders cannot rely on the implicit clock/reset, as they may be called from the + // context of a LazyRawModuleImp + private val lzy = iobinders.map({ case (s,fns) => s -> fns.map(f => f(true, lazySystem)) }) + private val imp = iobinders.map({ case (s,fns) => s -> fns.map(f => f(false, lazySystem.module)) }) + + private lazy val lzyFlattened: Map[String, IOBinderTuple] = lzy.map({ + case (s,ms) => s -> (ms.map(_._1).flatten, ms.map(_._2).flatten) + }) + private lazy val impFlattened: Map[String, IOBinderTuple] = imp.map({ + case (s,ms) => s -> (ms.map(_._1).flatten, ms.map(_._2).flatten) + }) + + // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) + lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer + + // A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports + lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap } // Note: The parameters instance is accessible only through LazyModule @@ -72,52 +87,46 @@ object GetSystemParameters { } } -class IOBinder(f: (View, View, View) => PartialFunction[Any, Any]) extends Config(f) - -// This macro overrides previous matches on some Top mixin. This is useful for -// binders which drive IO, since those typically cannot be composed -class OverrideIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => { - case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> - ((t: Any) => { - t match { - case system: T => - val (ports, cells) = fn(system) - (ports, cells) - case _ => (Nil, Nil) - } - }) - ) +class IOBinder[T](composer: Seq[IOBinderFunction] => Seq[IOBinderFunction])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { + case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> composer(up(IOBinders, site)(tag.runtimeClass.toString))) }) -// This macro composes with previous matches on some Top mixin. This is useful for -// annotation-like binders, since those can typically be composed -class ComposeIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => { - case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> - ((t: Any) => { - t match { - case system: T => - val r = up(IOBinders, site)(tag.runtimeClass.toString)(system) - val h = fn(system) - val ports = r._1 ++ h._1 - val cells = r._2 ++ h._2 - (ports, cells) - case _ => (Nil, Nil) - } - }) - ) -}) +class ConcreteIOBinder[T](composes: Boolean, fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends IOBinder[T]( + up => (if (composes) up else Nil) ++ Seq(((_, t) => { InModuleBody { + t match { + case system: T => fn(system) + case _ => (Nil, Nil) + } + }}): IOBinderFunction) +) -object BoreHelper { - def apply(name: String, source: Clock): Clock = { - val clock_io = IO(Output(Clock())).suggestName(name) - val clock_wire = Wire(Clock()).suggestName(s"chiptop_${name}") - dontTouch(clock_wire) - clock_wire := false.B.asClock // necessary for BoringUtils to work properly - BoringUtils.bore(source, Seq(clock_wire)) - clock_io := clock_wire - clock_io - } -} + +class LazyIOBinder[T](composes: Boolean, fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends IOBinder[T]( + up => (if (composes) up else Nil) ++ Seq(((isLazy, t) => { + val empty = new ModuleValue[IOBinderTuple] { + def getWrappedValue: IOBinderTuple = (Nil, Nil) + } + if (isLazy) { + t match { + case system: T => fn(system) + case _ => empty + } + } else { + empty + } + }): IOBinderFunction) +) + +// The "Override" binders override any previous IOBinders (lazy or concrete) defined on the same trait. +// The "Compose" binders do not override previously defined IOBinders on the same trait +// The default IOBinders evaluate only in the concrete "ModuleImp" phase of elaboration +// The "Lazy" IOBinders evaluate in the LazyModule phase, but can also generate hardware through InModuleBody + +class OverrideIOBinder[T](fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends ConcreteIOBinder[T](false, fn) +class ComposeIOBinder[T](fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends ConcreteIOBinder[T](true, fn) + +class OverrideLazyIOBinder[T](fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends LazyIOBinder[T](false, fn) +class ComposeLazyIOBinder[T](fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends LazyIOBinder[T](true, fn) case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams()) @@ -194,55 +203,55 @@ class WithExtInterruptIOCells extends OverrideIOBinder({ }) -class WithDebugIOCells extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - system.debug.map({ debug => - val p = system.p - val tlbus = system.outer.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) - val debug_clock = Wire(Clock()).suggestName("debug_clock") - val debug_reset = Wire(Reset()).suggestName("debug_reset") - debug_clock := false.B.asClock // must provide default assignment to avoid firrtl unassigned error - debug_reset := false.B // must provide default assignment to avoid firrtl unassigned error - BoringUtils.bore(tlbus.module.clock, Seq(debug_clock)) - BoringUtils.bore(tlbus.module.reset, Seq(debug_reset)) +class WithDebugIOCells extends OverrideLazyIOBinder({ + (system: HasPeripheryDebug) => { + implicit val p = GetSystemParameters(system) + val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) + val clockSinkNode = system.debugOpt.map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) + clockSinkNode.map(_ := tlbus.fixedClockNode) + def clockBundle = clockSinkNode.get.in.head._1 - // We never use the PSDIO, so tie it off on-chip - system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } - system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := debug_reset.asBool } } - system.debug.map { d => - // Tie off extTrigger - d.extTrigger.foreach { t => - t.in.req := false.B - t.out.ack := t.out.req + + InModuleBody { system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripheryDebugModuleImp => { + system.debug.map({ debug => + // We never use the PSDIO, so tie it off on-chip + system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } + system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := clockBundle.reset.asBool } } + system.debug.map { d => + // Tie off extTrigger + d.extTrigger.foreach { t => + t.in.req := false.B + t.out.ack := t.out.req + } + // Tie off disableDebug + d.disableDebug.foreach { d => d := false.B } + // Drive JTAG on-chip IOs + d.systemjtag.map { j => + j.reset := clockBundle.reset + j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W) + j.version := p(JtagDTMKey).idcodeVersion.U(4.W) + } } - // Tie off disableDebug - d.disableDebug.foreach { d => d := false.B } - // Drive JTAG on-chip IOs - d.systemjtag.map { j => - j.reset := debug_reset - j.mfr_id := system.p(JtagDTMKey).idcodeManufId.U(11.W) - j.part_number := system.p(JtagDTMKey).idcodePartNum.U(16.W) - j.version := system.p(JtagDTMKey).idcodeVersion.U(4.W) + Debug.connectDebugClockAndReset(Some(debug), clockBundle.clock) + + // Add IOCells for the DMI/JTAG/APB ports + val dmiTuple = debug.clockeddmi.map { d => + IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) } - } - Debug.connectDebugClockAndReset(Some(debug), debug_clock)(system.p) - // Add IOCells for the DMI/JTAG/APB ports - val dmiTuple = debug.clockeddmi.map { d => - IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) - } + val jtagTuple = debug.systemjtag.map { j => + IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + } - val jtagTuple = debug.systemjtag.map { j => - IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) - } + val apbTuple = debug.apb.map { a => + IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + } - val apbTuple = debug.apb.map { a => - IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) - } - - val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq - (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq) - }).getOrElse((Nil, Nil)) + val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq + (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq) + }).getOrElse((Nil, Nil)) + }}} } }) @@ -255,39 +264,60 @@ class WithSerialTLIOCells extends OverrideIOBinder({ }) -class WithAXI4MemPunchthrough extends OverrideIOBinder({ +class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MemPort) => { - val ports: Seq[ClockedIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) => - val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}") - p.bits <> m - p.clock := BoreHelper("axi4_mem_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) - p - }) - (ports, Nil) + implicit val p: Parameters = GetSystemParameters(system) + val clockSinkNode = p(ExtMem).map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) + clockSinkNode.map(_ := system.asInstanceOf[BaseSubsystem].mbus.fixedClockNode) + def clockBundle = clockSinkNode.get.in.head._1 + + InModuleBody { + val ports: Seq[ClockedIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}") + p.bits <> m + p.clock := clockBundle.clock + p + }) + (ports, Nil) + } } }) -class WithAXI4MMIOPunchthrough extends OverrideIOBinder({ +class WithAXI4MMIOPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MMIOPort) => { - val ports: Seq[ClockedIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) => - val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}") - p.bits <> m - p.clock := BoreHelper("axi4_mmio_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) - p - }) - (ports, Nil) + implicit val p: Parameters = GetSystemParameters(system) + val clockSinkNode = p(ExtBus).map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) + clockSinkNode.map(_ := system.asInstanceOf[BaseSubsystem].mbus.fixedClockNode) + def clockBundle = clockSinkNode.get.in.head._1 + + InModuleBody { + val ports: Seq[ClockedIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}") + p.bits <> m + p.clock := clockBundle.clock + p + }) + (ports, Nil) + } } }) -class WithL2FBusAXI4Punchthrough extends OverrideIOBinder({ - (system: CanHaveSlaveAXI4Port) => { - val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) => - val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}") - m <> p.bits - p.clock := BoreHelper("axi4_fbus_clock", system.asInstanceOf[BaseSubsystem].fbus.module.clock) - p - }) - (ports, Nil) +class WithL2FBusAXI4Punchthrough extends OverrideLazyIOBinder({ + (system: CanHaveSlaveAXI4Port) => { + implicit val p: Parameters = GetSystemParameters(system) + val clockSinkNode = p(ExtIn).map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) + clockSinkNode.map(_ := system.asInstanceOf[BaseSubsystem].fbus.fixedClockNode) + def clockBundle = clockSinkNode.get.in.head._1 + + InModuleBody { + val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) => + val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}") + m <> p.bits + p.clock := clockBundle.clock + p + }) + (ports, Nil) + } } }) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 2faff565..9c5c9d2c 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -6,6 +6,7 @@ import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} +import chipyard.iobinders.HasIOBinders // ------------------------------- // Chipyard Test Harness @@ -14,9 +15,7 @@ import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) trait HasTestHarnessFunctions { - val lazySystem: LazyModule val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]] - val portMap = scala.collection.mutable.Map[String, Seq[Data]]() } trait HasHarnessSignalReferences { @@ -44,7 +43,9 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign lazyDut match { case d: HasTestHarnessFunctions => d.harnessFunctions.foreach(_(this)) - ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } + lazyDut match { case d: HasIOBinders => + ApplyHarnessBinders(this, d.lazySystem, d.portMap) } } diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 444c7b33..2fa49fc3 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -66,7 +66,7 @@ class WithFireSimIOCellModels extends Config((site, here, up) => { }) class WithSerialBridge extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => { ports.map { port => implicit val p = GetSystemParameters(system) val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) @@ -77,7 +77,7 @@ class WithSerialBridge extends OverrideHarnessBinder({ }) class WithNICBridge extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: FireSim, ports: Seq[ClockedIO[NICIOvonly]]) => { val p: Parameters = GetSystemParameters(system) ports.map { n => NICBridge(n.clock, n.bits)(p) } Nil @@ -85,12 +85,12 @@ class WithNICBridge extends OverrideHarnessBinder({ }) class WithUARTBridge extends OverrideHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => + (system: HasPeripheryUARTModuleImp, th: FireSim, ports: Seq[UARTPortIO]) => ports.map { p => UARTBridge(th.harnessClock, p)(system.p) }; Nil }) class WithBlockDeviceBridge extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.toBool) } Nil @@ -98,7 +98,7 @@ class WithBlockDeviceBridge extends OverrideHarnessBinder({ }) class WithFASEDBridge extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MemPort, th: FireSim, ports: Seq[ClockedIO[AXI4Bundle]]) => { implicit val p: Parameters = GetSystemParameters(system) (ports zip system.memAXI4Node.edges.in).map { case (axi4, edge) => val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth, @@ -118,20 +118,20 @@ class WithFASEDBridge extends OverrideHarnessBinder({ }) class WithTracerVBridge extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + (system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) => { ports.map { p => p.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p)) } Nil } }) class WithDromajoBridge extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => + (system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) => ports.map { p => p.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p)) }; Nil }) class WithTraceGenBridge extends OverrideHarnessBinder({ - (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => + (system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) => ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil }) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index 90fd473a..70116456 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -160,7 +160,9 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna lazyModule match { case d: HasTestHarnessFunctions => require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset") d.harnessFunctions.foreach(_(this)) - ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } + lazyModule match { case d: HasIOBinders => + ApplyHarnessBinders(this, d.lazySystem, d.portMap) } NodeIdx.increment() } From 035e2e43158d7cb7aa79600cd1a7450b576dd105 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 17 Oct 2020 22:55:07 -0700 Subject: [PATCH 2/5] Add test for make TOP=DigitalTop --- .circleci/defaults.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/defaults.sh b/.circleci/defaults.sh index 1b41e395..e628de7b 100755 --- a/.circleci/defaults.sh +++ b/.circleci/defaults.sh @@ -47,7 +47,7 @@ LOCAL_FIRESIM_DIR=$LOCAL_CHIPYARD_DIR/sims/firesim/sim # key value store to get the build groups declare -A grouping -grouping["group-cores"]="chipyard-ariane chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor" +grouping["group-cores"]="chipyard-ariane chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor chipyard-digitaltop" grouping["group-peripherals"]="chipyard-dmirocket chipyard-blkdev chipyard-spiflashread chipyard-spiflashwrite chipyard-mmios chipyard-lbwif" grouping["group-accels"]="chipyard-nvdla chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-streaming-fir chipyard-streaming-passthrough" grouping["group-tracegen"]="tracegen tracegen-boom" @@ -59,6 +59,7 @@ mapping["chipyard-rocket"]="" mapping["chipyard-dmirocket"]=" CONFIG=dmiRocketConfig" mapping["chipyard-lbwif"]=" CONFIG=LBWIFRocketConfig" mapping["chipyard-sha3"]=" CONFIG=Sha3RocketConfig" +mapping["chipyard-digitaltop"]=" TOP=DigitalTop" mapping["chipyard-streaming-fir"]=" CONFIG=StreamingFIRRocketConfig" mapping["chipyard-streaming-passthrough"]=" CONFIG=StreamingPassthroughRocketConfig" mapping["chipyard-hetero"]=" CONFIG=LargeBoomAndRocketConfig" From f3d666d2b7675eebbe890b530a9de2a25cdd8588 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 19 Oct 2020 10:16:44 -0700 Subject: [PATCH 3/5] Clarify HarnessBinders ClassTag naming --- generators/chipyard/src/main/scala/HarnessBinders.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index c5b95f75..3cf70f3e 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -38,12 +38,13 @@ object ApplyHarnessBinders { } } -class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Seq[Any]) => (T, S, Seq[U]) => Seq[Any])(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) extends Config((site, here, up) => { - case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> +// The ClassTags here are necessary to overcome issues arising from type erasure +class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Seq[Any]) => (T, S, Seq[U]) => Seq[Any])(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { + case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString -> ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { val pts = ports.collect({case p: U => p}) - require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") - val upfn = up(HarnessBinders, site)(tag.runtimeClass.toString) + require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${portTag}") + val upfn = up(HarnessBinders, site)(systemTag.runtimeClass.toString) th match { case th: S => t match { From 7a55c55aa3e640e83b710c7bc9e73882af8959d2 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Mon, 19 Oct 2020 16:17:46 -0700 Subject: [PATCH 4/5] Fix no-MBUS configs --- docs/Customization/IOBinders.rst | 4 ++-- generators/chipyard/src/main/scala/IOBinders.scala | 6 ++---- .../src/main/scala/config/SodorConfigs.scala | 12 ++++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/Customization/IOBinders.rst b/docs/Customization/IOBinders.rst index ff180bcd..1ae95512 100644 --- a/docs/Customization/IOBinders.rst +++ b/docs/Customization/IOBinders.rst @@ -4,7 +4,7 @@ IOBinders and HarnessBinders In Chipyard we use special ``Parameters`` keys, ``IOBinders`` and ``HarnessBinders`` to bridge the gap between digital system IOs and TestHarness collateral. IOBinders -========= +--------- The ``IOBinder`` functions are responsible for instantiating IO cells and IOPorts in the ``ChipTop`` layer. @@ -19,7 +19,7 @@ For example, the ``WithUARTIOCells`` IOBinder will, for any ``System`` that migh :end-before: DOC include end: WithUARTIOCells HarnessBinders -============== +-------------- The ``HarnessBinder`` functions determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. The ``HarnessBinder`` interface is designed to be reused across various simulation/implementation modes, enabling decoupling of the target design from simulation and testing concerns. diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 6bf8a6df..46bed169 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -267,8 +267,7 @@ class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MemPort) => { implicit val p: Parameters = GetSystemParameters(system) val clockSinkNode = p(ExtMem).map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) - val mbus = system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS) - clockSinkNode.map(_ := mbus.fixedClockNode) + clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode) def clockBundle = clockSinkNode.get.in.head._1 InModuleBody { @@ -288,8 +287,7 @@ class WithAXI4MMIOPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MMIOPort) => { implicit val p: Parameters = GetSystemParameters(system) val clockSinkNode = p(ExtBus).map(_ => ClockSinkNode(Seq(ClockSinkParameters()))) - val mbus = system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS) - clockSinkNode.map(_ := mbus.fixedClockNode) + clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode) def clockBundle = clockSinkNode.get.in.head._1 InModuleBody { diff --git a/generators/chipyard/src/main/scala/config/SodorConfigs.scala b/generators/chipyard/src/main/scala/config/SodorConfigs.scala index ea245fbc..998ccff9 100644 --- a/generators/chipyard/src/main/scala/config/SodorConfigs.scala +++ b/generators/chipyard/src/main/scala/config/SodorConfigs.scala @@ -9,7 +9,7 @@ class Sodor1StageConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage1Factory) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) @@ -18,7 +18,7 @@ class Sodor2StageConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage2Factory) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) @@ -27,7 +27,7 @@ class Sodor3StageConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 2)) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) @@ -36,7 +36,7 @@ class Sodor3StageSinglePortConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 1)) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) @@ -45,7 +45,7 @@ class Sodor5StageConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage5Factory) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) @@ -54,6 +54,6 @@ class SodorUCodeConfig extends Config( new sodor.common.WithNSodorCores(1, internalTile = sodor.common.UCodeFactory) ++ new testchipip.WithSerialPBusMem ++ new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad - new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory + new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory new freechips.rocketchip.subsystem.WithNBanks(0) ++ new chipyard.config.AbstractConfig) From 7b83da054a4609202578168a8796df40a21ccc1d Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 28 Oct 2020 16:18:22 -0700 Subject: [PATCH 5/5] Clean up HarnessBinders --- .../src/main/scala/HarnessBinders.scala | 72 ++++++++----------- 1 file changed, 31 insertions(+), 41 deletions(-) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 2ff8ad94..02ab3732 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -27,19 +27,22 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon import scala.reflect.{ClassTag} -case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]]( - Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil) +case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]]( + Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => ()) ) object ApplyHarnessBinders { - def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters) = { + def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = { val pm = portMap.withDefaultValue(Nil) - p(HarnessBinders).map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } + p(HarnessBinders).foreach { case (s, f) => + f(sys, th, pm(s)) + f(sys.module, th, pm(s)) + } } } // The ClassTags here are necessary to overcome issues arising from type erasure -class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Seq[Any]) => (T, S, Seq[U]) => Seq[Any])(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { +class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString -> ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { val pts = ports.collect({case p: U => p}) @@ -49,71 +52,68 @@ class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T case th: S => t match { case system: T => composer(upfn)(system, th, pts) - case _ => Nil + case _ => } - case _ => Nil + case _ => } }) ) }) -class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any]) +class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit) (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) - extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => fn) + extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => fn) -class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any]) +class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit) (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) - extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => (t, th, p) => upfn(t, th, p) ++ fn(t, th, p)) + extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => (t, th, p) => { + upfn(t, th, p) + fn(t, th, p) + }) class WithGPIOTiedOff extends OverrideHarnessBinder({ - (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Analog]) => { + (system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => { ports.foreach { _ <> AnalogConst(0) } - Nil } }) // DOC include start: WithUARTAdapter class WithUARTAdapter extends OverrideHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { UARTAdapter.connect(ports)(system.p) - Nil } }) // DOC include end: WithUARTAdapter class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ - (system: HasPeripherySPIFlashModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { + (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p) - Nil } }) class WithSimBlockDevice extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) } - Nil } }) class WithBlockDeviceModel extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } } - Nil } }) class WithLoopbackNIC extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { n => withClockAndReset(n.clock, th.harnessReset) { NicLoopback.connect(Some(n.bits), p(NICKey)) } } - Nil } }) @@ -121,7 +121,6 @@ class WithSimNetwork extends OverrideHarnessBinder({ (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) } - Nil } }) @@ -135,7 +134,6 @@ class WithSimAXIMem extends OverrideHarnessBinder({ } mem.io_axi4.head <> port.bits } - Nil } }) @@ -150,7 +148,6 @@ class WithBlackBoxSimMem extends OverrideHarnessBinder({ mem.io.clock := port.clock mem.io.reset := port.reset } - Nil } }) @@ -164,26 +161,23 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({ } mmio_mem.io_axi4.head <> port.bits } - Nil } }) class WithTieOffInterrupts extends OverrideHarnessBinder({ - (system: HasExtInterruptsModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UInt]) => { + (system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => { ports.foreach { _ := 0.U } - Nil } }) class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ - (system: CanHaveSlaveAXI4Port, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { ports.foreach({ p => p := DontCare; p.bits.tieoff() }) - Nil } }) class WithSimDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { case d: ClockedDMIIO => @@ -195,12 +189,11 @@ class WithSimDebug extends OverrideHarnessBinder({ when (dtm_success) { th.success := true.B } val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success) } - Nil } }) class WithTiedOffDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => { ports.map { case j: JTAGIO => j.TCK := true.B.asClock @@ -220,13 +213,12 @@ class WithTiedOffDebug extends OverrideHarnessBinder({ a.psel := false.B a.penable := false.B } - Nil } }) class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) @@ -236,7 +228,7 @@ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ }) class WithSimSerial extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) @@ -247,15 +239,13 @@ class WithSimSerial extends OverrideHarnessBinder({ }) class WithTraceGenSuccess extends OverrideHarnessBinder({ - (system: TraceGenSystemModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Bool]) => { + (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { ports.map { p => when (p) { th.success := true.B } } - Nil } }) class WithSimDromajoBridge extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } - Nil } })