Merge pull request #699 from ucb-bar/lazy-iobinders

Support diplomatic IOBinders
This commit is contained in:
Jerry Zhao
2020-11-02 20:14:54 -08:00
committed by GitHub
9 changed files with 222 additions and 219 deletions

View File

@@ -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"

View File

@@ -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.

View File

@@ -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

View File

@@ -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}
@@ -27,48 +27,54 @@ 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, 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): Unit = {
val pm = portMap.withDefaultValue(Nil)
map.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))
}
}
}
class OverrideHarnessBinder[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 ->
// The ClassTags here are necessary to overcome issues arising from type erasure
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: S => p})
require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}")
t match {
case system: T => fn(system, th, pts)
case _ => Nil
val pts = ports.collect({case p: U => p})
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 {
case system: T => composer(upfn)(system, th, pts)
case _ =>
}
case _ =>
}
})
)
})
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]) => Unit)
(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => fn)
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]) => Unit) => (t, th, p) => {
upfn(t, th, p)
fn(t, th, p)
})
class WithGPIOTiedOff extends OverrideHarnessBinder({
(system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => {
ports.foreach { _ <> AnalogConst(0) }
Nil
}
})
@@ -76,7 +82,6 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({
class WithUARTAdapter extends OverrideHarnessBinder({
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => {
UARTAdapter.connect(ports)(system.p)
Nil
}
})
// DOC include end: WithUARTAdapter
@@ -84,7 +89,6 @@ class WithUARTAdapter extends OverrideHarnessBinder({
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => {
SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p)
Nil
}
})
@@ -92,7 +96,6 @@ class WithSimBlockDevice extends OverrideHarnessBinder({
(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
}
})
@@ -100,7 +103,6 @@ class WithBlockDeviceModel extends OverrideHarnessBinder({
(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
}
})
@@ -112,15 +114,13 @@ class WithLoopbackNIC extends OverrideHarnessBinder({
NicLoopback.connect(Some(n.bits), p(NICKey))
}
}
Nil
}
})
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
}
})
@@ -134,7 +134,6 @@ class WithSimAXIMem extends OverrideHarnessBinder({
}
mem.io_axi4.head <> port.bits
}
Nil
}
})
@@ -149,7 +148,6 @@ class WithBlackBoxSimMem extends OverrideHarnessBinder({
mem.io.clock := port.clock
mem.io.reset := port.reset
}
Nil
}
})
@@ -163,42 +161,39 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({
}
mmio_mem.io_axi4.head <> port.bits
}
Nil
}
})
class WithTieOffInterrupts extends OverrideHarnessBinder({
(system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => {
ports.foreach { _ := 0.U }
Nil
}
})
class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
(system: CanHaveSlaveAXI4Port, th: 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: 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 }
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: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
ports.map {
case j: JTAGIO =>
j.TCK := true.B.asClock
@@ -218,7 +213,6 @@ class WithTiedOffDebug extends OverrideHarnessBinder({
a.psel := false.B
a.penable := false.B
}
Nil
}
})
@@ -247,13 +241,11 @@ class WithSimSerial extends OverrideHarnessBinder({
class WithTraceGenSuccess extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: 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]) => {
ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) }
Nil
}
})

View File

@@ -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._
@@ -26,6 +26,12 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon
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.
@@ -38,21 +44,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
@@ -70,63 +85,45 @@ 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)
}
})
)
})
object BoreHelper {
def apply[T <: Data](name: String, source: T): T = {
val (io, wire) = source match {
case c: Clock =>
val wire = Wire(Clock())
// Provide a dummy assignment to prevent FIRRTL invalid assignment
// errors prior to running the wiring pass
wire := false.B.asClock
(IO(Output(Clock())), wire)
case r: Reset =>
val wire = Wire(Reset())
wire := false.B
(IO(Output(Reset())), wire)
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)
}
io.suggestName(name)
wire.suggestName(s"chiptop_${name}")
dontTouch(wire)
BoringUtils.bore(source, Seq(wire))
io := wire
io.asInstanceOf[source.type]
}
}
}}): IOBinderFunction)
)
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())
@@ -203,55 +200,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 = true)
}
}
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 = true)
}
val jtagTuple = debug.systemjtag.map { j =>
IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = true)
}
val jtagTuple = debug.systemjtag.map { j =>
IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = true)
}
val apbTuple = debug.apb.map { a =>
IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = true)
}
val apbTuple = debug.apb.map { a =>
IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = true)
}
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))
}}}
}
})
@@ -264,43 +261,62 @@ class WithSerialTLIOCells extends OverrideIOBinder({
})
class WithAXI4MemPunchthrough extends OverrideIOBinder({
class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
(system: CanHaveMasterAXI4MemPort) => {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}")
p.bits <> m
val mbus = system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS)
p.clock := BoreHelper("axi4_mem_clock", mbus.module.clock)
p.reset := BoreHelper("axi4_mem_reset", mbus.module.reset)
p
})
(ports, Nil)
implicit val p: Parameters = GetSystemParameters(system)
val clockSinkNode = p(ExtMem).map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode)
def clockBundle = clockSinkNode.get.in.head._1
InModuleBody {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}")
p.bits <> m
p.clock := clockBundle.clock
p.reset := clockBundle.reset
p
})
(ports, Nil)
}
}
})
class WithAXI4MMIOPunchthrough extends OverrideIOBinder({
class WithAXI4MMIOPunchthrough extends OverrideLazyIOBinder({
(system: CanHaveMasterAXI4MMIOPort) => {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}")
p.bits <> m
val mbus = system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS)
p.clock := BoreHelper("axi4_mmio_clock", mbus.module.clock)
p.reset := BoreHelper("axi4_mmio_reset", mbus.module.reset)
p
})
(ports, Nil)
implicit val p: Parameters = GetSystemParameters(system)
val clockSinkNode = p(ExtBus).map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode)
def clockBundle = clockSinkNode.get.in.head._1
InModuleBody {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}")
p.bits <> m
p.clock := clockBundle.clock
p.reset := clockBundle.reset
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)
}
}
})

View File

@@ -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 {
@@ -43,7 +42,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)
}
}

View File

@@ -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)

View File

@@ -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[ClockedAndResetIO[AXI4Bundle]]) => {
(system: CanHaveMasterAXI4MemPort, th: FireSim, ports: Seq[ClockedAndResetIO[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
})

View File

@@ -153,7 +153,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()
}