Switch PRCI to HarnessBinder/IOBinders
This commit is contained in:
@@ -7,7 +7,7 @@ import freechips.rocketchip.config.{Parameters}
|
|||||||
|
|
||||||
import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell}
|
import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell}
|
||||||
|
|
||||||
import chipyard.{BuildTop, HasHarnessSignalReferences, HasTestHarnessFunctions}
|
import chipyard.{BuildTop, HasHarnessSignalReferences}
|
||||||
import chipyard.harness.{ApplyHarnessBinders}
|
import chipyard.harness.{ApplyHarnessBinders}
|
||||||
import chipyard.iobinders.{HasIOBinders}
|
import chipyard.iobinders.{HasIOBinders}
|
||||||
|
|
||||||
@@ -34,9 +34,6 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell
|
|||||||
val dutReset = dReset
|
val dutReset = dReset
|
||||||
|
|
||||||
// must be after HasHarnessSignalReferences assignments
|
// must be after HasHarnessSignalReferences assignments
|
||||||
lazyDut match { case d: HasTestHarnessFunctions =>
|
|
||||||
d.harnessFunctions.foreach(_(this))
|
|
||||||
}
|
|
||||||
lazyDut match { case d: HasIOBinders =>
|
lazyDut match { case d: HasIOBinders =>
|
||||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import sifive.blocks.devices.uart._
|
|||||||
import sifive.blocks.devices.spi._
|
import sifive.blocks.devices.spi._
|
||||||
import sifive.blocks.devices.gpio._
|
import sifive.blocks.devices.gpio._
|
||||||
|
|
||||||
import chipyard.{HasHarnessSignalReferences, HasTestHarnessFunctions, BuildTop, ChipTop, ExtTLMem, CanHaveMasterTLMemPort, DefaultClockFrequencyKey, HasReferenceClockFreq}
|
import chipyard.{HasHarnessSignalReferences, BuildTop, ChipTop, ExtTLMem, CanHaveMasterTLMemPort, DefaultClockFrequencyKey}
|
||||||
import chipyard.iobinders.{HasIOBinders}
|
import chipyard.iobinders.{HasIOBinders}
|
||||||
import chipyard.harness.{ApplyHarnessBinders}
|
import chipyard.harness.{ApplyHarnessBinders}
|
||||||
|
|
||||||
@@ -129,17 +129,11 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod
|
|||||||
childReset := buildtopReset
|
childReset := buildtopReset
|
||||||
|
|
||||||
// harness binders are non-lazy
|
// harness binders are non-lazy
|
||||||
_outer.topDesign match { case d: HasTestHarnessFunctions =>
|
|
||||||
d.harnessFunctions.foreach(_(this))
|
|
||||||
}
|
|
||||||
_outer.topDesign match { case d: HasIOBinders =>
|
_outer.topDesign match { case d: HasIOBinders =>
|
||||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the top-level reference clock is equal to the default
|
// check the top-level reference clock is equal to the default
|
||||||
// non-exhaustive since you need all ChipTop clocks to equal the default
|
// non-exhaustive since you need all ChipTop clocks to equal the default
|
||||||
_outer.topDesign match {
|
require(getRefClockFreq == p(DefaultClockFrequencyKey))
|
||||||
case d: HasReferenceClockFreq => require(d.refClockFreqMHz == p(DefaultClockFrequencyKey))
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ import barstools.iocell.chisel._
|
|||||||
|
|
||||||
case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p))
|
case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p))
|
||||||
|
|
||||||
trait HasReferenceClockFreq {
|
|
||||||
def refClockFreqMHz: Double
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter,
|
* The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter,
|
||||||
* named "system", which is an instance of DigitalTop by default. The diplomatic clocks of System, as well as its implicit clock,
|
* named "system", which is an instance of DigitalTop by default. The diplomatic clocks of System, as well as its implicit clock,
|
||||||
@@ -27,31 +23,14 @@ trait HasReferenceClockFreq {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope
|
class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope
|
||||||
with HasTestHarnessFunctions with HasReferenceClockFreq with HasIOBinders {
|
with HasIOBinders {
|
||||||
// The system module specified by BuildSystem
|
// The system module specified by BuildSystem
|
||||||
lazy 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 (connected by clocking scheme)
|
|
||||||
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
|
|
||||||
|
|
||||||
// Generate Clocks and Reset
|
|
||||||
val mvRefClkFreq = p(ClockingSchemeKey)(this)
|
|
||||||
def refClockFreqMHz: Double = mvRefClkFreq.getWrappedValue
|
|
||||||
|
|
||||||
// NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children
|
// NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children
|
||||||
// of ChipTop (ex: ClockGroup) do not receive clock or reset.
|
// of ChipTop (ex: ClockGroup) do not receive clock or reset.
|
||||||
// However. anonymous children of ChipTop should not need an implicit Clock or Reset
|
// However. anonymous children of ChipTop should not need an implicit Clock or Reset
|
||||||
// anyways, they probably need to be explicitly clocked.
|
// anyways, they probably need to be explicitly clocked.
|
||||||
lazy val module: LazyModuleImpLike = new LazyRawModuleImp(this) {
|
lazy val module: LazyModuleImpLike = new LazyRawModuleImp(this) { }
|
||||||
// These become the implicit clock and reset to the System
|
|
||||||
val implicit_clock = implicitClockSinkNode.in.head._1.clock
|
|
||||||
val implicit_reset = implicitClockSinkNode.in.head._1.reset
|
|
||||||
|
|
||||||
// Connect the implicit clock/reset, if present
|
|
||||||
lazySystem.module match { case l: LazyModuleImp => {
|
|
||||||
l.clock := implicit_clock
|
|
||||||
l.reset := implicit_reset
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
package chipyard
|
|
||||||
|
|
||||||
import chisel3._
|
|
||||||
|
|
||||||
import scala.collection.mutable.{ArrayBuffer}
|
|
||||||
|
|
||||||
import freechips.rocketchip.prci._
|
|
||||||
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, InstantiatesTiles}
|
|
||||||
import freechips.rocketchip.config.{Parameters, Field, Config}
|
|
||||||
import freechips.rocketchip.diplomacy.{ModuleValue, OutwardNodeHandle, InModuleBody, LazyModule}
|
|
||||||
import freechips.rocketchip.util.{ResetCatchAndSync}
|
|
||||||
|
|
||||||
import barstools.iocell.chisel._
|
|
||||||
import testchipip.{TLTileResetCtrl}
|
|
||||||
|
|
||||||
import chipyard.clocking._
|
|
||||||
import chipyard.iobinders._
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple reset implementation that punches out reset ports
|
|
||||||
* for standard Module classes. The ChipTop reset pin is Async.
|
|
||||||
* Synchronization is performed in the ClockGroupResetSynchronizer
|
|
||||||
*/
|
|
||||||
object GenerateReset {
|
|
||||||
def apply(chiptop: ChipTop, clock: Clock): Reset = {
|
|
||||||
implicit val p = chiptop.p
|
|
||||||
// this needs directionality so generateIOFromSignal works
|
|
||||||
val async_reset_wire = Wire(Input(AsyncReset()))
|
|
||||||
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(async_reset_wire, "reset", p(IOCellKey),
|
|
||||||
abstractResetAsAsync = true)
|
|
||||||
|
|
||||||
chiptop.iocells ++= resetIOCell
|
|
||||||
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
|
||||||
reset_io := th.dutReset
|
|
||||||
Nil
|
|
||||||
})
|
|
||||||
async_reset_wire
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
case object ClockingSchemeKey extends Field[ChipTop => ModuleValue[Double]](ClockingSchemeGenerators.dividerOnlyClockGenerator)
|
|
||||||
/*
|
|
||||||
* This is a Seq of assignment functions, that accept a clock name and return an optional frequency.
|
|
||||||
* Functions that appear later in this seq have higher precedence that earlier ones.
|
|
||||||
* If no function returns a non-empty value, the value specified in
|
|
||||||
* [[DefaultClockFrequencyKey]] will be used.
|
|
||||||
*/
|
|
||||||
case object ClockFrequencyAssignersKey extends Field[Seq[(String) => Option[Double]]](Seq.empty)
|
|
||||||
case object DefaultClockFrequencyKey extends Field[Double]()
|
|
||||||
|
|
||||||
class ClockNameMatchesAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
|
||||||
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
|
|
||||||
Seq((cName: String) => if (cName == name) Some(fMHz) else None)
|
|
||||||
})
|
|
||||||
|
|
||||||
class ClockNameContainsAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
|
||||||
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
|
|
||||||
Seq((cName: String) => if (cName.contains(name)) Some(fMHz) else None)
|
|
||||||
})
|
|
||||||
|
|
||||||
object ClockingSchemeGenerators {
|
|
||||||
val dividerOnlyClockGenerator: ChipTop => ModuleValue[Double] = { chiptop =>
|
|
||||||
implicit val p = chiptop.p
|
|
||||||
|
|
||||||
// Requires existence of undriven asyncClockGroups in subsystem
|
|
||||||
val systemAsyncClockGroup = chiptop.lazySystem match {
|
|
||||||
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) =>
|
|
||||||
l.asyncClockGroupsNode
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a control register for each tile's reset
|
|
||||||
val resetSetter = chiptop.lazySystem match {
|
|
||||||
case sys: BaseSubsystem with InstantiatesTiles => Some(TLTileResetCtrl(sys))
|
|
||||||
case _ => None
|
|
||||||
}
|
|
||||||
val resetSetterResetProvider = resetSetter.map(_.tileResetProviderNode).getOrElse(ClockGroupEphemeralNode())
|
|
||||||
|
|
||||||
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
|
|
||||||
// provides the implicit clock to the system
|
|
||||||
(chiptop.implicitClockSinkNode
|
|
||||||
:= ClockGroup()
|
|
||||||
:= aggregator)
|
|
||||||
// provides the system clock (ex. the bus clocks)
|
|
||||||
(systemAsyncClockGroup
|
|
||||||
:*= ClockGroupNamePrefixer()
|
|
||||||
:*= aggregator)
|
|
||||||
|
|
||||||
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
|
||||||
val dividerOnlyClkGenerator = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator"))
|
|
||||||
// provides all the divided clocks (from the top-level clock)
|
|
||||||
(aggregator
|
|
||||||
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
|
|
||||||
:= ClockGroupResetSynchronizer()
|
|
||||||
:= resetSetterResetProvider
|
|
||||||
:= dividerOnlyClkGenerator.node
|
|
||||||
:= referenceClockSource)
|
|
||||||
|
|
||||||
val asyncResetBroadcast = FixedClockBroadcast(None)
|
|
||||||
resetSetter.foreach(_.asyncResetSinkNode := asyncResetBroadcast)
|
|
||||||
val asyncResetSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
|
||||||
asyncResetBroadcast := asyncResetSource
|
|
||||||
|
|
||||||
InModuleBody {
|
|
||||||
val clock_wire = Wire(Input(Clock()))
|
|
||||||
val reset_wire = GenerateReset(chiptop, clock_wire)
|
|
||||||
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
|
|
||||||
chiptop.iocells ++= clockIOCell
|
|
||||||
|
|
||||||
referenceClockSource.out.unzip._1.map { o =>
|
|
||||||
o.clock := clock_wire
|
|
||||||
o.reset := reset_wire
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncResetSource.out.unzip._1.map { o =>
|
|
||||||
o.clock := false.B.asClock // async reset broadcast network does not provide a clock
|
|
||||||
o.reset := reset_wire
|
|
||||||
}
|
|
||||||
|
|
||||||
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
|
||||||
clock_io := th.buildtopClock
|
|
||||||
Nil })
|
|
||||||
|
|
||||||
// return the reference frequency
|
|
||||||
dividerOnlyClkGenerator.module.referenceFreq
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,6 +31,7 @@ import sifive.blocks.devices.uart._
|
|||||||
import sifive.blocks.devices.spi._
|
import sifive.blocks.devices.spi._
|
||||||
|
|
||||||
import chipyard._
|
import chipyard._
|
||||||
|
import chipyard.clocking._
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// Common Config Fragments
|
// Common Config Fragments
|
||||||
@@ -68,8 +69,10 @@ class WithL2TLBs(entries: Int) extends Config((site, here, up) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
class TraceGenTop(implicit p: Parameters) extends TraceGenSystem
|
||||||
|
with HasChipyardPRCI
|
||||||
class WithTracegenSystem extends Config((site, here, up) => {
|
class WithTracegenSystem extends Config((site, here, up) => {
|
||||||
case BuildSystem => (p: Parameters) => new TraceGenSystem()(p)
|
case BuildSystem => (p: Parameters) => new TraceGenTop()(p)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class DigitalTop(implicit p: Parameters) extends ChipyardSystem
|
|||||||
with chipyard.example.CanHavePeripheryStreamingFIR // Enables optionally adding the DSPTools FIR example widget
|
with chipyard.example.CanHavePeripheryStreamingFIR // Enables optionally adding the DSPTools FIR example widget
|
||||||
with chipyard.example.CanHavePeripheryStreamingPassthrough // Enables optionally adding the DSPTools streaming-passthrough example widget
|
with chipyard.example.CanHavePeripheryStreamingPassthrough // Enables optionally adding the DSPTools streaming-passthrough example widget
|
||||||
with nvidia.blocks.dla.CanHavePeripheryNVDLA // Enables optionally having an NVDLA
|
with nvidia.blocks.dla.CanHavePeripheryNVDLA // Enables optionally having an NVDLA
|
||||||
|
with chipyard.clocking.HasChipyardPRCI // Use Chipyard reset/clock distribution
|
||||||
{
|
{
|
||||||
override lazy val module = new DigitalTopModule(this)
|
override lazy val module = new DigitalTopModule(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import barstools.iocell.chisel._
|
|||||||
import testchipip._
|
import testchipip._
|
||||||
|
|
||||||
import chipyard.{HasHarnessSignalReferences, HarnessClockInstantiatorKey}
|
import chipyard.{HasHarnessSignalReferences, HarnessClockInstantiatorKey}
|
||||||
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO}
|
import chipyard.clocking.{HasChipyardPRCI}
|
||||||
|
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, ClockWithFreq}
|
||||||
|
|
||||||
import tracegen.{TraceGenSystemModuleImp}
|
import tracegen.{TraceGenSystemModuleImp}
|
||||||
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
|
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
|
||||||
@@ -322,8 +323,23 @@ class WithSimDromajoBridge extends ComposeHarnessBinder({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
class WithTieOffCustomBootPin extends OverrideHarnessBinder({
|
class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
|
||||||
(system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
|
(system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => {
|
||||||
ports.foreach(_ := false.B)
|
val pin = PlusArg("custom_boot_pin", width=1)
|
||||||
|
ports.foreach(_ := pin)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class WithClockAndResetFromHarness extends OverrideHarnessBinder({
|
||||||
|
(system: HasChipyardPRCI, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
|
||||||
|
implicit val p = GetSystemParameters(system)
|
||||||
|
ports.map ({
|
||||||
|
case c: ClockWithFreq => {
|
||||||
|
th.setRefClockFreq(c.freqMHz)
|
||||||
|
c.clock := th.buildtopClock
|
||||||
|
}
|
||||||
|
case r: AsyncReset => r := th.buildtopReset.asAsyncReset
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import freechips.rocketchip.subsystem._
|
|||||||
import freechips.rocketchip.system.{SimAXIMem}
|
import freechips.rocketchip.system.{SimAXIMem}
|
||||||
import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters}
|
import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters}
|
||||||
import freechips.rocketchip.util._
|
import freechips.rocketchip.util._
|
||||||
import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters}
|
import freechips.rocketchip.prci._
|
||||||
import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem}
|
import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem}
|
||||||
|
|
||||||
import sifive.blocks.devices.gpio._
|
import sifive.blocks.devices.gpio._
|
||||||
@@ -23,6 +23,7 @@ import barstools.iocell.chisel._
|
|||||||
|
|
||||||
import testchipip._
|
import testchipip._
|
||||||
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
|
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
|
||||||
|
import chipyard.clocking.{HasChipyardPRCI, DividerOnlyClockGenerator}
|
||||||
|
|
||||||
import scala.reflect.{ClassTag}
|
import scala.reflect.{ClassTag}
|
||||||
|
|
||||||
@@ -384,3 +385,45 @@ class WithDontTouchPorts extends OverrideIOBinder({
|
|||||||
(system: DontTouch) => system.dontTouchPorts(); (Nil, Nil)
|
(system: DontTouch) => system.dontTouchPorts(); (Nil, Nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
class ClockWithFreq(val freqMHz: Double) extends Bundle {
|
||||||
|
val clock = Clock()
|
||||||
|
}
|
||||||
|
|
||||||
|
class WithDividerOnlyClockGenerator extends OverrideLazyIOBinder({
|
||||||
|
(system: HasChipyardPRCI) => {
|
||||||
|
// Connect the implicit clock
|
||||||
|
implicit val p = GetSystemParameters(system)
|
||||||
|
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
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect all other requested clocks
|
||||||
|
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
||||||
|
val dividerOnlyClockGen = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator"))
|
||||||
|
|
||||||
|
(system.allClockGroupsNode
|
||||||
|
:= dividerOnlyClockGen.node
|
||||||
|
:= referenceClockSource)
|
||||||
|
|
||||||
|
InModuleBody {
|
||||||
|
val clock_wire = Wire(Input(new ClockWithFreq(dividerOnlyClockGen.module.referenceFreq)))
|
||||||
|
val reset_wire = Wire(Input(AsyncReset()))
|
||||||
|
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
|
||||||
|
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
|
||||||
|
|
||||||
|
referenceClockSource.out.unzip._1.map { o =>
|
||||||
|
o.clock := clock_wire.clock
|
||||||
|
o.reset := reset_wire
|
||||||
|
}
|
||||||
|
|
||||||
|
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
|
|||||||
// -------------------------------
|
// -------------------------------
|
||||||
|
|
||||||
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
||||||
|
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
|
||||||
trait HasTestHarnessFunctions {
|
|
||||||
val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]]
|
|
||||||
}
|
|
||||||
|
|
||||||
trait HasHarnessSignalReferences {
|
trait HasHarnessSignalReferences {
|
||||||
|
implicit val p: Parameters
|
||||||
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
// 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 buildtopClock: Clock
|
||||||
def buildtopReset: Reset
|
def buildtopReset: Reset
|
||||||
def dutReset: Reset
|
def dutReset: Reset
|
||||||
@@ -90,25 +91,18 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign
|
|||||||
|
|
||||||
io.success := false.B
|
io.success := false.B
|
||||||
|
|
||||||
val freqMHz = lazyDut match {
|
val dutReset = buildtopReset.asAsyncReset
|
||||||
case d: HasReferenceClockFreq => d.refClockFreqMHz
|
|
||||||
case _ => p(DefaultClockFrequencyKey)
|
|
||||||
}
|
|
||||||
val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000))
|
|
||||||
|
|
||||||
buildtopClock := refClkBundle.clock
|
|
||||||
buildtopReset := WireInit(refClkBundle.reset)
|
|
||||||
val dutReset = refClkBundle.reset.asAsyncReset
|
|
||||||
|
|
||||||
val success = io.success
|
val success = io.success
|
||||||
|
|
||||||
lazyDut match { case d: HasTestHarnessFunctions =>
|
|
||||||
d.harnessFunctions.foreach(_(this))
|
|
||||||
}
|
|
||||||
lazyDut match { case d: HasIOBinders =>
|
lazyDut match { case d: HasIOBinders =>
|
||||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
|
||||||
|
|
||||||
|
buildtopClock := refClkBundle.clock
|
||||||
|
buildtopReset := WireInit(refClkBundle.reset)
|
||||||
|
|
||||||
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||||
implicitHarnessClockBundle.clock := clock
|
implicitHarnessClockBundle.clock := clock
|
||||||
implicitHarnessClockBundle.reset := reset
|
implicitHarnessClockBundle.reset := reset
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package chipyard.clocking
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import chisel3.experimental.{Analog, IO}
|
||||||
|
|
||||||
|
import freechips.rocketchip.config._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.prci._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.devices.tilelink._
|
||||||
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
|
||||||
|
object ClockGroupCombiner {
|
||||||
|
def apply()(implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = {
|
||||||
|
LazyModule(new ClockGroupCombiner()).node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** This node combines sets of clock groups according to functions provided in the ClockGroupCombinerKey
|
||||||
|
* The ClockGroupCombinersKey contains a list of tuples of:
|
||||||
|
* - The name of the combined group
|
||||||
|
* - A function on the ClockSinkParameters, returning True if the associated clock group should be grouped by this node
|
||||||
|
* This node will fail if
|
||||||
|
* - Multiple grouping functions match a single clock group
|
||||||
|
* - A grouping function matches zero clock groups
|
||||||
|
* - A grouping function matches clock groups with different requested frequncies
|
||||||
|
*/
|
||||||
|
class ClockGroupCombiner(implicit p: Parameters, v: ValName) extends LazyModule {
|
||||||
|
val combiners = p(ClockGroupCombinerKey)
|
||||||
|
val sourceFn: ClockGroupSourceParameters => ClockGroupSourceParameters = { m => m }
|
||||||
|
val sinkFn: ClockGroupSinkParameters => ClockGroupSinkParameters = { u =>
|
||||||
|
var i = 0
|
||||||
|
val (grouped, rest) = combiners.map(_._2).foldLeft((Seq[ClockSinkParameters](), u.members)) { case ((grouped, rest), c) =>
|
||||||
|
val (g, r) = rest.partition(c(_))
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
ClockGroupSinkParameters(
|
||||||
|
name = u.name,
|
||||||
|
members = grouped ++ rest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val node = ClockGroupAdapterNode(sourceFn, sinkFn)
|
||||||
|
lazy val module = new LazyRawModuleImp(this) {
|
||||||
|
(node.out zip node.in).map { case ((o, oe), (i, ie)) =>
|
||||||
|
{
|
||||||
|
val inMap = (i.member.data zip ie.sink.members).map { case (id, im) =>
|
||||||
|
im.name.get -> id
|
||||||
|
}.toMap
|
||||||
|
(o.member.data zip oe.sink.members).map { case (od, om) =>
|
||||||
|
val matches = combiners.filter(c => c._2(om))
|
||||||
|
require(matches.size <= 1)
|
||||||
|
if (matches.size == 0) {
|
||||||
|
od := inMap(om.name.get)
|
||||||
|
} else {
|
||||||
|
od := inMap(matches(0)._1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,23 @@ package chipyard.clocking
|
|||||||
|
|
||||||
import chisel3._
|
import chisel3._
|
||||||
|
|
||||||
import freechips.rocketchip.config.{Parameters}
|
import freechips.rocketchip.config.{Parameters, Config, Field}
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.prci._
|
import freechips.rocketchip.prci._
|
||||||
|
|
||||||
|
case object ClockFrequencyAssignersKey extends Field[Seq[(String) => Option[Double]]](Seq.empty)
|
||||||
|
|
||||||
|
class ClockNameMatchesAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
||||||
|
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
|
||||||
|
Seq((cName: String) => if (cName == name) Some(fMHz) else None)
|
||||||
|
})
|
||||||
|
|
||||||
|
class ClockNameContainsAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
||||||
|
case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++
|
||||||
|
Seq((cName: String) => if (cName.contains(name)) Some(fMHz) else None)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sort of node can be used when it is a connectivity passthrough, but modifies
|
* This sort of node can be used when it is a connectivity passthrough, but modifies
|
||||||
* the flow of parameters (which may result in changing the names of the underlying signals).
|
* the flow of parameters (which may result in changing the names of the underlying signals).
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package chipyard.clocking
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
|
||||||
|
import scala.collection.mutable.{ArrayBuffer}
|
||||||
|
|
||||||
|
import freechips.rocketchip.config.{Parameters, Field, Config}
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.devices.tilelink._
|
||||||
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.tile._
|
||||||
|
import freechips.rocketchip.prci._
|
||||||
|
|
||||||
|
import testchipip.{TLTileResetCtrl}
|
||||||
|
import chipyard.{DefaultClockFrequencyKey}
|
||||||
|
|
||||||
|
case class ChipyardPRCIControlParams(
|
||||||
|
slaveWhere: TLBusWrapperLocation = CBUS,
|
||||||
|
baseAddress: BigInt = 0x100000,
|
||||||
|
enableTileClockGating: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
case object ChipyardPRCIControlKey extends Field[ChipyardPRCIControlParams](ChipyardPRCIControlParams())
|
||||||
|
|
||||||
|
trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles =>
|
||||||
|
require(p(SubsystemDriveAsyncClockGroupsKey).isEmpty, "Subsystem asyncClockGroups must be undriven")
|
||||||
|
|
||||||
|
implicit val n = ValName("chipyardPRCI")
|
||||||
|
|
||||||
|
val prciParams = p(ChipyardPRCIControlKey)
|
||||||
|
|
||||||
|
// Set up clock domain
|
||||||
|
private val tlbus = locateTLBusWrapper(prciParams.slaveWhere)
|
||||||
|
val prci_ctrl_domain = LazyModule(new ClockSinkDomain(name=Some("chipyard-prci-control")))
|
||||||
|
prci_ctrl_domain.clockNode := tlbus.fixedClockNode
|
||||||
|
|
||||||
|
// Aggregate all the clock groups into a single node
|
||||||
|
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
|
||||||
|
val allClockGroupsNode = ClockGroupEphemeralNode()
|
||||||
|
|
||||||
|
// There are two "sets" of clocks which must be dealt with
|
||||||
|
|
||||||
|
// 1. The implicit clock from the subsystem. RC is moving away from depending on this
|
||||||
|
// clock, but some modules still use it. Since the implicit clock sink node
|
||||||
|
// is created in the ChipTop (the hierarchy wrapping the subsystem), this function
|
||||||
|
// is provided to allow connecting that clock to the clock aggregator. This function
|
||||||
|
// should be called in the ChipTop context
|
||||||
|
def connectImplicitClockSinkNode(sink: ClockSinkNode) =
|
||||||
|
(sink
|
||||||
|
:= ClockGroup()
|
||||||
|
:= aggregator)
|
||||||
|
|
||||||
|
// 2. The rest of the diplomatic clocks in the subsystem are routed to this asyncClockGroupsNode
|
||||||
|
(asyncClockGroupsNode
|
||||||
|
:*= ClockGroupNamePrefixer()
|
||||||
|
:*= aggregator)
|
||||||
|
|
||||||
|
|
||||||
|
// Once all the clocks are gathered in the aggregator node, several steps remain
|
||||||
|
// 1. Assign frequencies to any clock groups which did not specify a frequency.
|
||||||
|
// 2. Combine duplicated clock groups (clock groups which physically should be in the same clock domain)
|
||||||
|
// 3. Synchronize reset to each clock group
|
||||||
|
// 4. Clock gate the clock groups corresponding to Tiles (if desired).
|
||||||
|
// 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
|
||||||
|
(aggregator
|
||||||
|
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
|
||||||
|
:= ClockGroupCombiner()
|
||||||
|
:= ClockGroupResetSynchronizer()
|
||||||
|
:= TileClockGater(prciParams.baseAddress + 0x00000, tlbus, prciParams.enableTileClockGating)
|
||||||
|
:= TileResetSetter(prciParams.baseAddress + 0x10000, tlbus, tile_prci_domains.map(_.tile_reset_domain.clockNode.portParams(0).name.get), Nil)
|
||||||
|
:= allClockGroupsNode)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package chipyard.clocking
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import chisel3.experimental.{Analog, IO}
|
||||||
|
|
||||||
|
import freechips.rocketchip.config._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.prci._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.devices.tilelink._
|
||||||
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
|
||||||
|
/** This node adds clock gating control registers.
|
||||||
|
* If deploying on a platform which does not support clock gating, deasserting the enable
|
||||||
|
* flag will generate the registers, preserving the same memory map and behavior, but will not
|
||||||
|
* generate any gaters
|
||||||
|
*/
|
||||||
|
class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit p: Parameters, valName: ValName) extends LazyModule
|
||||||
|
{
|
||||||
|
val device = new SimpleDevice(s"clock-gater", Nil)
|
||||||
|
val clockNode = ClockGroupIdentityNode()
|
||||||
|
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val sources = clockNode.in.head._1.member.data.toSeq
|
||||||
|
val sinks = clockNode.out.head._1.member.elements.toSeq
|
||||||
|
val nSinks = sinks.size
|
||||||
|
val regs = (0 until nSinks).map({i =>
|
||||||
|
val sinkName = sinks(i)._1
|
||||||
|
val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) }
|
||||||
|
if (sinkName.contains("tile") && enable) {
|
||||||
|
println(s"ClockGate for ${sinkName} regmapped at ${(address+i*4).toString(16)}")
|
||||||
|
sinks(i)._2.clock := ClockGate(sources(i).clock, reg.io.q.asBool)
|
||||||
|
sinks(i)._2.reset := sources(i).reset
|
||||||
|
} else {
|
||||||
|
sinks(i)._2 := sources(i)
|
||||||
|
}
|
||||||
|
reg
|
||||||
|
})
|
||||||
|
tlNode.regmap((0 until nSinks).map({i =>
|
||||||
|
i*4 -> Seq(RegField.rwReg(1, regs(i).io))
|
||||||
|
}): _*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TileClockGater {
|
||||||
|
def apply(address: BigInt, tlbus: TLBusWrapper, enable: Boolean)(implicit p: Parameters, v: ValName) = {
|
||||||
|
val gater = LazyModule(new TileClockGater(address, tlbus.beatBytes, enable))
|
||||||
|
tlbus.toVariableWidthSlave(Some("clock-gater")) { gater.tlNode := TLBuffer() }
|
||||||
|
gater.clockNode
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package chipyard.clocking
|
||||||
|
|
||||||
|
import chisel3._
|
||||||
|
import chisel3.util._
|
||||||
|
import chisel3.experimental.{Analog, IO}
|
||||||
|
|
||||||
|
import freechips.rocketchip.config._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
import freechips.rocketchip.diplomacy._
|
||||||
|
import freechips.rocketchip.prci._
|
||||||
|
import freechips.rocketchip.util._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
|
import freechips.rocketchip.devices.tilelink._
|
||||||
|
import freechips.rocketchip.regmapper._
|
||||||
|
import freechips.rocketchip.subsystem._
|
||||||
|
|
||||||
|
// Currently only works if all tiles are already driven by independent clock groups
|
||||||
|
// TODO: After https://github.com/chipsalliance/rocket-chip/pull/2842 is merged, we should
|
||||||
|
// always put all tiles on independent clock groups
|
||||||
|
class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], initResetHarts: Seq[Int])(implicit p: Parameters)
|
||||||
|
extends LazyModule {
|
||||||
|
val device = new SimpleDevice("tile-reset-setter", Nil)
|
||||||
|
val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)
|
||||||
|
val clockNode = ClockGroupIdentityNode()
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val nTiles = p(TilesLocated(InSubsystem)).size
|
||||||
|
require (nTiles <= 4096 / 4)
|
||||||
|
val tile_async_resets = Wire(Vec(nTiles, Reset()))
|
||||||
|
val r_tile_resets = (0 until nTiles).map({ i =>
|
||||||
|
tile_async_resets(i) := true.B.asAsyncReset // Remove this line after https://github.com/chipsalliance/rocket-chip/pull/2842
|
||||||
|
withReset (tile_async_resets(i)) {
|
||||||
|
Module(new AsyncResetRegVec(w=1, init=(if (initResetHarts.contains(i)) 1 else 0)))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tlNode.regmap((0 until nTiles).map({ i =>
|
||||||
|
i * 4 -> Seq(RegField.rwReg(1, r_tile_resets(i).io)),
|
||||||
|
}): _*)
|
||||||
|
|
||||||
|
val tileMap = tileNames.zipWithIndex.map({ case (n, i) =>
|
||||||
|
n -> (tile_async_resets(i), r_tile_resets(i).io.q)
|
||||||
|
})
|
||||||
|
|
||||||
|
(clockNode.out zip clockNode.in).map { case ((o, _), (i, _)) =>
|
||||||
|
(o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) =>
|
||||||
|
oD.clock := iD.clock
|
||||||
|
oD.reset := iD.reset
|
||||||
|
for ((n, (rIn, rOut)) <- tileMap) {
|
||||||
|
if (name.contains(n)) {
|
||||||
|
println(name, n)
|
||||||
|
// Async because the reset coming out of the AsyncResetRegVec is
|
||||||
|
// clocked to the bus this is attached to, not the clock in this
|
||||||
|
// clock bundle. We expect a ClockGroupResetSynchronizer downstream
|
||||||
|
// to synchronize the resets
|
||||||
|
// Also, this or enforces that the tiles come out of reset after the reset of the system
|
||||||
|
oD.reset := (rOut.asBool || iD.reset.asBool).asAsyncReset
|
||||||
|
rIn := iD.reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object TileResetSetter {
|
||||||
|
def apply(address: BigInt, tlbus: TLBusWrapper, tileNames: Seq[String], initResetHarts: Seq[Int])(implicit p: Parameters, v: ValName) = {
|
||||||
|
val setter = LazyModule(new TileResetSetter(address, tlbus.beatBytes, tileNames, initResetHarts))
|
||||||
|
tlbus.toVariableWidthSlave(Some("tile-reset-setter")) { setter.tlNode := TLBuffer() }
|
||||||
|
setter.clockNode
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,8 @@ class AbstractConfig extends Config(
|
|||||||
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
|
new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
|
||||||
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
|
new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present
|
||||||
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
|
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
|
||||||
new chipyard.harness.WithTieOffCustomBootPin ++
|
new chipyard.harness.WithCustomBootPinPlusArg ++
|
||||||
|
new chipyard.harness.WithClockAndResetFromHarness ++
|
||||||
|
|
||||||
// The IOBinders instantiate ChipTop IOs to match desired digital IOs
|
// The IOBinders instantiate ChipTop IOs to match desired digital IOs
|
||||||
// IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through
|
// IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through
|
||||||
@@ -39,6 +40,7 @@ class AbstractConfig extends Config(
|
|||||||
new chipyard.iobinders.WithTraceIOPunchthrough ++
|
new chipyard.iobinders.WithTraceIOPunchthrough ++
|
||||||
new chipyard.iobinders.WithExtInterruptIOCells ++
|
new chipyard.iobinders.WithExtInterruptIOCells ++
|
||||||
new chipyard.iobinders.WithCustomBootPin ++
|
new chipyard.iobinders.WithCustomBootPin ++
|
||||||
|
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
|
||||||
|
|
||||||
new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM
|
new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM
|
||||||
new chipyard.config.WithBootROM ++ // use default bootrom
|
new chipyard.config.WithBootROM ++ // use default bootrom
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import freechips.rocketchip.rocket.{DCacheParams}
|
|||||||
class AbstractTraceGenConfig extends Config(
|
class AbstractTraceGenConfig extends Config(
|
||||||
new chipyard.harness.WithBlackBoxSimMem ++
|
new chipyard.harness.WithBlackBoxSimMem ++
|
||||||
new chipyard.harness.WithTraceGenSuccess ++
|
new chipyard.harness.WithTraceGenSuccess ++
|
||||||
|
new chipyard.harness.WithClockAndResetFromHarness ++
|
||||||
new chipyard.iobinders.WithAXI4MemPunchthrough ++
|
new chipyard.iobinders.WithAXI4MemPunchthrough ++
|
||||||
new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++
|
new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++
|
||||||
|
new chipyard.iobinders.WithDividerOnlyClockGenerator ++
|
||||||
new chipyard.config.WithTracegenSystem ++
|
new chipyard.config.WithTracegenSystem ++
|
||||||
new chipyard.config.WithNoSubsystemDrivenClocks ++
|
new chipyard.config.WithNoSubsystemDrivenClocks ++
|
||||||
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++
|
new chipyard.config.WithPeripheryBusFrequencyAsDefault ++
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import chisel3.experimental.{IO}
|
|||||||
import freechips.rocketchip.prci._
|
import freechips.rocketchip.prci._
|
||||||
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
|
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
|
||||||
import freechips.rocketchip.config.{Field, Config, Parameters}
|
import freechips.rocketchip.config.{Field, Config, Parameters}
|
||||||
import freechips.rocketchip.diplomacy.{LazyModule, InModuleBody, ValName}
|
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, InModuleBody, ValName}
|
||||||
import freechips.rocketchip.util.{ResetCatchAndSync, RecordMap}
|
import freechips.rocketchip.util.{ResetCatchAndSync, RecordMap}
|
||||||
|
|
||||||
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock, ResetPulseBridge, ResetPulseBridgeParameters}
|
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock, ResetPulseBridge, ResetPulseBridgeParameters}
|
||||||
@@ -166,59 +166,69 @@ class ClockBridgeInstantiator {
|
|||||||
case object ClockBridgeInstantiatorKey extends Field[ClockBridgeInstantiator](new ClockBridgeInstantiator)
|
case object ClockBridgeInstantiatorKey extends Field[ClockBridgeInstantiator](new ClockBridgeInstantiator)
|
||||||
case object FireSimBaseClockNameKey extends Field[String]("implicit_clock")
|
case object FireSimBaseClockNameKey extends Field[String]("implicit_clock")
|
||||||
|
|
||||||
class WithFireSimSimpleClocks extends Config((site, here, up) => {
|
class ClocksWithSinkParams(val params: Seq[ClockSinkParameters]) extends Bundle {
|
||||||
case ClockingSchemeKey => { chiptop: ChipTop =>
|
val clocks = Vec(params.size, Clock())
|
||||||
implicit val p = chiptop.p
|
}
|
||||||
|
|
||||||
|
class WithFireSimSimpleClocks extends OverrideLazyIOBinder({
|
||||||
|
(system: HasChipyardPRCI) => {
|
||||||
|
implicit val p = GetSystemParameters(system)
|
||||||
// Figure out what provides this in the chipyard scheme
|
// Figure out what provides this in the chipyard scheme
|
||||||
implicit val valName = ValName("FireSimClocking")
|
implicit val valName = ValName("FireSimClocking")
|
||||||
|
|
||||||
// Requires existence of undriven asyncClockGroups in subsystem
|
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
|
||||||
val systemAsyncClockGroup = chiptop.lazySystem match {
|
system.connectImplicitClockSinkNode(implicitClockSinkNode)
|
||||||
case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) =>
|
InModuleBody {
|
||||||
l.asyncClockGroupsNode
|
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 aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
|
|
||||||
(chiptop.implicitClockSinkNode := ClockGroup() := aggregator)
|
|
||||||
(systemAsyncClockGroup :*= ClockGroupNamePrefixer() :*= aggregator)
|
|
||||||
|
|
||||||
val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
|
val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
|
||||||
|
system.allClockGroupsNode := inputClockSource
|
||||||
(aggregator
|
|
||||||
:= ClockGroupResetSynchronizer()
|
|
||||||
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
|
|
||||||
:= inputClockSource)
|
|
||||||
|
|
||||||
|
|
||||||
InModuleBody {
|
InModuleBody {
|
||||||
val (clockGroupBundle, clockGroupEdge) = inputClockSource.out.head
|
val (clockGroupBundle, clockGroupEdge) = inputClockSource.out.head
|
||||||
val input_clocks = IO(Input(RecordMap((clockGroupEdge.sink.members.map { m => (m.name.get, Clock()) }):_* )))
|
val reset_io = IO(Input(AsyncReset())).suggestName("async_reset")
|
||||||
|
|
||||||
|
val input_clocks = IO(Input(new ClocksWithSinkParams(clockGroupEdge.sink.members)))
|
||||||
.suggestName("clocks")
|
.suggestName("clocks")
|
||||||
val reset = IO(Input(Reset())).suggestName("reset")
|
|
||||||
|
|
||||||
(clockGroupBundle.member.data zip input_clocks.data).foreach { case (clockBundle, inputClock) =>
|
(clockGroupBundle.member.data zip input_clocks.clocks).foreach { case (clockBundle, inputClock) =>
|
||||||
clockBundle.clock := inputClock
|
clockBundle.clock := inputClock
|
||||||
clockBundle.reset := reset
|
clockBundle.reset := reset_io
|
||||||
}
|
}
|
||||||
|
|
||||||
val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", clockGroupEdge.sink.members)
|
(Seq(reset_io, input_clocks), Nil)
|
||||||
pllConfig.emitSummaries
|
}
|
||||||
val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield {
|
}
|
||||||
RationalClock(sinkP.name.get, 1, division)
|
})
|
||||||
}
|
|
||||||
|
|
||||||
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
class WithFireSimHarnessClockBinder extends OverrideHarnessBinder({
|
||||||
reset := th.buildtopReset
|
(system: HasChipyardPRCI, th: FireSim, ports: Seq[Data]) => {
|
||||||
input_clocks := p(ClockBridgeInstantiatorKey)
|
implicit val p = th.p
|
||||||
.requestClockRecordMap(BuildTopClockParameters(
|
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,
|
rationalClockSpecs.toSeq,
|
||||||
p(FireSimBaseClockNameKey),
|
p(FireSimBaseClockNameKey),
|
||||||
pllConfig.referenceFreqMHz * (1000 * 1000)))
|
pllConfig.referenceFreqMHz * (1000 * 1000)))
|
||||||
Nil })
|
(c.clocks zip c.params) map ({ case (clock, param) =>
|
||||||
|
clock := input_clocks(param.name.get).get
|
||||||
// return the reference frequency
|
})
|
||||||
pllConfig.referenceFreqMHz
|
}
|
||||||
}
|
case r: Reset => r := th.buildtopReset.asAsyncReset
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -245,8 +255,6 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna
|
|||||||
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
|
def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B }
|
||||||
def success = { require(false, "success should not be used in Firesim"); false.B }
|
def success = { require(false, "success should not be used in Firesim"); false.B }
|
||||||
|
|
||||||
var btFreqMHz: Option[Double] = None
|
|
||||||
|
|
||||||
// Instantiate multiple instances of the DUT to implement supernode
|
// Instantiate multiple instances of the DUT to implement supernode
|
||||||
for (i <- 0 until p(NumNodes)) {
|
for (i <- 0 until p(NumNodes)) {
|
||||||
// It's not a RC bump without some hacks...
|
// It's not a RC bump without some hacks...
|
||||||
@@ -259,22 +267,13 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna
|
|||||||
})))
|
})))
|
||||||
val module = Module(lazyModule.module)
|
val module = Module(lazyModule.module)
|
||||||
|
|
||||||
btFreqMHz = Some(lazyModule match {
|
|
||||||
case d: HasReferenceClockFreq => d.refClockFreqMHz
|
|
||||||
case _ => p(DefaultClockFrequencyKey)
|
|
||||||
})
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
lazyModule match { case d: HasIOBinders =>
|
lazyModule match { case d: HasIOBinders =>
|
||||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
||||||
}
|
}
|
||||||
NodeIdx.increment()
|
NodeIdx.increment()
|
||||||
}
|
}
|
||||||
|
|
||||||
buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000))
|
buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", getRefClockFreq * (1000 * 1000))
|
||||||
|
|
||||||
p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge
|
p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import testchipip.{BlockDeviceKey, BlockDeviceConfig, TracePortKey, TracePortPar
|
|||||||
import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams}
|
import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams}
|
||||||
import scala.math.{min, max}
|
import scala.math.{min, max}
|
||||||
|
|
||||||
|
import chipyard.clocking.{ChipyardPRCIControlKey}
|
||||||
import icenet._
|
import icenet._
|
||||||
import testchipip.WithRingSystemBus
|
import testchipip.WithRingSystemBus
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ class WithBootROM extends Config((site, here, up) => {
|
|||||||
// Disables clock-gating; doesn't play nice with our FAME-1 pass
|
// Disables clock-gating; doesn't play nice with our FAME-1 pass
|
||||||
class WithoutClockGating extends Config((site, here, up) => {
|
class WithoutClockGating extends Config((site, here, up) => {
|
||||||
case DebugModuleKey => up(DebugModuleKey, site).map(_.copy(clockGate = false))
|
case DebugModuleKey => up(DebugModuleKey, site).map(_.copy(clockGate = false))
|
||||||
|
case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey, site).copy(enableTileClockGating = false)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Testing configurations
|
// Testing configurations
|
||||||
@@ -65,6 +67,7 @@ class WithFireSimDesignTweaks extends Config(
|
|||||||
// Required: Bake in the default FASED memory model
|
// Required: Bake in the default FASED memory model
|
||||||
new WithDefaultMemModel ++
|
new WithDefaultMemModel ++
|
||||||
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
|
// Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset
|
||||||
|
new WithFireSimHarnessClockBinder ++
|
||||||
new WithFireSimSimpleClocks ++
|
new WithFireSimSimpleClocks ++
|
||||||
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
|
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
|
||||||
new WithBootROM ++
|
new WithBootROM ++
|
||||||
|
|||||||
Reference in New Issue
Block a user