Unify multi-node btw chipyard/firechip | unify harness clocking
This commit is contained in:
@@ -111,6 +111,7 @@ class WithPassthroughClockGenerator extends OverrideLazyIOBinder({
|
||||
val (bundle, edge) = clockGroupAggNode.out(0)
|
||||
|
||||
val clock_ios = (bundle.member.data zip edge.sink.members).map { case (b, m) =>
|
||||
require(m.take.isDefined, s"Clock ${m.name.get} has no requested frequency")
|
||||
val freq = m.take.get.freqMHz
|
||||
val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}")
|
||||
b.clock := clock_io.clock
|
||||
|
||||
@@ -23,10 +23,9 @@ object ClockGroupCombiner {
|
||||
case object ClockGroupCombinerKey extends Field[Seq[(String, ClockSinkParameters => Boolean)]](Nil)
|
||||
|
||||
// All clock groups with a name containing any substring in names will be combined into a single clock group
|
||||
class WithClockGroupsCombinedByName(grouped_name: String, names: String*) extends Config((site, here, up) => {
|
||||
case ClockGroupCombinerKey => {
|
||||
val combiner: ClockSinkParameters => Boolean = { m => names.map(n => m.name.get.contains(n)).reduce(_||_) }
|
||||
up(ClockGroupCombinerKey) ++ Seq((grouped_name, combiner))
|
||||
class WithClockGroupsCombinedByName(groups: (String, Seq[String])*) extends Config((site, here, up) => {
|
||||
case ClockGroupCombinerKey => groups.map { case (grouped_name, matched_names) =>
|
||||
(grouped_name, (m: ClockSinkParameters) => matched_names.map(n => m.name.get.contains(n)).reduce(_||_))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -49,9 +48,14 @@ class ClockGroupCombiner(implicit p: Parameters, v: ValName) extends LazyModule
|
||||
val name = combiners(i)._1
|
||||
i = i + 1
|
||||
require(g.size >= 1)
|
||||
require(g.forall(_.take.get == g.head.take.get))
|
||||
(grouped ++ Seq(ClockSinkParameters(take = g.head.take, name = Some(name))), r)
|
||||
val takes = g.map(_.take).flatten
|
||||
require(takes.distinct.size <= 1,
|
||||
s"Clock group $name has non-homogeneous requested ClockParameters $takes")
|
||||
require(takes.size > 0,
|
||||
s"Clock group $name has no inheritable frequencies")
|
||||
(grouped ++ Seq(ClockSinkParameters(take = takes.headOption, name = Some(name))), r)
|
||||
}
|
||||
|
||||
ClockGroupSinkParameters(
|
||||
name = u.name,
|
||||
members = grouped ++ rest
|
||||
|
||||
@@ -60,23 +60,23 @@ object ClockGroupNamePrefixer {
|
||||
* The default if all functions return None.
|
||||
*/
|
||||
object ClockGroupFrequencySpecifier {
|
||||
def apply(
|
||||
assigners: Seq[(String) => Option[Double]],
|
||||
defaultFreq: Double)(
|
||||
implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = {
|
||||
def apply(assigners: Seq[(String) => Option[Double]])(
|
||||
implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = {
|
||||
|
||||
def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = {
|
||||
require(clock.name.nonEmpty, "All clocks in clock group must have an assigned name")
|
||||
val clockFreq = assigners.foldLeft(defaultFreq)(
|
||||
(currentFreq, candidateFunc) => candidateFunc(clock.name.get).getOrElse(currentFreq))
|
||||
|
||||
clock.copy(take = clock.take match {
|
||||
case Some(cp) =>
|
||||
println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.")
|
||||
Some(cp)
|
||||
case None => Some(ClockParameters(clockFreq))
|
||||
})
|
||||
}
|
||||
def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = clock.copy(take = clock.take match {
|
||||
case Some(cp) =>
|
||||
println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.")
|
||||
Some(cp)
|
||||
case None => {
|
||||
val freqs = assigners.map { f => f(clock.name.get) }.flatten
|
||||
if (freqs.size > 0) {
|
||||
println(s"Clock ${clock.name.get}: using specified frequency of ${freqs.last}")
|
||||
Some(ClockParameters(freqs.last))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
LazyModule(new ClockGroupParameterModifier(sinkFn = { s => s.copy(members = s.members.map(lookupFrequencyForName)) })).node
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.prci._
|
||||
|
||||
import testchipip.{TLTileResetCtrl}
|
||||
import chipyard.harness.{DefaultClockFrequencyKey}
|
||||
|
||||
case class ChipyardPRCIControlParams(
|
||||
slaveWhere: TLBusWrapperLocation = CBUS,
|
||||
@@ -70,7 +69,7 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
|
||||
// 5. Add reset control registers to the tiles (if desired)
|
||||
// The final clock group here contains physically distinct clock domains, which some PRCI node in a
|
||||
// diplomatic IOBinder should drive
|
||||
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
|
||||
val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey))
|
||||
val clockGroupCombiner = ClockGroupCombiner()
|
||||
val resetSynchronizer = ClockGroupResetSynchronizer()
|
||||
val tileClockGater = if (prciParams.enableTileClockGating) { prci_ctrl_domain {
|
||||
|
||||
@@ -44,6 +44,9 @@ class AbstractConfig extends Config(
|
||||
|
||||
// By default, punch out IOs to the Harness
|
||||
new chipyard.clocking.WithPassthroughClockGenerator ++
|
||||
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "mbus", "pbus", "fbus", "cbus", "implicit"))) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus
|
||||
new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus
|
||||
|
||||
new testchipip.WithCustomBootPin ++ // add a custom-boot-pin to support pin-driven boot address
|
||||
new testchipip.WithBootAddrReg ++ // add a boot-addr-reg for configurable boot address
|
||||
@@ -55,9 +58,6 @@ class AbstractConfig extends Config(
|
||||
new chipyard.config.WithL2TLBs(1024) ++ // use L2 TLBs
|
||||
new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks
|
||||
new chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set
|
||||
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set)
|
||||
new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus
|
||||
new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus
|
||||
new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++ // Default 2 memory channels
|
||||
new freechips.rocketchip.subsystem.WithClockGateModel ++ // add default EICG_wrapper clock gate model
|
||||
new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port
|
||||
|
||||
@@ -32,7 +32,7 @@ class ChipLikeQuadRocketConfig extends Config(
|
||||
new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure
|
||||
|
||||
// Create the uncore clock group
|
||||
new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus") ++
|
||||
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus"))) ++
|
||||
|
||||
new chipyard.config.AbstractConfig)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class TinyRocketConfig extends Config(
|
||||
class UARTTSIRocketConfig extends Config(
|
||||
new chipyard.harness.WithUARTSerial ++
|
||||
new chipyard.config.WithNoUART ++
|
||||
new chipyard.config.WithMemoryBusFrequency(10) ++
|
||||
new chipyard.config.WithMemoryBusFrequency(10) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(10) ++
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core
|
||||
new chipyard.config.AbstractConfig)
|
||||
@@ -90,11 +90,13 @@ class MulticlockRocketConfig extends Config(
|
||||
new freechips.rocketchip.subsystem.WithNBigCores(1) ++
|
||||
// Frequency specifications
|
||||
new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540
|
||||
new chipyard.config.WithSystemBusFrequency(800.0) ++ // Ditto
|
||||
new chipyard.clocking.WithClockGroupsCombinedByName(("uncore" , Seq("sbus", "cbus", "implicit")),
|
||||
("periphery", Seq("pbus", "fbus"))) ++
|
||||
new chipyard.config.WithSystemBusFrequency(800.0) ++ // Matches the maximum frequency of U540
|
||||
new chipyard.config.WithMemoryBusFrequency(1000.0) ++ // 2x the U540 freq (appropriate for a 128b Mbus)
|
||||
new chipyard.config.WithPeripheryBusFrequency(100) ++ // Retains the default pbus frequency
|
||||
new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (800 MHz)
|
||||
new chipyard.config.WithPeripheryBusFrequency(100) ++ // Slow periphery bus
|
||||
// Crossing specifications
|
||||
new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between FBUS and SBUS
|
||||
new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS
|
||||
new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS
|
||||
new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
|
||||
@@ -102,7 +104,6 @@ class MulticlockRocketConfig extends Config(
|
||||
|
||||
// DOC include start: MulticlockAXIOverSerialConfig
|
||||
class MulticlockAXIOverSerialConfig extends Config(
|
||||
new chipyard.config.WithSystemBusFrequencyAsDefault ++
|
||||
new chipyard.config.WithSystemBusFrequency(250) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(250) ++
|
||||
new chipyard.config.WithMemoryBusFrequency(250) ++
|
||||
|
||||
@@ -13,7 +13,6 @@ class AbstractTraceGenConfig extends Config(
|
||||
new chipyard.clocking.WithPassthroughClockGenerator ++
|
||||
new chipyard.config.WithTracegenSystem ++
|
||||
new chipyard.config.WithNoSubsystemDrivenClocks ++
|
||||
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++
|
||||
new chipyard.config.WithMemoryBusFrequency(100.0) ++
|
||||
new chipyard.config.WithPeripheryBusFrequency(100.0) ++
|
||||
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++
|
||||
|
||||
@@ -13,7 +13,6 @@ import freechips.rocketchip.tilelink.{HasTLBusParams}
|
||||
|
||||
import chipyard._
|
||||
import chipyard.clocking._
|
||||
import chipyard.harness.{DefaultClockFrequencyKey}
|
||||
|
||||
// The default RocketChip BaseSubsystem drives its diplomatic clock graph
|
||||
// with the implicit clocks of Subsystem. Don't do that, instead we extend
|
||||
@@ -37,14 +36,6 @@ class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockN
|
||||
},
|
||||
fMHz)
|
||||
|
||||
class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => {
|
||||
case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get.toDouble / (1000 * 1000))
|
||||
})
|
||||
|
||||
class WithSystemBusFrequencyAsDefault extends Config((site, here, up) => {
|
||||
case DefaultClockFrequencyKey => (site(SystemBusKey).dtsFrequency.get.toDouble / (1000 * 1000))
|
||||
})
|
||||
|
||||
class BusFrequencyAssignment[T <: HasTLBusParams](re: Regex, key: Field[T]) extends Config((site, here, up) => {
|
||||
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
|
||||
Seq((cName: String) => site(key).dtsFrequency.flatMap { f =>
|
||||
|
||||
@@ -46,15 +46,12 @@ class FlatTestHarness(implicit val p: Parameters) extends Module {
|
||||
val memFreq = axiDomainParams.getMemFrequency(lazyDut.system)
|
||||
|
||||
withClockAndReset(clock, reset) {
|
||||
val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
memOverSerialTLClockBundle.clock := clock
|
||||
memOverSerialTLClockBundle.reset := reset
|
||||
val serial_bits = dut.serial_tl_pad.bits
|
||||
dut.serial_tl_pad.clock := clock
|
||||
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
|
||||
lazyDut.system.serdesser.get,
|
||||
serial_bits,
|
||||
memOverSerialTLClockBundle,
|
||||
clock,
|
||||
reset)
|
||||
io.success := SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), clock, reset)
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon
|
||||
|
||||
import scala.reflect.{ClassTag}
|
||||
|
||||
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]) => ())
|
||||
case object HarnessBinders extends Field[Map[String, (Any, HasHarnessInstantiators, Seq[Data]) => Unit]](
|
||||
Map[String, (Any, HasHarnessInstantiators, Seq[Data]) => Unit]().withDefaultValue((t: Any, th: HasHarnessInstantiators, d: Seq[Data]) => ())
|
||||
)
|
||||
|
||||
object ApplyHarnessBinders {
|
||||
def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = {
|
||||
def apply(th: HasHarnessInstantiators, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = {
|
||||
val pm = portMap.withDefaultValue(Nil)
|
||||
p(HarnessBinders).foreach { case (s, f) =>
|
||||
f(sys, th, pm(s))
|
||||
@@ -45,9 +45,9 @@ object ApplyHarnessBinders {
|
||||
}
|
||||
|
||||
// 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) => {
|
||||
class HarnessBinder[T, S <: HasHarnessInstantiators, 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]) => {
|
||||
((t: Any, th: HasHarnessInstantiators, ports: Seq[Data]) => {
|
||||
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)
|
||||
@@ -63,11 +63,11 @@ class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T
|
||||
)
|
||||
})
|
||||
|
||||
class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit)
|
||||
class OverrideHarnessBinder[T, S <: HasHarnessInstantiators, 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)
|
||||
class ComposeHarnessBinder[T, S <: HasHarnessInstantiators, 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)
|
||||
@@ -76,72 +76,66 @@ class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: =>
|
||||
|
||||
|
||||
class WithGPIOTiedOff extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => {
|
||||
(system: HasPeripheryGPIOModuleImp, th: HasHarnessInstantiators, ports: Seq[Analog]) => {
|
||||
ports.foreach { _ <> AnalogConst(0) }
|
||||
}
|
||||
})
|
||||
|
||||
// DOC include start: WithUARTAdapter
|
||||
class WithUARTAdapter extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => {
|
||||
(system: HasPeripheryUARTModuleImp, th: HasHarnessInstantiators, ports: Seq[UARTPortIO]) => {
|
||||
UARTAdapter.connect(ports)(system.p)
|
||||
}
|
||||
})
|
||||
// DOC include end: WithUARTAdapter
|
||||
|
||||
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
|
||||
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => {
|
||||
SimSPIFlashModel.connect(ports, th.buildtopReset, rdOnly)(system.p)
|
||||
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessInstantiators, ports: Seq[SPIChipIO]) => {
|
||||
SimSPIFlashModel.connect(ports, th.harnessBinderReset, rdOnly)(system.p)
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimBlockDevice extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => SimBlockDevice.connect(b.clock, th.buildtopReset.asBool, Some(b.bits)) }
|
||||
ports.map { b => SimBlockDevice.connect(b.clock, th.harnessBinderReset.asBool, Some(b.bits)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithBlockDeviceModel extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => withClockAndReset(b.clock, th.buildtopReset) { BlockDeviceModel.connect(Some(b.bits)) } }
|
||||
ports.map { b => BlockDeviceModel.connect(Some(b.bits)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithLoopbackNIC extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
(system: CanHavePeripheryIceNIC, th: HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { n =>
|
||||
withClockAndReset(n.clock, th.buildtopReset) {
|
||||
NicLoopback.connect(Some(n.bits), p(NICKey))
|
||||
}
|
||||
}
|
||||
ports.map { n => NicLoopback.connect(Some(n.bits), p(NICKey)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimNetwork extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.buildtopReset.asBool) }
|
||||
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessBinderReset.asBool) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimAXIMem extends OverrideHarnessBinder({
|
||||
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
|
||||
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[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))
|
||||
withClockAndReset(port.clock, port.reset) {
|
||||
Module(mem.module).suggestName("mem")
|
||||
}
|
||||
Module(mem.module).suggestName("mem")
|
||||
mem.io_axi4.head <> port.bits
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
|
||||
p(SerialTLKey).map({ sVal =>
|
||||
@@ -153,29 +147,27 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
|
||||
|
||||
ports.map({ port =>
|
||||
// DOC include start: HarnessClockInstantiatorEx
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val memOverSerialTLClockBundle = th.harnessClockInstantiator.requestClockBundle("mem_over_serial_tl_clock", memFreq)
|
||||
val serial_bits = port.bits
|
||||
port.clock := th.buildtopClock
|
||||
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
memOverSerialTLClockBundle,
|
||||
th.buildtopReset)
|
||||
// DOC include end: HarnessClockInstantiatorEx
|
||||
val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
val memOverSerialTLClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq)
|
||||
val serial_bits = port.bits
|
||||
port.clock := th.harnessBinderClock
|
||||
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
memOverSerialTLClock,
|
||||
th.harnessBinderReset)
|
||||
// DOC include end: HarnessClockInstantiatorEx
|
||||
val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
|
||||
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
|
||||
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
|
||||
val memSize = sVal.memParams.size
|
||||
val memBase = sVal.memParams.base
|
||||
val lineSize = p(CacheBlockBytes)
|
||||
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram")
|
||||
mem.io.axi <> axi_port.bits
|
||||
mem.io.clock := axi_port.clock
|
||||
mem.io.reset := axi_port.reset
|
||||
}
|
||||
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
|
||||
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
|
||||
val memSize = sVal.memParams.size
|
||||
val memBase = sVal.memParams.base
|
||||
val lineSize = p(CacheBlockBytes)
|
||||
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram")
|
||||
mem.io.axi <> axi_port.bits
|
||||
mem.io.clock := axi_port.clock
|
||||
mem.io.reset := axi_port.reset
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -183,7 +175,7 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
|
||||
})
|
||||
|
||||
class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({
|
||||
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
|
||||
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
|
||||
val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
|
||||
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
|
||||
// TODO FIX: This currently makes each SimDRAM contain the entire memory space
|
||||
@@ -218,7 +210,7 @@ class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBind
|
||||
})
|
||||
|
||||
class WithSimAXIMMIO extends OverrideHarnessBinder({
|
||||
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
|
||||
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[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))
|
||||
@@ -231,13 +223,13 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({
|
||||
})
|
||||
|
||||
class WithTieOffInterrupts extends OverrideHarnessBinder({
|
||||
(system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => {
|
||||
(system: HasExtInterruptsModuleImp, th: HasHarnessInstantiators, ports: Seq[UInt]) => {
|
||||
ports.foreach { _ := 0.U }
|
||||
}
|
||||
})
|
||||
|
||||
class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
|
||||
(system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => {
|
||||
(system: CanHaveSlaveAXI4Port, th: HasHarnessInstantiators, ports: Seq[ClockedIO[AXI4Bundle]]) => {
|
||||
ports.foreach({ p =>
|
||||
p.bits := DontCare
|
||||
p.bits.aw.valid := false.B
|
||||
@@ -250,13 +242,13 @@ class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
|
||||
})
|
||||
|
||||
class WithSimDebug extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||
(system: HasPeripheryDebug, th: HasHarnessInstantiators, 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 TestchipSimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success)
|
||||
val dtm = Module(new TestchipSimDTM).connect(th.harnessBinderClock, th.harnessBinderReset.asBool, d, dtm_success)
|
||||
case j: JTAGChipIO =>
|
||||
val dtm_success = WireInit(false.B)
|
||||
when (dtm_success) { th.success := true.B }
|
||||
@@ -267,13 +259,13 @@ class WithSimDebug extends OverrideHarnessBinder({
|
||||
j.TMS := jtag_wire.TMS
|
||||
j.TDI := jtag_wire.TDI
|
||||
val jtag = Module(new SimJTAG(tickDelay=3))
|
||||
jtag.connect(jtag_wire, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success)
|
||||
jtag.connect(jtag_wire, th.harnessBinderClock, th.harnessBinderReset.asBool, ~(th.harnessBinderReset.asBool), dtm_success)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class WithTiedOffDebug extends OverrideHarnessBinder({
|
||||
(system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||
(system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => {
|
||||
ports.map {
|
||||
case j: JTAGChipIO =>
|
||||
j.TCK := true.B.asClock
|
||||
@@ -300,7 +292,7 @@ class WithTiedOffDebug extends OverrideHarnessBinder({
|
||||
|
||||
|
||||
class WithSerialTLTiedOff extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
ports.map({ port =>
|
||||
val bits = port.bits
|
||||
@@ -313,56 +305,52 @@ class WithSerialTLTiedOff extends OverrideHarnessBinder({
|
||||
})
|
||||
|
||||
class WithSimTSIOverSerialTL extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
ports.map({ port =>
|
||||
val bits = port.bits
|
||||
port.clock := th.buildtopClock
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
val success = SimTSI.connect(Some(ram.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
}
|
||||
port.clock := th.harnessBinderClock
|
||||
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
|
||||
val success = SimTSI.connect(Some(ram.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool)
|
||||
when (success) { th.success := true.B }
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
class WithUARTSerial extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
ports.map({ port =>
|
||||
val freq = p(PeripheryBusKey).dtsFrequency.get
|
||||
val bits = port.bits
|
||||
port.clock := th.buildtopClock
|
||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
val uart_to_serial = Module(new UARTToSerial(freq, UARTParams(0)))
|
||||
val serial_width_adapter = Module(new SerialWidthAdapter(
|
||||
8, TSI.WIDTH))
|
||||
ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide)
|
||||
UARTAdapter.connect(Seq(uart_to_serial.io.uart), uart_to_serial.div)
|
||||
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
|
||||
th.success := false.B
|
||||
}
|
||||
port.clock := th.harnessBinderClock
|
||||
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
|
||||
val uart_to_serial = Module(new UARTToSerial(freq, UARTParams(0)))
|
||||
val serial_width_adapter = Module(new SerialWidthAdapter(
|
||||
8, TSI.WIDTH))
|
||||
ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide)
|
||||
UARTAdapter.connect(Seq(uart_to_serial.io.uart), uart_to_serial.div)
|
||||
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
|
||||
th.success := false.B
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
class WithTraceGenSuccess extends OverrideHarnessBinder({
|
||||
(system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
|
||||
(system: TraceGenSystemModuleImp, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
|
||||
ports.map { p => when (p) { th.success := true.B } }
|
||||
}
|
||||
})
|
||||
|
||||
class WithSimDromajoBridge extends ComposeHarnessBinder({
|
||||
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => {
|
||||
(system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => {
|
||||
ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) }
|
||||
}
|
||||
})
|
||||
|
||||
class WithCospike extends ComposeHarnessBinder({
|
||||
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => {
|
||||
(system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => {
|
||||
implicit val p = chipyard.iobinders.GetSystemParameters(system)
|
||||
val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem]
|
||||
val tiles = chipyardSystem.tiles
|
||||
@@ -381,7 +369,7 @@ class WithCospike extends ComposeHarnessBinder({
|
||||
|
||||
|
||||
class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
|
||||
(system: CanHavePeripheryCustomBootPin, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
|
||||
val pin = PlusArg("custom_boot_pin", width=1)
|
||||
ports.foreach(_ := pin)
|
||||
}
|
||||
@@ -389,14 +377,14 @@ class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
|
||||
|
||||
|
||||
class WithClockAndResetFromHarness extends OverrideHarnessBinder({
|
||||
(system: HasChipyardPRCI, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||
(system: HasChipyardPRCI, th: HasHarnessInstantiators, ports: Seq[Data]) => {
|
||||
implicit val p = GetSystemParameters(system)
|
||||
ports.map ({
|
||||
case c: ClockWithFreq => {
|
||||
val clock = th.harnessClockInstantiator.requestClockBundle(s"clock_${c.freqMHz}MHz", c.freqMHz * (1000 * 1000))
|
||||
c.clock := clock.clock
|
||||
val clock = th.harnessClockInstantiator.requestClockMHz(s"clock_${c.freqMHz}MHz", c.freqMHz)
|
||||
c.clock := clock
|
||||
}
|
||||
case r: AsyncReset => r := th.buildtopReset.asAsyncReset
|
||||
case r: AsyncReset => r := th.harnessBinderReset.asAsyncReset
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,24 +17,26 @@ import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
|
||||
// HarnessClockInstantiators are classes which generate clocks that drive
|
||||
// TestHarness simulation models and any Clock inputs to the ChipTop
|
||||
trait HarnessClockInstantiator {
|
||||
val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty
|
||||
val clockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty
|
||||
|
||||
// request a clock bundle at a particular frequency
|
||||
def requestClockBundle(name: String, freqRequested: Double): ClockBundle = {
|
||||
if (_clockMap.contains(name)) {
|
||||
require(freqRequested == _clockMap(name)._1,
|
||||
s"Request clock freq = $freqRequested != previously requested ${_clockMap(name)._2} for requested clock $name")
|
||||
_clockMap(name)._2
|
||||
// request a clock at a particular frequency
|
||||
def requestClockHz(name: String, freqHzRequested: Double): Clock = {
|
||||
if (clockMap.contains(name)) {
|
||||
require(freqHzRequested == clockMap(name)._1,
|
||||
s"Request clock freq = $freqHzRequested != previously requested ${clockMap(name)._2} for requested clock $name")
|
||||
clockMap(name)._2
|
||||
} else {
|
||||
val clockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
_clockMap(name) = (freqRequested, clockBundle)
|
||||
clockBundle
|
||||
val clock = Wire(Clock())
|
||||
clockMap(name) = (freqHzRequested, clock)
|
||||
clock
|
||||
}
|
||||
}
|
||||
|
||||
def requestClockMHz(name: String, freqMHzRequested: Double): Clock = {
|
||||
requestClockHz(name, freqMHzRequested * (1000 * 1000))
|
||||
}
|
||||
// refClock is the clock generated by TestDriver that is
|
||||
// passed to the TestHarness as its implicit clock
|
||||
def instantiateHarnessClocks(refClock: ClockBundle): Unit
|
||||
def instantiateHarnessClocks(refClock: Clock): Unit
|
||||
}
|
||||
|
||||
class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map(
|
||||
@@ -63,19 +65,14 @@ class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map(
|
||||
// This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim
|
||||
// It is useful for VCS/Xcelium-driven RTL simulations
|
||||
class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator {
|
||||
def instantiateHarnessClocks(refClock: ClockBundle): Unit = {
|
||||
val sinks = _clockMap.map({ case (name, (freq, bundle)) =>
|
||||
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
|
||||
}).toSeq
|
||||
|
||||
def instantiateHarnessClocks(refClock: Clock): Unit = {
|
||||
// connect wires to clock source
|
||||
for (sinkParams <- sinks) {
|
||||
val source = Module(new ClockSourceAtFreqMHz(sinkParams.take.get.freqMHz))
|
||||
for ((name, (freqHz, clock)) <- clockMap) {
|
||||
val source = Module(new ClockSourceAtFreqMHz(freqHz / (1000 * 1000)))
|
||||
source.io.power := true.B
|
||||
source.io.gate := false.B
|
||||
|
||||
_clockMap(sinkParams.name.get)._2.clock := source.io.clk
|
||||
_clockMap(sinkParams.name.get)._2.reset := refClock.reset
|
||||
clock := source.io.clk
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,12 +82,11 @@ class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) =
|
||||
})
|
||||
|
||||
class AllClocksFromHarnessClockInstantiator extends HarnessClockInstantiator {
|
||||
def instantiateHarnessClocks(refClock: ClockBundle): Unit = {
|
||||
val freqs = _clockMap.map(_._2._1)
|
||||
def instantiateHarnessClocks(refClock: Clock): Unit = {
|
||||
val freqs = clockMap.map(_._2._1)
|
||||
freqs.tail.foreach(t => require(t == freqs.head, s"Mismatching clocks $t != ${freqs.head}"))
|
||||
for ((_, (_, bundle)) <- _clockMap) {
|
||||
bundle.clock := refClock.clock
|
||||
bundle.reset := refClock.reset
|
||||
for ((name, (freq, clock)) <- clockMap) {
|
||||
clock := refClock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package chipyard.harness
|
||||
|
||||
import chisel3._
|
||||
|
||||
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
|
||||
import freechips.rocketchip.diplomacy.{LazyModule}
|
||||
import org.chipsalliance.cde.config.{Field, Parameters, Config}
|
||||
import freechips.rocketchip.util.{ResetCatchAndSync}
|
||||
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
|
||||
import freechips.rocketchip.stage.phases.TargetDirKey
|
||||
|
||||
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
|
||||
import chipyard.iobinders.HasIOBinders
|
||||
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
|
||||
import chipyard.{ChipTop}
|
||||
|
||||
// -------------------------------
|
||||
// Chipyard Test Harness
|
||||
// -------------------------------
|
||||
|
||||
case object MultiChipNChips extends Field[Int](0) // 0 means ignore MultiChipParams
|
||||
case class MultiChipParameters(chipId: Int) extends Field[Parameters]
|
||||
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
||||
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]()
|
||||
case object HarnessBinderClockFrequencyKey extends Field[Double](100.0) // MHz
|
||||
case object MultiChipIdx extends Field[Int](0)
|
||||
|
||||
class WithMultiChip(id: Int, p: Parameters) extends Config((site, here, up) => {
|
||||
case MultiChipParameters(`id`) => p
|
||||
case MultiChipNChips => up(MultiChipNChips) max (id + 1)
|
||||
})
|
||||
|
||||
class WithHomogeneousMultiChip(n: Int, p: Parameters, idStart: Int = 0) extends Config((site, here, up) => {
|
||||
case MultiChipParameters(id) => if (id >= idStart && id < idStart + n) p else up(MultiChipParameters(id))
|
||||
case MultiChipNChips => up(MultiChipNChips) max (idStart + n)
|
||||
})
|
||||
|
||||
class WithHarnessBinderClockFreqMHz(freqMHz: Double) extends Config((site, here, up) => {
|
||||
case HarnessBinderClockFrequencyKey => freqMHz
|
||||
})
|
||||
|
||||
// A TestHarness mixing this in will
|
||||
// - use the HarnessClockInstantiator clock provide
|
||||
trait HasHarnessInstantiators {
|
||||
implicit val p: Parameters
|
||||
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
||||
private val harnessBinderClockFreq: Double = p(HarnessBinderClockFrequencyKey)
|
||||
def getHarnessBinderClockFreqHz: Double = harnessBinderClockFreq * 1000000
|
||||
def getHarnessBinderClockFreqMHz: Double = harnessBinderClockFreq
|
||||
|
||||
// buildtopClock takes the refClockFreq, and drives the harnessbinders
|
||||
val harnessBinderClock = Wire(Clock())
|
||||
val harnessBinderReset = Wire(Reset())
|
||||
|
||||
// classes which inherit this trait should provide the below definitions
|
||||
def implicitClock: Clock
|
||||
def implicitReset: Reset
|
||||
def success: Bool
|
||||
|
||||
// This can be accessed to get new clocks from the harness
|
||||
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
|
||||
|
||||
private val chipParameters = if (p(MultiChipNChips) == 0) {
|
||||
Seq(p)
|
||||
} else {
|
||||
(0 until p(MultiChipNChips)).map { i => p(MultiChipParameters(i)).alterPartial {
|
||||
case TargetDirKey => p(TargetDirKey) // hacky fix
|
||||
case MultiChipIdx => i
|
||||
}}
|
||||
}
|
||||
|
||||
// This shold be called last to build the ChipTops
|
||||
def instantiateChipTops(): Seq[LazyModule] = {
|
||||
val lazyDuts = chipParameters.zipWithIndex.map { case (q,i) =>
|
||||
LazyModule(q(BuildTop)(q)).suggestName(s"chiptop$i")
|
||||
}
|
||||
val duts = lazyDuts.map(l => Module(l.module))
|
||||
|
||||
withClockAndReset (harnessBinderClock, harnessBinderReset) {
|
||||
lazyDuts.zipWithIndex.foreach {
|
||||
case (d: HasIOBinders, i: Int) => ApplyHarnessBinders(this, d.lazySystem, d.portMap)(chipParameters(i))
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
|
||||
val harnessBinderClk = harnessClockInstantiator.requestClockMHz("harnessbinder_clock", getHarnessBinderClockFreqMHz)
|
||||
println(s"Harness binder clock is $harnessBinderClockFreq")
|
||||
harnessBinderClock := harnessBinderClk
|
||||
harnessBinderReset := implicitReset
|
||||
|
||||
harnessClockInstantiator.instantiateHarnessClocks(implicitClock)
|
||||
|
||||
lazyDuts
|
||||
}
|
||||
}
|
||||
@@ -17,48 +17,15 @@ import chipyard.{ChipTop}
|
||||
// Chipyard Test Harness
|
||||
// -------------------------------
|
||||
|
||||
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
||||
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
|
||||
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]()
|
||||
|
||||
trait HasHarnessSignalReferences {
|
||||
implicit val p: Parameters
|
||||
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
|
||||
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
||||
var refClockFreq: Double = p(DefaultClockFrequencyKey)
|
||||
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
|
||||
def getRefClockFreq: Double = refClockFreq
|
||||
def buildtopClock: Clock
|
||||
def buildtopReset: Reset
|
||||
def success: Bool
|
||||
}
|
||||
|
||||
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
|
||||
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessInstantiators {
|
||||
val io = IO(new Bundle {
|
||||
val success = Output(Bool())
|
||||
})
|
||||
val success = WireInit(false.B)
|
||||
io.success := success
|
||||
|
||||
val buildtopClock = Wire(Clock())
|
||||
val buildtopReset = Wire(Reset())
|
||||
def implicitClock = clock
|
||||
def implicitReset = reset
|
||||
|
||||
val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop")
|
||||
val dut = Module(lazyDut.module)
|
||||
|
||||
io.success := false.B
|
||||
|
||||
val success = io.success
|
||||
|
||||
lazyDut match { case d: HasIOBinders =>
|
||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||
}
|
||||
|
||||
val refClkBundle = harnessClockInstantiator.requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
|
||||
|
||||
buildtopClock := refClkBundle.clock
|
||||
buildtopReset := WireInit(refClkBundle.reset)
|
||||
|
||||
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
implicitHarnessClockBundle.clock := clock
|
||||
implicitHarnessClockBundle.reset := reset
|
||||
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
|
||||
instantiateChipTops()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ package firesim.firesim
|
||||
|
||||
import chisel3._
|
||||
import chisel3.experimental.annotate
|
||||
import chisel3.experimental.{DataMirror, Direction}
|
||||
import chisel3.util.experimental.BoringUtils
|
||||
|
||||
import org.chipsalliance.cde.config.{Field, Config, Parameters}
|
||||
@@ -30,11 +31,12 @@ import cva6.CVA6Tile
|
||||
import boom.common.{BoomTile}
|
||||
import barstools.iocell.chisel._
|
||||
import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey}
|
||||
import chipyard._
|
||||
import chipyard.harness._
|
||||
|
||||
object MainMemoryConsts {
|
||||
val regionNamePrefix = "MainMemory"
|
||||
def globalName = s"${regionNamePrefix}_${NodeIdx()}"
|
||||
def globalName()(implicit p: Parameters) = s"${regionNamePrefix}_${p(MultiChipIdx)}"
|
||||
}
|
||||
|
||||
trait Unsupported {
|
||||
@@ -72,11 +74,9 @@ class WithTSIBridgeAndHarnessRAMOverSerialTL extends OverrideHarnessBinder({
|
||||
ports.map { port =>
|
||||
implicit val p = GetSystemParameters(system)
|
||||
val bits = port.bits
|
||||
port.clock := th.buildtopClock
|
||||
val ram = withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset)
|
||||
}
|
||||
TSIBridge(th.buildtopClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.buildtopReset.asBool)
|
||||
port.clock := th.harnessBinderClock
|
||||
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
|
||||
TSIBridge(th.harnessBinderClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.harnessBinderReset.asBool)
|
||||
}
|
||||
Nil
|
||||
}
|
||||
@@ -97,13 +97,13 @@ class WithUARTBridge extends OverrideHarnessBinder({
|
||||
val pbusClockNode = system.outer.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(PBUS).fixedClockNode
|
||||
val pbusClock = pbusClockNode.in.head._1.clock
|
||||
BoringUtils.bore(pbusClock, Seq(uartSyncClock))
|
||||
ports.map { p => UARTBridge(uartSyncClock, p, th.buildtopReset.asBool)(system.p) }; Nil
|
||||
ports.map { p => UARTBridge(uartSyncClock, p, th.harnessBinderReset.asBool)(system.p) }; Nil
|
||||
})
|
||||
|
||||
class WithBlockDeviceBridge extends OverrideHarnessBinder({
|
||||
(system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
|
||||
implicit val p: Parameters = GetSystemParameters(system)
|
||||
ports.map { b => BlockDevBridge(b.clock, b.bits, th.buildtopReset.asBool) }
|
||||
ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessBinderReset.asBool) }
|
||||
Nil
|
||||
}
|
||||
})
|
||||
@@ -120,21 +120,16 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({
|
||||
val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations])
|
||||
|
||||
ports.map({ port =>
|
||||
val axiClock = p(ClockBridgeInstantiatorKey).requestClock("mem_over_serial_tl_clock", memFreq)
|
||||
val axiClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||
axiClockBundle.clock := axiClock
|
||||
axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool)
|
||||
val axiClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq)
|
||||
|
||||
val serial_bits = port.bits
|
||||
port.clock := th.buildtopClock
|
||||
val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
||||
TSIHarness.connectMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
axiClockBundle,
|
||||
th.buildtopReset)
|
||||
}
|
||||
TSIBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.buildtopReset.asBool)
|
||||
port.clock := th.harnessBinderClock
|
||||
val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM(
|
||||
system.serdesser.get,
|
||||
serial_bits,
|
||||
axiClock,
|
||||
ResetCatchAndSync(axiClock, th.harnessBinderReset.asBool))
|
||||
TSIBridge(th.harnessBinderClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.harnessBinderReset.asBool)
|
||||
|
||||
// connect SimAxiMem
|
||||
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) =>
|
||||
@@ -192,7 +187,7 @@ class WithDromajoBridge extends ComposeHarnessBinder({
|
||||
|
||||
class WithTraceGenBridge extends OverrideHarnessBinder({
|
||||
(system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) =>
|
||||
ports.map { p => GroundTestBridge(th.buildtopClock, p)(system.p) }; Nil
|
||||
ports.map { p => GroundTestBridge(th.harnessBinderClock, p)(system.p) }; Nil
|
||||
})
|
||||
|
||||
class WithFireSimMultiCycleRegfile extends ComposeIOBinder({
|
||||
|
||||
@@ -20,258 +20,67 @@ import chipyard.harness._
|
||||
import chipyard.iobinders._
|
||||
import chipyard.clocking._
|
||||
|
||||
// Determines the number of times to instantiate the DUT in the harness.
|
||||
// Subsumes legacy supernode support
|
||||
case object NumNodes extends Field[Int](1)
|
||||
|
||||
class WithNumNodes(n: Int) extends Config((pname, site, here) => {
|
||||
case NumNodes => n
|
||||
})
|
||||
|
||||
// Hacky: Set before each node is generated. Ideally we'd give IO binders
|
||||
// accesses to the the Harness's parameters instance. We could then alter that.
|
||||
object NodeIdx {
|
||||
private var idx = 0
|
||||
def increment(): Unit = {idx = idx + 1 }
|
||||
def apply(): Int = idx
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies DUT clocks for the rational clock bridge
|
||||
*
|
||||
* @param allClocks Seq. of RationalClocks that want a clock
|
||||
*
|
||||
* @param baseClockName Name of domain that the allClocks is rational to
|
||||
*
|
||||
* @param baseFreqRequested Freq. for the reference domain in Hz
|
||||
*/
|
||||
case class BuildTopClockParameters(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double)
|
||||
|
||||
/**
|
||||
* Under FireSim's current multiclock implementation there can be only a
|
||||
* single clock bridge. This requires, therefore, that it be instantiated in
|
||||
* the harness and reused across all supernode instances. This class attempts to
|
||||
* memoize its instantiation such that it can be referenced from within a ClockScheme function.
|
||||
*/
|
||||
class ClockBridgeInstantiator {
|
||||
private val _harnessClockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty
|
||||
class FireSimClockBridgeInstantiator extends HarnessClockInstantiator {
|
||||
// connect all clock wires specified to the RationalClockBridge
|
||||
def instantiateHarnessClocks(refClock: Clock): Unit = {
|
||||
val sinks = clockMap.map({ case (name, (freq, bundle)) =>
|
||||
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name))
|
||||
}).toSeq
|
||||
|
||||
// Assumes that the supernode implementation results in duplicated clocks
|
||||
// (i.e. only 1 set of clocks is generated for all BuildTop designs)
|
||||
private var _buildTopClockParams: Option[BuildTopClockParameters] = None
|
||||
private val _buildTopClockMap: LinkedHashMap[String, (RationalClock, Clock)] = LinkedHashMap.empty
|
||||
private var _buildTopClockRecord: Option[RecordMap[Clock]] = None
|
||||
val pllConfig = new SimplePllConfiguration("firesimRationalClockBridge", sinks)
|
||||
pllConfig.emitSummaries()
|
||||
|
||||
/**
|
||||
* Request a clock at a particular frequency
|
||||
*
|
||||
* @param name An identifier for the associated clock domain
|
||||
*
|
||||
* @param freqRequested Freq. for the domain in Hz
|
||||
*/
|
||||
def requestClock(name: String, freqRequested: Double): Clock = {
|
||||
val clkWire = Wire(new Clock)
|
||||
_harnessClockMap(name) = (freqRequested, clkWire)
|
||||
clkWire
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a RecordMap of clocks for a set of input RationalClocks. Used to drive
|
||||
* the design elaborated by buildtop
|
||||
*
|
||||
* @param clockMapParameters Defines the set of required clocks
|
||||
*/
|
||||
def requestClockRecordMap(clockMapParameters: BuildTopClockParameters): RecordMap[Clock] = {
|
||||
if (_buildTopClockParams.isDefined) {
|
||||
require(_buildTopClockParams.get == clockMapParameters, "Must request same set of clocks on repeated invocations.")
|
||||
} else {
|
||||
val clockRecord = Wire(RecordMap(clockMapParameters.allClocks.map { c => (c.name, Clock()) }:_*))
|
||||
// Build up the mutable structures describing the clocks for the dut
|
||||
_buildTopClockParams = Some(clockMapParameters)
|
||||
_buildTopClockRecord = Some(clockRecord)
|
||||
|
||||
for (clock <- clockMapParameters.allClocks) {
|
||||
val clockWire = Wire(new Clock)
|
||||
_buildTopClockMap(clock.name) = (clock, clockWire)
|
||||
clockRecord(clock.name).get := clockWire
|
||||
var instantiatedClocks = LinkedHashMap[Int, (Clock, Seq[String])]()
|
||||
// connect wires to clock source
|
||||
for ((name, (freq, clock)) <- clockMap) {
|
||||
val freqMHz = (freq / (1000 * 1000)).toInt
|
||||
if (!instantiatedClocks.contains(freqMHz)) {
|
||||
val clock = Wire(Clock())
|
||||
instantiatedClocks(freqMHz) = (clock, Seq(name))
|
||||
} else {
|
||||
instantiatedClocks(freqMHz) = (instantiatedClocks(freqMHz)._1, instantiatedClocks(freqMHz)._2 :+ name)
|
||||
}
|
||||
clock := instantiatedClocks(freqMHz)._1
|
||||
}
|
||||
|
||||
_buildTopClockRecord.get
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect all clocks requested to ClockBridge
|
||||
*/
|
||||
def instantiateFireSimClockBridge: Unit = {
|
||||
require(_buildTopClockParams.isDefined, "Must have rational clocks to assign to")
|
||||
val BuildTopClockParameters(allClocks, refRatClockName, refRatClockFreq) = _buildTopClockParams.get
|
||||
require(_buildTopClockMap.exists(_._1 == refRatClockName),
|
||||
s"Provided base-clock name for rational clocks, ${refRatClockName}, doesn't match a name within specified rational clocks." +
|
||||
"Available clocks:\n " + _buildTopClockMap.map(_._1).mkString("\n "))
|
||||
|
||||
// Simplify the RationalClocks ratio's
|
||||
val refRatClock = _buildTopClockMap.find(_._1 == refRatClockName).get._2._1
|
||||
val simpleRatClocks = _buildTopClockMap.map { t =>
|
||||
val ratClock = t._2._1
|
||||
ratClock.copy(
|
||||
multiplier = ratClock.multiplier * refRatClock.divisor,
|
||||
divisor = ratClock.divisor * refRatClock.multiplier).simplify
|
||||
}
|
||||
|
||||
// Determine all the clock dividers (harness + rational clocks)
|
||||
// Note: Requires that the BuildTop reference frequency is requested with proper freq.
|
||||
val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(refRatClockName))
|
||||
val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) =>
|
||||
ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name))
|
||||
val ratClocks = instantiatedClocks.map { case (freqMHz, (clock, names)) =>
|
||||
(RationalClock(names.mkString(","), 1, pllConfig.referenceFreqMHz.toInt / freqMHz), clock)
|
||||
}.toSeq
|
||||
val allSinkParams = harSinkParams :+ refRatSinkParams
|
||||
|
||||
// Use PLL config to determine overall div's
|
||||
val pllConfig = new SimplePllConfiguration("firesimOverallClockBridge", allSinkParams)
|
||||
pllConfig.emitSummaries
|
||||
|
||||
// Adjust all BuildTop RationalClocks with the div determined by the PLL
|
||||
val refRatDiv = pllConfig.sinkDividerMap(refRatSinkParams)
|
||||
val adjRefRatClocks = simpleRatClocks.map { clock =>
|
||||
clock.copy(divisor = clock.divisor * refRatDiv).simplify
|
||||
}
|
||||
|
||||
// Convert harness clocks to RationalClocks
|
||||
val harRatClocks = harSinkParams.map { case ClockSinkParameters(_, _, _, _, clkParamsOpt, nameOpt) =>
|
||||
RationalClock(nameOpt.get, 1, pllConfig.referenceFreqMHz.toInt / clkParamsOpt.get.freqMHz.toInt)
|
||||
}
|
||||
|
||||
val allAdjRatClks = adjRefRatClocks ++ harRatClocks
|
||||
|
||||
// Removes clocks that have the same frequency before instantiating the
|
||||
// clock bridge to avoid unnecessary BUFGCE use.
|
||||
val allDistinctRatClocks = allAdjRatClks.foldLeft(Seq(RationalClock(pllConfig.referenceSinkParams.name.get, 1, 1))) {
|
||||
case (list, candidate) => if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate
|
||||
}
|
||||
|
||||
val clockBridge = Module(new RationalClockBridge(allDistinctRatClocks))
|
||||
val cbVecTuples = allDistinctRatClocks.zip(clockBridge.io.clocks)
|
||||
|
||||
// Connect all clocks (harness + BuildTop clocks)
|
||||
for (clock <- allAdjRatClks) {
|
||||
val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(clock)).get
|
||||
_buildTopClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
|
||||
_harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField }
|
||||
val clockBridge = Module(new RationalClockBridge(ratClocks.map(_._1)))
|
||||
(clockBridge.io.clocks zip ratClocks).foreach { case (clk, rat) =>
|
||||
rat._2 := clk
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case object ClockBridgeInstantiatorKey extends Field[ClockBridgeInstantiator](new ClockBridgeInstantiator)
|
||||
case object FireSimBaseClockNameKey extends Field[String]("implicit_clock")
|
||||
|
||||
class ClocksWithSinkParams(val params: Seq[ClockSinkParameters]) extends Bundle {
|
||||
val clocks = Vec(params.size, Clock())
|
||||
}
|
||||
|
||||
class WithFireSimSimpleClocks extends OverrideLazyIOBinder({
|
||||
(system: HasChipyardPRCI) => {
|
||||
implicit val p = GetSystemParameters(system)
|
||||
// Figure out what provides this in the chipyard scheme
|
||||
implicit val valName = ValName("FireSimClocking")
|
||||
|
||||
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
|
||||
system.connectImplicitClockSinkNode(implicitClockSinkNode)
|
||||
InModuleBody {
|
||||
val implicit_clock = implicitClockSinkNode.in.head._1.clock
|
||||
val implicit_reset = implicitClockSinkNode.in.head._1.reset
|
||||
system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => {
|
||||
l.clock := implicit_clock
|
||||
l.reset := implicit_reset
|
||||
}}
|
||||
}
|
||||
|
||||
val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
|
||||
system.allClockGroupsNode := inputClockSource
|
||||
|
||||
InModuleBody {
|
||||
val (clockGroupBundle, clockGroupEdge) = inputClockSource.out.head
|
||||
val reset_io = IO(Input(AsyncReset())).suggestName("async_reset")
|
||||
|
||||
val input_clocks = IO(Input(new ClocksWithSinkParams(clockGroupEdge.sink.members)))
|
||||
.suggestName("clocks")
|
||||
|
||||
(clockGroupBundle.member.data zip input_clocks.clocks).foreach { case (clockBundle, inputClock) =>
|
||||
clockBundle.clock := inputClock
|
||||
clockBundle.reset := reset_io
|
||||
}
|
||||
|
||||
(Seq(reset_io, input_clocks), Nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
class WithFireSimHarnessClockBinder extends OverrideHarnessBinder({
|
||||
(system: HasChipyardPRCI, th: FireSim, ports: Seq[Data]) => {
|
||||
implicit val p = th.p
|
||||
ports.map ({
|
||||
case c: ClocksWithSinkParams => {
|
||||
val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", c.params)
|
||||
pllConfig.emitSummaries
|
||||
th.setRefClockFreq(pllConfig.referenceFreqMHz)
|
||||
val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield {
|
||||
RationalClock(sinkP.name.get, 1, division)
|
||||
}
|
||||
val input_clocks: RecordMap[Clock] = p(ClockBridgeInstantiatorKey).requestClockRecordMap(
|
||||
BuildTopClockParameters(
|
||||
rationalClockSpecs.toSeq,
|
||||
p(FireSimBaseClockNameKey),
|
||||
pllConfig.referenceFreqMHz * (1000 * 1000)))
|
||||
(c.clocks zip c.params) map ({ case (clock, param) =>
|
||||
clock := input_clocks(param.name.get).get
|
||||
})
|
||||
}
|
||||
case r: Reset => r := th.buildtopReset.asAsyncReset
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences {
|
||||
class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessInstantiators {
|
||||
require(harnessClockInstantiator.isInstanceOf[FireSimClockBridgeInstantiator])
|
||||
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
|
||||
|
||||
val buildtopClock = Wire(Clock())
|
||||
val buildtopReset = WireInit(false.B)
|
||||
// The peek-poke bridge must still be instantiated even though it's
|
||||
// functionally unused. This will be removed in a future PR.
|
||||
val dummy = WireInit(false.B)
|
||||
val peekPokeBridge = PeekPokeBridge(buildtopClock, dummy)
|
||||
val peekPokeBridge = PeekPokeBridge(harnessBinderClock, dummy)
|
||||
|
||||
val resetBridge = Module(new ResetPulseBridge(ResetPulseBridgeParameters()))
|
||||
// In effect, the bridge counts the length of the reset in terms of this clock.
|
||||
resetBridge.io.clock := buildtopClock
|
||||
buildtopReset := resetBridge.io.reset
|
||||
// Ensures FireSim-synthesized assertions and instrumentation is disabled
|
||||
// while buildtopReset is asserted. This ensures assertions do not fire at
|
||||
// time zero in the event their local reset is delayed (typically because it
|
||||
// has been pipelined)
|
||||
midas.targetutils.GlobalResetCondition(buildtopReset)
|
||||
resetBridge.io.clock := harnessBinderClock
|
||||
|
||||
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
|
||||
def implicitClock = false.B.asClock // unused
|
||||
def implicitReset = resetBridge.io.reset
|
||||
def success = { require(false, "success should not be used in Firesim"); false.B }
|
||||
|
||||
// Instantiate multiple instances of the DUT to implement supernode
|
||||
for (i <- 0 until p(NumNodes)) {
|
||||
// It's not a RC bump without some hacks...
|
||||
// Copy the AsyncClockGroupsKey to generate a fresh node on each
|
||||
// instantiation of the dut, otherwise the initial instance will be
|
||||
// reused across each node
|
||||
import freechips.rocketchip.subsystem.AsyncClockGroupsKey
|
||||
val lazyModule = LazyModule(p(BuildTop)(p))
|
||||
val module = Module(lazyModule.module)
|
||||
instantiateChipTops()
|
||||
|
||||
lazyModule match { case d: HasIOBinders =>
|
||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||
}
|
||||
NodeIdx.increment()
|
||||
}
|
||||
|
||||
buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
|
||||
|
||||
p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge
|
||||
// Ensures FireSim-synthesized assertions and instrumentation is disabled
|
||||
// while resetBridge.io.reset is asserted. This ensures assertions do not fire at
|
||||
// time zero in the event their local reset is delayed (typically because it
|
||||
// has been pipelined)
|
||||
midas.targetutils.GlobalResetCondition(resetBridge.io.reset)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams}
|
||||
import scala.math.{min, max}
|
||||
|
||||
import chipyard.clocking.{ChipyardPRCIControlKey}
|
||||
import chipyard.harness.{HarnessClockInstantiatorKey}
|
||||
import icenet._
|
||||
|
||||
import firesim.bridges._
|
||||
@@ -43,6 +44,11 @@ class WithoutClockGating extends Config((site, here, up) => {
|
||||
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey, site).copy(enableTileClockGating = false)
|
||||
})
|
||||
|
||||
// Use the firesim clock bridge instantiator. this is required
|
||||
class WithFireSimHarnessClockBridgeInstantiator extends Config((site, here, up) => {
|
||||
case HarnessClockInstantiatorKey => () => new FireSimClockBridgeInstantiator
|
||||
})
|
||||
|
||||
// Testing configurations
|
||||
// This enables printfs used in testing
|
||||
class WithScalaTestFeatures extends Config((site, here, up) => {
|
||||
@@ -63,9 +69,10 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small")
|
||||
|
||||
// Minimal set of FireSim-related design tweaks - notably discludes FASED, TraceIO, and the BlockDevice
|
||||
class WithMinimalFireSimDesignTweaks extends Config(
|
||||
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
|
||||
new WithFireSimHarnessClockBinder ++
|
||||
new WithFireSimSimpleClocks ++
|
||||
// Required*: Punch all clocks to FireSim's harness clock instantiator
|
||||
new WithFireSimHarnessClockBridgeInstantiator ++
|
||||
new chipyard.harness.WithClockAndResetFromHarness ++
|
||||
new chipyard.clocking.WithPassthroughClockGenerator ++
|
||||
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
|
||||
new WithBootROM ++
|
||||
// Required: Existing FAME-1 transform cannot handle black-box clock gates
|
||||
@@ -116,19 +123,11 @@ class WithFireSimConfigTweaks extends Config(
|
||||
// Using some other frequency will require runnings the FASED runtime configuration generator
|
||||
// to generate faithful DDR3 timing values.
|
||||
new chipyard.config.WithSystemBusFrequency(1000.0) ++
|
||||
new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (1000 MHz)
|
||||
// Explicitly set PBUS + MBUS to 1000 MHz, since they will be driven to 100 MHz by default because of assignments in the Chisel
|
||||
new chipyard.config.WithPeripheryBusFrequency(1000.0) ++
|
||||
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
|
||||
new WithFireSimDesignTweaks
|
||||
)
|
||||
|
||||
// Tweak more representative of testchip configs
|
||||
class WithFireSimTestChipConfigTweaks extends Config(
|
||||
new chipyard.config.WithTestChipBusFreqs ++
|
||||
new WithFireSimDesignTweaks
|
||||
)
|
||||
|
||||
// Tweaks to use minimal design tweaks
|
||||
// Need to use initramfs to use linux (no block device)
|
||||
class WithMinimalFireSimHighPerfConfigTweaks extends Config(
|
||||
@@ -267,9 +266,10 @@ class FireSimLeanGemminiPrintfRocketConfig extends Config(
|
||||
// Supernode Configurations, base off chipyard's RocketConfig
|
||||
//**********************************************************************************
|
||||
class SupernodeFireSimRocketConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8 GB
|
||||
new FireSimRocketConfig)
|
||||
new WithFireSimHarnessClockBridgeInstantiator ++
|
||||
new chipyard.harness.WithHomogeneousMultiChip(n=4, new Config(
|
||||
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8GB DRAM per node
|
||||
new FireSimRocketConfig)))
|
||||
|
||||
//**********************************************************************************
|
||||
//* CVA6 Configurations
|
||||
|
||||
Submodule generators/testchipip updated: ebf61569c5...e95e807464
Reference in New Issue
Block a user