Merge remote-tracking branch 'ch/lazy-iobinders' into local-fpga-temp

This commit is contained in:
Abraham Gonzalez
2020-10-20 21:23:11 -07:00
23 changed files with 424 additions and 246 deletions

View File

@@ -47,7 +47,7 @@ LOCAL_FIRESIM_DIR=$LOCAL_CHIPYARD_DIR/sims/firesim/sim
# key value store to get the build groups # key value store to get the build groups
declare -A grouping declare -A grouping
grouping["group-cores"]="chipyard-ariane chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor" grouping["group-cores"]="chipyard-ariane chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor chipyard-digitaltop"
grouping["group-peripherals"]="chipyard-dmirocket chipyard-blkdev chipyard-spiflashread chipyard-spiflashwrite chipyard-mmios chipyard-lbwif" grouping["group-peripherals"]="chipyard-dmirocket chipyard-blkdev chipyard-spiflashread chipyard-spiflashwrite chipyard-mmios chipyard-lbwif"
grouping["group-accels"]="chipyard-nvdla chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-streaming-fir chipyard-streaming-passthrough" grouping["group-accels"]="chipyard-nvdla chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-streaming-fir chipyard-streaming-passthrough"
grouping["group-tracegen"]="tracegen tracegen-boom" grouping["group-tracegen"]="tracegen tracegen-boom"
@@ -59,6 +59,7 @@ mapping["chipyard-rocket"]=""
mapping["chipyard-dmirocket"]=" CONFIG=dmiRocketConfig" mapping["chipyard-dmirocket"]=" CONFIG=dmiRocketConfig"
mapping["chipyard-lbwif"]=" CONFIG=LBWIFRocketConfig" mapping["chipyard-lbwif"]=" CONFIG=LBWIFRocketConfig"
mapping["chipyard-sha3"]=" CONFIG=Sha3RocketConfig" mapping["chipyard-sha3"]=" CONFIG=Sha3RocketConfig"
mapping["chipyard-digitaltop"]=" TOP=DigitalTop"
mapping["chipyard-streaming-fir"]=" CONFIG=StreamingFIRRocketConfig" mapping["chipyard-streaming-fir"]=" CONFIG=StreamingFIRRocketConfig"
mapping["chipyard-streaming-passthrough"]=" CONFIG=StreamingPassthroughRocketConfig" mapping["chipyard-streaming-passthrough"]=" CONFIG=StreamingPassthroughRocketConfig"
mapping["chipyard-hetero"]=" CONFIG=LargeBoomAndRocketConfig" mapping["chipyard-hetero"]=" CONFIG=LargeBoomAndRocketConfig"

View File

@@ -110,7 +110,7 @@ generator_temp: $(SCALA_SOURCES) $(sim_files) $(EXTRA_GENERATOR_REQS)
--target-dir $(build_dir) \ --target-dir $(build_dir) \
--name $(long_name) \ --name $(long_name) \
--top-module $(MODEL_PACKAGE).$(MODEL) \ --top-module $(MODEL_PACKAGE).$(MODEL) \
--legacy-configs $(CONFIG_PACKAGE).$(CONFIG)) --legacy-configs $(CONFIG_PACKAGE):$(CONFIG))
.PHONY: firrtl .PHONY: firrtl
firrtl: $(FIRRTL_FILE) firrtl: $(FIRRTL_FILE)

View File

@@ -4,7 +4,7 @@ IOBinders and HarnessBinders
In Chipyard we use special ``Parameters`` keys, ``IOBinders`` and ``HarnessBinders`` to bridge the gap between digital system IOs and TestHarness collateral. In Chipyard we use special ``Parameters`` keys, ``IOBinders`` and ``HarnessBinders`` to bridge the gap between digital system IOs and TestHarness collateral.
IOBinders IOBinders
========= ---------
The ``IOBinder`` functions are responsible for instantiating IO cells and IOPorts in the ``ChipTop`` layer. The ``IOBinder`` functions are responsible for instantiating IO cells and IOPorts in the ``ChipTop`` layer.
@@ -19,7 +19,7 @@ For example, the ``WithUARTIOCells`` IOBinder will, for any ``System`` that migh
:end-before: DOC include end: WithUARTIOCells :end-before: DOC include end: WithUARTIOCells
HarnessBinders HarnessBinders
============== --------------
The ``HarnessBinder`` functions determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. The ``HarnessBinder`` interface is designed to be reused across various simulation/implementation modes, enabling decoupling of the target design from simulation and testing concerns. The ``HarnessBinder`` functions determine what modules to bind to the IOs of a ``ChipTop`` in the ``TestHarness``. The ``HarnessBinder`` interface is designed to be reused across various simulation/implementation modes, enabling decoupling of the target design from simulation and testing concerns.

View File

@@ -46,7 +46,20 @@ and proceed with the rest of the tutorial.
Running your Design in FireSim Running your Design in FireSim
------------------------------ ------------------------------
Converting a Chipyard config (one in ``chipyard/src/main/scala`` to run in FireSim is simple. We are using the same target (top) RTL, and only need to specify a new set of connection behaviors for the IOs of that module. Simply create a matching config within ``generators/firechip/src/main/scala/TargetConfigs`` that inherits your config defined in ``chipyard``. Converting a Chipyard config (one in ``chipyard/src/main/scala`` to run in FireSim is simple, and can be done either through the traditional configuration system or through FireSim's build-recipes scheme.
A FireSim simulation requires 3 additional config fragments:
* ``WithFireSimConfigTweaks`` modifies your design to better fit the FireSim usage model. This is composed of multiple smaller config fragments. For example, the removal of clock-gating (using the ``WithoutClockGating`` config fragment) which is required for correct functioning of the compiler. This config fragment also includes other config fragments such as the inclusion of UART in the design, which although may technically be optional,is *strongly* recommended.
* ``WithDefaultMemModel`` provides a default configuration for FASED memory models in the FireSim simulation. See the FireSim documentation for details. This config fragment is currently included by default within ``WithFireSimConfigTweaks``, so it isn't neccessary to add in separately, but it is required if you choose not to use ``WithFireSimConfigTweaks``.
* ``WithDefaultFireSimBridges`` sets the ``IOBinders`` key to use FireSim's Bridge system, which can drive target IOs with software bridge models running on the simulation host. See the FireSim documentation for details.
The simplest method to add this config fragments to your custom Chipyard config is through FireSim's build recipe scheme.
After your FireSim environment is setup, you will define your custom build recipe in ``sims/firesim/deploy/deploy/config_build_recipes.ini``. By prepending the FireSim config fragments (separated by ``_``) to your Chipyard configuration, these config fragments will be added to your custom configuration as if they were listed in a custom Chisel config class definition. For example, if you would like to convert the Chipyard ``LargeBoomConfig`` to a FireSim simulation with a DDR3 memory model, the appropriate FireSim ``TARGET_CONFIG`` would be ``DDR3FRFCFSLLC4MB_WithDefaultFireSimBridges_WithFireSimConfigTweaks_chipyard.LargeBoomConfig``. Note that the FireSim config fragments are part of the ``firesim.firesim`` scala package and therefore there do not need to be prefixed with the full package name as opposed to the Chipyard config fragments which need to be prefixed with the chipyard package name.
An alternative method to prepending the FireSim config fragments in the FireSim build recipe is to create a new "permanent" FireChip custom configuration, which includes the FireSim config fragments.
We are using the same target (top) RTL, and only need to specify a new set of connection behaviors for the IOs of that module. Simply create a matching config within ``generators/firechip/src/main/scala/TargetConfigs`` that inherits your config defined in ``chipyard``.
.. literalinclude:: ../../generators/firechip/src/main/scala/TargetConfigs.scala .. literalinclude:: ../../generators/firechip/src/main/scala/TargetConfigs.scala
@@ -54,9 +67,4 @@ Converting a Chipyard config (one in ``chipyard/src/main/scala`` to run in FireS
:start-after: DOC include start: firesimconfig :start-after: DOC include start: firesimconfig
:end-before: DOC include end: firesimconfig :end-before: DOC include end: firesimconfig
While this option seems to require the maintenance of additional configuration code, it has the benefit of allowing for the inclusion of more complex config fragments which also accept custom arguments (for example, ``WithDefaultMemModel`` can take an optional argument``)
Only 3 additional config fragments are needed.
* ``WithFireSimConfigTweaks`` modifies your design to better fit the FireSim usage model. For example, FireSim designs typically include a UART. Technically, adding this in is optional, but *strongly* recommended.
* ``WithDefaultMemModel`` sets the external memory model in the FireSim simulation. See the FireSim documentation for details.
* ``WithDefaultFireSimBridges`` sets the ``IOBinders`` key to use FireSim's Bridge system, which can drive target IOs with software bridge models running on the simulation host. See the FireSim documentation for details.

View File

@@ -23,12 +23,10 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters)
* drive clock and reset generation * drive clock and reset generation
*/ */
class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunctions with BindingScope { class ChipTop(implicit p: Parameters) extends LazyModule
// A publicly accessible list of IO cells (useful for a floorplanning tool, for example) with HasTestHarnessFunctions with HasIOBinders with BindingScope {
val iocells = ArrayBuffer.empty[IOCell]
// The system module specified by BuildSystem // The system module specified by BuildSystem
val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system")
// The implicitClockSinkNode provides the implicit clock and reset for the System // The implicitClockSinkNode provides the implicit clock and reset for the System
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
@@ -45,13 +43,6 @@ class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunc
val implicit_clock = implicitClockSinkNode.in.head._1.clock val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset val implicit_reset = implicitClockSinkNode.in.head._1.reset
// Note: IOBinders cannot rely on the implicit clock/reset, as this is a LazyRawModuleImp
val (_ports, _iocells, _portMap) = ApplyIOBinders(lazySystem, p(IOBinders))
// We ignore _ports for now...
iocells ++= _iocells
portMap ++= _portMap
// Connect the implicit clock/reset, if present // Connect the implicit clock/reset, if present
lazySystem.module match { case l: LazyModuleImp => { lazySystem.module match { case l: LazyModuleImp => {
l.clock := implicit_clock l.clock := implicit_clock

View File

@@ -8,12 +8,12 @@ import freechips.rocketchip.prci._
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, InstantiatesTiles} import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, InstantiatesTiles}
import freechips.rocketchip.config.{Parameters, Field, Config} import freechips.rocketchip.config.{Parameters, Field, Config}
import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule} import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule}
import freechips.rocketchip.util.{ResetCatchAndSync, Pow2ClockDivider} import freechips.rocketchip.util.{ResetCatchAndSync}
import barstools.iocell.chisel._ import barstools.iocell.chisel._
import testchipip.{TLTileResetCtrl} import testchipip.{TLTileResetCtrl}
import chipyard.clocking.{DividerOnlyClockGenerator, ClockGroupNamePrefixer, ClockGroupFrequencySpecifier} import chipyard.clocking._
/** /**
* Chipyard provides three baseline, top-level reset schemes, set using the * Chipyard provides three baseline, top-level reset schemes, set using the
@@ -121,13 +121,14 @@ object ClockingSchemeGenerators {
:= ClockGroup() := ClockGroup()
:= aggregator) := aggregator)
(systemAsyncClockGroup (systemAsyncClockGroup
:= resetSetter :*= resetSetter
:= ClockGroupNamePrefixer() :*= ClockGroupNamePrefixer()
:= aggregator) :*= aggregator)
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters())) val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
(aggregator (aggregator
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) := ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
:= ClockGroupResetSynchronizer()
:= DividerOnlyClockGenerator() := DividerOnlyClockGenerator()
:= referenceClockSource) := referenceClockSource)

View File

@@ -5,13 +5,13 @@ import chisel3.util.{log2Up}
import freechips.rocketchip.config.{Field, Parameters, Config} import freechips.rocketchip.config.{Field, Parameters, Config}
import freechips.rocketchip.subsystem._ import freechips.rocketchip.subsystem._
import freechips.rocketchip.diplomacy.{LazyModule, ValName} import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.tilelink.{BootROMLocated} import freechips.rocketchip.devices.tilelink.{BootROMLocated}
import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI} import freechips.rocketchip.devices.debug.{Debug, ExportDebug, DebugModuleKey, DMI}
import freechips.rocketchip.groundtest.{GroundTestSubsystem} import freechips.rocketchip.groundtest.{GroundTestSubsystem}
import freechips.rocketchip.tile._ import freechips.rocketchip.tile._
import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams} import freechips.rocketchip.rocket.{RocketCoreParams, MulDivParams, DCacheParams, ICacheParams}
import freechips.rocketchip.util.{AsyncResetReg} import freechips.rocketchip.util.{AsyncResetReg, Symmetric}
import freechips.rocketchip.prci._ import freechips.rocketchip.prci._
import testchipip._ import testchipip._
@@ -172,3 +172,46 @@ class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => {
case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get / (1000 * 1000)).toDouble case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get / (1000 * 1000)).toDouble
}) })
/**
* Mixins to specify crossing types between the 5 traditional TL buses
*
* Note: these presuppose the legacy connections between buses and set
* parameters in SubsystemCrossingParams; they may not be resuable in custom
* topologies (but you can specify the desired crossings in your topology).
*
* @param xType The clock crossing type
*
*/
class WithSbusToMbusCrossingType(xType: ClockCrossingType) extends Config((site, here, up) => {
case SbusToMbusXTypeKey => xType
})
class WithSbusToCbusCrossingType(xType: ClockCrossingType) extends Config((site, here, up) => {
case SbusToCbusXTypeKey => xType
})
class WithCbusToPbusCrossingType(xType: ClockCrossingType) extends Config((site, here, up) => {
case CbusToPbusXTypeKey => xType
})
class WithFbusToSbusCrossingType(xType: ClockCrossingType) extends Config((site, here, up) => {
case FbusToSbusXTypeKey => xType
})
/**
* Mixins to set the dtsFrequency field of BusParams -- these will percolate its way
* up the diplomatic graph to the clock sources.
*/
class WithPeripheryBusFrequency(freqMHz: Double) extends Config((site, here, up) => {
case PeripheryBusKey => up(PeripheryBusKey).copy(dtsFrequency = Some(BigInt((freqMHz * 1e6).toLong)))
})
class WithMemoryBusFrequency(freqMHz: Double) extends Config((site, here, up) => {
case MemoryBusKey => up(MemoryBusKey).copy(dtsFrequency = Some(BigInt((freqMHz * 1e6).toLong)))
})
class WithSystemBusFrequency(freqMHz: Double) extends Config((site, here, up) => {
case SystemBusKey => up(SystemBusKey).copy(dtsFrequency = Some(BigInt((freqMHz * 1e6).toLong)))
})
class WithControlBusFrequency(freqMHz: Double) extends Config((site, here, up) => {
case ControlBusKey => up(ControlBusKey).copy(dtsFrequency = Some(BigInt((freqMHz * 1e6).toLong)))
})
class WithRationalMemoryBusCrossing extends WithSbusToMbusCrossingType(RationalCrossing(Symmetric))
class WithAsynchrousMemoryBusCrossing extends WithSbusToMbusCrossingType(AsynchronousCrossing())

View File

@@ -0,0 +1,62 @@
package chipyard
import freechips.rocketchip.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.{Location, Symmetric}
import freechips.rocketchip.subsystem._
// I'm putting this code here temporarily as I think it should be a candidate
// for upstreaming based on input from Henry Cook, but don't wnat to deal with
// an RC branch just yet.
// For subsystem/BusTopology.scala
/**
* Keys that serve as a means to define crossing types from a Parameters instance
*/
case object SbusToMbusXTypeKey extends Field[ClockCrossingType](NoCrossing)
case object SbusToCbusXTypeKey extends Field[ClockCrossingType](NoCrossing)
case object CbusToPbusXTypeKey extends Field[ClockCrossingType](SynchronousCrossing())
case object FbusToSbusXTypeKey extends Field[ClockCrossingType](SynchronousCrossing())
// Biancolin: This, modified from Henry's email
/** Parameterization of a topology containing a banked coherence manager and a bus for attaching memory devices. */
case class CoherentMulticlockBusTopologyParams(
sbus: SystemBusParams, // TODO remove this after better width propagation
mbus: MemoryBusParams,
l2: BankedL2Params,
sbusToMbusXType: ClockCrossingType = NoCrossing
) extends TLBusWrapperTopology(
instantiations = (if (l2.nBanks == 0) Nil else List(
(MBUS, mbus),
(L2, CoherenceManagerWrapperParams(mbus.blockBytes, mbus.beatBytes, l2.nBanks, L2.name)(l2.coherenceManager)))),
connections = if (l2.nBanks == 0) Nil else List(
(SBUS, L2, TLBusWrapperConnection(xType = NoCrossing, driveClockFromMaster = Some(true), nodeBinding = BIND_STAR)()),
(L2, MBUS, TLBusWrapperConnection.crossTo(
xType = sbusToMbusXType,
driveClockFromMaster = Some(true),
nodeBinding = BIND_QUERY))
)
)
// For subsystem/Configs.scala
class WithMulticlockCoherentBusTopology extends Config((site, here, up) => {
case TLNetworkTopologyLocated(InSubsystem) => List(
JustOneBusTopologyParams(sbus = site(SystemBusKey)),
HierarchicalBusTopologyParams(
pbus = site(PeripheryBusKey),
fbus = site(FrontBusKey),
cbus = site(ControlBusKey),
xTypes = SubsystemCrossingParams(
sbusToCbusXType = site(SbusToCbusXTypeKey),
cbusToPbusXType = site(CbusToPbusXTypeKey),
fbusToSbusXType = site(FbusToSbusXTypeKey))),
CoherentMulticlockBusTopologyParams(
sbus = site(SystemBusKey),
mbus = site(MemoryBusKey),
l2 = site(BankedL2Key),
sbusToMbusXType = site(SbusToMbusXTypeKey)))
})

View File

@@ -1,7 +1,7 @@
package chipyard.harness package chipyard.harness
import chisel3._ import chisel3._
import chisel3.experimental.{Analog} import chisel3.experimental.{Analog, BaseModule}
import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
@@ -31,42 +31,43 @@ case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalRefer
Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil) Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil)
) )
object ApplyHarnessBinders { object ApplyHarnessBinders {
def apply(th: HasHarnessSignalReferences, sys: LazyModule, map: Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]], portMap: Map[String, Seq[Data]]) = { def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters) = {
val pm = portMap.withDefaultValue(Nil) val pm = portMap.withDefaultValue(Nil)
map.map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } p(HarnessBinders).map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) }
} }
} }
class OverrideHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { // The ClassTags here are necessary to overcome issues arising from type erasure
case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Seq[Any]) => (T, S, Seq[U]) => Seq[Any])(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => {
case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString ->
((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => {
val pts = ports.collect({case p: S => p}) val pts = ports.collect({case p: U => p})
require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${portTag}")
t match { val upfn = up(HarnessBinders, site)(systemTag.runtimeClass.toString)
case system: T => fn(system, th, pts) th match {
case th: S =>
t match {
case system: T => composer(upfn)(system, th, pts)
case _ => Nil
}
case _ => Nil case _ => Nil
} }
}) })
) )
}) })
class ComposeHarnessBinder[T, S <: Data](fn: => (T, HasHarnessSignalReferences, Seq[S]) => Seq[Any])(implicit tag: ClassTag[T], ptag: ClassTag[S]) extends Config((site, here, up) => { class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any])
case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => fn)
val pts = ports.collect({case p: S => p})
require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${ptag}") class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Seq[Any])
t match { (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
case system: T => up(HarnessBinders, site)(tag.runtimeClass.toString)(system, th, pts) ++ fn(system, th, pts) extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Seq[Any]) => (t, th, p) => upfn(t, th, p) ++ fn(t, th, p))
case _ => Nil
}
})
)
})
class WithGPIOTiedOff extends OverrideHarnessBinder({ class WithGPIOTiedOff extends OverrideHarnessBinder({
(system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => { (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Analog]) => {
ports.foreach { _ <> AnalogConst(0) } ports.foreach { _ <> AnalogConst(0) }
Nil Nil
} }
@@ -74,7 +75,7 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({
// DOC include start: WithUARTAdapter // DOC include start: WithUARTAdapter
class WithUARTAdapter extends OverrideHarnessBinder({ class WithUARTAdapter extends OverrideHarnessBinder({
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => {
UARTAdapter.connect(ports)(system.p) UARTAdapter.connect(ports)(system.p)
Nil Nil
} }
@@ -82,14 +83,14 @@ class WithUARTAdapter extends OverrideHarnessBinder({
// DOC include end: WithUARTAdapter // DOC include end: WithUARTAdapter
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { (system: HasPeripherySPIFlashModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => {
SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p) SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p)
Nil Nil
} }
}) })
class WithSimBlockDevice extends OverrideHarnessBinder({ class WithSimBlockDevice extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) } ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) }
Nil Nil
@@ -97,7 +98,7 @@ class WithSimBlockDevice extends OverrideHarnessBinder({
}) })
class WithBlockDeviceModel extends OverrideHarnessBinder({ class WithBlockDeviceModel extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { (system: CanHavePeripheryBlockDevice, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } } ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } }
Nil Nil
@@ -105,7 +106,7 @@ class WithBlockDeviceModel extends OverrideHarnessBinder({
}) })
class WithLoopbackNIC extends OverrideHarnessBinder({ class WithLoopbackNIC extends OverrideHarnessBinder({
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
ports.map { n => ports.map { n =>
withClockAndReset(n.clock, th.harnessReset) { withClockAndReset(n.clock, th.harnessReset) {
@@ -117,7 +118,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({
}) })
class WithSimNetwork extends OverrideHarnessBinder({ class WithSimNetwork extends OverrideHarnessBinder({
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) } ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) }
Nil Nil
@@ -125,11 +126,11 @@ class WithSimNetwork extends OverrideHarnessBinder({
}) })
class WithSimAXIMem extends OverrideHarnessBinder({ class WithSimAXIMem extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) => (ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p))
withClockAndReset(port.clock, th.harnessReset) { withClockAndReset(port.clock, port.reset) {
Module(mem.module).suggestName("mem") Module(mem.module).suggestName("mem")
} }
mem.io_axi4.head <> port.bits mem.io_axi4.head <> port.bits
@@ -139,7 +140,7 @@ class WithSimAXIMem extends OverrideHarnessBinder({
}) })
class WithBlackBoxSimMem extends OverrideHarnessBinder({ class WithBlackBoxSimMem extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) => (ports zip system.memAXI4Node.edges.in).map { case (port, edge) =>
val memSize = p(ExtMem).get.master.size val memSize = p(ExtMem).get.master.size
@@ -147,18 +148,18 @@ class WithBlackBoxSimMem extends OverrideHarnessBinder({
val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)).suggestName("simdram") val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)).suggestName("simdram")
mem.io.axi <> port.bits mem.io.axi <> port.bits
mem.io.clock := port.clock mem.io.clock := port.clock
mem.io.reset := th.harnessReset mem.io.reset := port.reset
} }
Nil Nil
} }
}) })
class WithSimAXIMMIO extends OverrideHarnessBinder({ class WithSimAXIMMIO extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val p: Parameters = chipyard.iobinders.GetSystemParameters(system)
(ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) => (ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) =>
val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p)) val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p))
withClockAndReset(port.clock, th.harnessReset) { withClockAndReset(port.clock, port.reset) {
Module(mmio_mem.module).suggestName("mmio_mem") Module(mmio_mem.module).suggestName("mmio_mem")
} }
mmio_mem.io_axi4.head <> port.bits mmio_mem.io_axi4.head <> port.bits
@@ -168,26 +169,27 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({
}) })
class WithTieOffInterrupts extends OverrideHarnessBinder({ class WithTieOffInterrupts extends OverrideHarnessBinder({
(system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => { (system: HasExtInterruptsModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UInt]) => {
ports.foreach { _ := 0.U } ports.foreach { _ := 0.U }
Nil Nil
} }
}) })
class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ class WithTieOffL2FBusAXI extends OverrideHarnessBinder({
(system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { (system: CanHaveSlaveAXI4Port, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => {
ports.foreach({ p => p := DontCare; p.bits.tieoff() }) ports.foreach({ p => p := DontCare; p.bits.tieoff() })
Nil Nil
} }
}) })
class WithSimDebug extends OverrideHarnessBinder({ class WithSimDebug extends OverrideHarnessBinder({
(system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => {
implicit val p: Parameters = GetSystemParameters(system)
ports.map { ports.map {
case d: ClockedDMIIO => case d: ClockedDMIIO =>
val dtm_success = WireInit(false.B) val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B } when (dtm_success) { th.success := true.B }
val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) val dtm = Module(new SimDTM).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success)
case j: JTAGIO => case j: JTAGIO =>
val dtm_success = WireInit(false.B) val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B } when (dtm_success) { th.success := true.B }
@@ -198,7 +200,7 @@ class WithSimDebug extends OverrideHarnessBinder({
}) })
class WithTiedOffDebug extends OverrideHarnessBinder({ class WithTiedOffDebug extends OverrideHarnessBinder({
(system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { (system: HasPeripheryDebug, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => {
ports.map { ports.map {
case j: JTAGIO => case j: JTAGIO =>
j.TCK := true.B.asClock j.TCK := true.B.asClock
@@ -224,7 +226,7 @@ class WithTiedOffDebug extends OverrideHarnessBinder({
class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system) implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port => ports.map({ port =>
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
@@ -234,7 +236,7 @@ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({
}) })
class WithSimSerial extends OverrideHarnessBinder({ class WithSimSerial extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { (system: CanHavePeripheryTLSerial, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system) implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port => ports.map({ port =>
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
@@ -245,14 +247,14 @@ class WithSimSerial extends OverrideHarnessBinder({
}) })
class WithTraceGenSuccess extends OverrideHarnessBinder({ class WithTraceGenSuccess extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { (system: TraceGenSystemModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Bool]) => {
ports.map { p => when (p) { th.success := true.B } } ports.map { p => when (p) { th.success := true.B } }
Nil Nil
} }
}) })
class WithSimDromajoBridge extends ComposeHarnessBinder({ class WithSimDromajoBridge extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { (system: CanHaveTraceIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => {
ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) }
Nil Nil
} }

View File

@@ -1,17 +1,17 @@
package chipyard.iobinders package chipyard.iobinders
import chisel3._ import chisel3._
import chisel3.util.experimental.{BoringUtils}
import chisel3.experimental.{Analog, IO, DataMirror} import chisel3.experimental.{Analog, IO, DataMirror}
import freechips.rocketchip.config._ import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} import freechips.rocketchip.diplomacy._
import freechips.rocketchip.devices.debug._ import freechips.rocketchip.devices.debug._
import freechips.rocketchip.jtag.{JTAGIO} import freechips.rocketchip.jtag.{JTAGIO}
import freechips.rocketchip.subsystem._ 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.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem} import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem}
import sifive.blocks.devices.gpio._ import sifive.blocks.devices.gpio._
@@ -28,6 +28,12 @@ import chipyard.GlobalResetSchemeKey
import scala.reflect.{ClassTag} import scala.reflect.{ClassTag}
object IOBinderTypes {
type IOBinderTuple = (Seq[Data], Seq[IOCell])
type IOBinderFunction = (Boolean, => Any) => ModuleValue[IOBinderTuple]
}
import IOBinderTypes._
// System for instantiating binders based // System for instantiating binders based
// on the scala type of the Target (_not_ its IO). This avoids needing to // on the scala type of the Target (_not_ its IO). This avoids needing to
// duplicate harnesses (essentially test harnesses) for each target. // duplicate harnesses (essentially test harnesses) for each target.
@@ -40,21 +46,30 @@ import scala.reflect.{ClassTag}
// You can add your own binder by adding a new (key, fn) pair, typically by using // You can add your own binder by adding a new (key, fn) pair, typically by using
// the OverrideIOBinder or ComposeIOBinder macros // the OverrideIOBinder or ComposeIOBinder macros
case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]]( case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]](
Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil)) Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil)
) )
object ApplyIOBinders {
def apply(sys: LazyModule, map: Map[String, (Any) => (Seq[Data], Seq[IOCell])]):
(Iterable[Data], Iterable[IOCell], Map[String, Seq[Data]]) = {
val lzy = map.map({ case (s,f) => s -> f(sys) })
val imp = map.map({ case (s,f) => s -> f(sys.module) })
val unzipped = (lzy.values ++ imp.values).unzip
val ports: Iterable[Data] = unzipped._1.flatten abstract trait HasIOBinders { this: LazyModule =>
val cells: Iterable[IOCell] = unzipped._2.flatten val lazySystem: LazyModule
val portMap: Map[String, Seq[Data]] = map.keys.map(k => k -> (lzy(k)._1 ++ imp(k)._1)).toMap private val iobinders = p(IOBinders)
(ports, cells, portMap) // Note: IOBinders cannot rely on the implicit clock/reset, as they may be called from the
} // context of a LazyRawModuleImp
private val lzy = iobinders.map({ case (s,fns) => s -> fns.map(f => f(true, lazySystem)) })
private val imp = iobinders.map({ case (s,fns) => s -> fns.map(f => f(false, lazySystem.module)) })
private lazy val lzyFlattened: Map[String, IOBinderTuple] = lzy.map({
case (s,ms) => s -> (ms.map(_._1).flatten, ms.map(_._2).flatten)
})
private lazy val impFlattened: Map[String, IOBinderTuple] = imp.map({
case (s,ms) => s -> (ms.map(_._1).flatten, ms.map(_._2).flatten)
})
// A publicly accessible list of IO cells (useful for a floorplanning tool, for example)
lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer
// A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports
lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap
} }
// Note: The parameters instance is accessible only through LazyModule // Note: The parameters instance is accessible only through LazyModule
@@ -72,52 +87,45 @@ object GetSystemParameters {
} }
} }
class IOBinder(f: (View, View, View) => PartialFunction[Any, Any]) extends Config(f) class IOBinder[T](composer: Seq[IOBinderFunction] => Seq[IOBinderFunction])(implicit tag: ClassTag[T]) extends Config((site, here, up) => {
case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> composer(up(IOBinders, site)(tag.runtimeClass.toString)))
// This macro overrides previous matches on some Top mixin. This is useful for
// binders which drive IO, since those typically cannot be composed
class OverrideIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => {
case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString ->
((t: Any) => {
t match {
case system: T =>
val (ports, cells) = fn(system)
(ports, cells)
case _ => (Nil, Nil)
}
})
)
}) })
// This macro composes with previous matches on some Top mixin. This is useful for class ConcreteIOBinder[T](composes: Boolean, fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends IOBinder[T](
// annotation-like binders, since those can typically be composed up => (if (composes) up else Nil) ++ Seq(((_, t) => { InModuleBody {
class ComposeIOBinder[T, S <: Data](fn: => (T) => (Seq[S], Seq[IOCell]))(implicit tag: ClassTag[T]) extends IOBinder((site, here, up) => { t match {
case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> case system: T => fn(system)
((t: Any) => { case _ => (Nil, Nil)
t match { }
case system: T => }}): IOBinderFunction)
val r = up(IOBinders, site)(tag.runtimeClass.toString)(system) )
val h = fn(system)
val ports = r._1 ++ h._1
val cells = r._2 ++ h._2
(ports, cells)
case _ => (Nil, Nil)
}
})
)
})
object BoreHelper { class LazyIOBinder[T](composes: Boolean, fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends IOBinder[T](
def apply(name: String, source: Clock): Clock = { up => (if (composes) up else Nil) ++ Seq(((isLazy, t) => {
val clock_io = IO(Output(Clock())).suggestName(name) val empty = new ModuleValue[IOBinderTuple] {
val clock_wire = Wire(Clock()).suggestName(s"chiptop_${name}") def getWrappedValue: IOBinderTuple = (Nil, Nil)
dontTouch(clock_wire) }
clock_wire := false.B.asClock // necessary for BoringUtils to work properly if (isLazy) {
BoringUtils.bore(source, Seq(clock_wire)) t match {
clock_io := clock_wire case system: T => fn(system)
clock_io case _ => empty
} }
} } else {
empty
}
}): IOBinderFunction)
)
// The "Override" binders override any previous IOBinders (lazy or concrete) defined on the same trait.
// The "Compose" binders do not override previously defined IOBinders on the same trait
// The default IOBinders evaluate only in the concrete "ModuleImp" phase of elaboration
// The "Lazy" IOBinders evaluate in the LazyModule phase, but can also generate hardware through InModuleBody
class OverrideIOBinder[T](fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends ConcreteIOBinder[T](false, fn)
class ComposeIOBinder[T](fn: T => IOBinderTuple)(implicit tag: ClassTag[T]) extends ConcreteIOBinder[T](true, fn)
class OverrideLazyIOBinder[T](fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends LazyIOBinder[T](false, fn)
class ComposeLazyIOBinder[T](fn: T => ModuleValue[IOBinderTuple])(implicit tag: ClassTag[T]) extends LazyIOBinder[T](true, fn)
case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams()) case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams())
@@ -194,55 +202,55 @@ class WithExtInterruptIOCells extends OverrideIOBinder({
}) })
class WithDebugIOCells extends OverrideIOBinder({ class WithDebugIOCells extends OverrideLazyIOBinder({
(system: HasPeripheryDebugModuleImp) => { (system: HasPeripheryDebug) => {
system.debug.map({ debug => implicit val p = GetSystemParameters(system)
val p = system.p val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere)
val tlbus = system.outer.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) val clockSinkNode = system.debugOpt.map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
val debug_clock = Wire(Clock()).suggestName("debug_clock") clockSinkNode.map(_ := tlbus.fixedClockNode)
val debug_reset = Wire(Reset()).suggestName("debug_reset") def clockBundle = clockSinkNode.get.in.head._1
debug_clock := false.B.asClock // must provide default assignment to avoid firrtl unassigned error
debug_reset := false.B // must provide default assignment to avoid firrtl unassigned error
BoringUtils.bore(tlbus.module.clock, Seq(debug_clock))
BoringUtils.bore(tlbus.module.reset, Seq(debug_reset))
// We never use the PSDIO, so tie it off on-chip
system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } InModuleBody { system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripheryDebugModuleImp => {
system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := debug_reset.asBool } } system.debug.map({ debug =>
system.debug.map { d => // We never use the PSDIO, so tie it off on-chip
// Tie off extTrigger system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
d.extTrigger.foreach { t => system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := clockBundle.reset.asBool } }
t.in.req := false.B system.debug.map { d =>
t.out.ack := t.out.req // Tie off extTrigger
d.extTrigger.foreach { t =>
t.in.req := false.B
t.out.ack := t.out.req
}
// Tie off disableDebug
d.disableDebug.foreach { d => d := false.B }
// Drive JTAG on-chip IOs
d.systemjtag.map { j =>
j.reset := clockBundle.reset
j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W)
j.version := p(JtagDTMKey).idcodeVersion.U(4.W)
}
} }
// Tie off disableDebug Debug.connectDebugClockAndReset(Some(debug), clockBundle.clock)
d.disableDebug.foreach { d => d := false.B }
// Drive JTAG on-chip IOs // Add IOCells for the DMI/JTAG/APB ports
d.systemjtag.map { j => val dmiTuple = debug.clockeddmi.map { d =>
j.reset := debug_reset IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
j.mfr_id := system.p(JtagDTMKey).idcodeManufId.U(11.W)
j.part_number := system.p(JtagDTMKey).idcodePartNum.U(16.W)
j.version := system.p(JtagDTMKey).idcodeVersion.U(4.W)
} }
}
Debug.connectDebugClockAndReset(Some(debug), debug_clock)(system.p)
// Add IOCells for the DMI/JTAG/APB ports val jtagTuple = debug.systemjtag.map { j =>
val dmiTuple = debug.clockeddmi.map { d => IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) }
}
val jtagTuple = debug.systemjtag.map { j => val apbTuple = debug.apb.map { a =>
IOCell.generateIOFromSignal(j.jtag, "jtag", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync)
} }
val apbTuple = debug.apb.map { a => val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq
IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq)
} }).getOrElse((Nil, Nil))
}}}
val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq
(allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq)
}).getOrElse((Nil, Nil))
} }
}) })
@@ -255,39 +263,62 @@ class WithSerialTLIOCells extends OverrideIOBinder({
}) })
class WithAXI4MemPunchthrough extends OverrideIOBinder({ class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
(system: CanHaveMasterAXI4MemPort) => { (system: CanHaveMasterAXI4MemPort) => {
val ports: Seq[ClockedIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) => implicit val p: Parameters = GetSystemParameters(system)
val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}") val clockSinkNode = p(ExtMem).map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
p.bits <> m clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode)
p.clock := BoreHelper("axi4_mem_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) def clockBundle = clockSinkNode.get.in.head._1
p
}) InModuleBody {
(ports, Nil) val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}")
p.bits <> m
p.clock := clockBundle.clock
p.reset := clockBundle.reset
p
})
(ports, Nil)
}
} }
}) })
class WithAXI4MMIOPunchthrough extends OverrideIOBinder({ class WithAXI4MMIOPunchthrough extends OverrideLazyIOBinder({
(system: CanHaveMasterAXI4MMIOPort) => { (system: CanHaveMasterAXI4MMIOPort) => {
val ports: Seq[ClockedIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) => implicit val p: Parameters = GetSystemParameters(system)
val p = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}") val clockSinkNode = p(ExtBus).map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
p.bits <> m clockSinkNode.map(_ := system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(MBUS).fixedClockNode)
p.clock := BoreHelper("axi4_mmio_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock) def clockBundle = clockSinkNode.get.in.head._1
p
}) InModuleBody {
(ports, Nil) val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}")
p.bits <> m
p.clock := clockBundle.clock
p.reset := clockBundle.reset
p
})
(ports, Nil)
}
} }
}) })
class WithL2FBusAXI4Punchthrough extends OverrideIOBinder({ class WithL2FBusAXI4Punchthrough extends OverrideLazyIOBinder({
(system: CanHaveSlaveAXI4Port) => { (system: CanHaveSlaveAXI4Port) => {
val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) => implicit val p: Parameters = GetSystemParameters(system)
val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}") val clockSinkNode = p(ExtIn).map(_ => ClockSinkNode(Seq(ClockSinkParameters())))
m <> p.bits clockSinkNode.map(_ := system.asInstanceOf[BaseSubsystem].fbus.fixedClockNode)
p.clock := BoreHelper("axi4_fbus_clock", system.asInstanceOf[BaseSubsystem].fbus.module.clock) def clockBundle = clockSinkNode.get.in.head._1
p
}) InModuleBody {
(ports, Nil) val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}")
m <> p.bits
p.clock := clockBundle.clock
p
})
(ports, Nil)
}
} }
}) })

View File

@@ -6,6 +6,7 @@ import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.config.{Field, Parameters}
import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasIOBinders
// ------------------------------- // -------------------------------
// Chipyard Test Harness // Chipyard Test Harness
@@ -14,9 +15,7 @@ import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
trait HasTestHarnessFunctions { trait HasTestHarnessFunctions {
val lazySystem: LazyModule
val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]] val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]]
val portMap = scala.collection.mutable.Map[String, Seq[Data]]()
} }
trait HasHarnessSignalReferences { trait HasHarnessSignalReferences {
@@ -44,7 +43,9 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign
lazyDut match { case d: HasTestHarnessFunctions => lazyDut match { case d: HasTestHarnessFunctions =>
d.harnessFunctions.foreach(_(this)) d.harnessFunctions.foreach(_(this))
ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) }
lazyDut match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
} }
} }

View File

@@ -62,6 +62,10 @@ case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValN
* fast reference clock (roughly LCM(requested frequencies)) which is passed up the * fast reference clock (roughly LCM(requested frequencies)) which is passed up the
* diplomatic graph, and then generates dividers for each unique requested * diplomatic graph, and then generates dividers for each unique requested
* frequency. * frequency.
*
* Output resets are not synchronized to generated clocks and should be
* synchronized by the user in a manner they see fit.
*
*/ */
class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName: ValName) extends LazyModule { class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName: ValName) extends LazyModule {
@@ -87,6 +91,7 @@ class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName
for (((sinkBName, sinkB), sinkP) <- outClocks.member.elements.zip(outSinkParams.members)) { for (((sinkBName, sinkB), sinkP) <- outClocks.member.elements.zip(outSinkParams.members)) {
val div = pllConfig.sinkDividerMap(sinkP) val div = pllConfig.sinkDividerMap(sinkP)
sinkB.clock := dividedClocks.getOrElse(div, instantiateDivider(div)) sinkB.clock := dividedClocks.getOrElse(div, instantiateDivider(div))
// Reset handling and synchronization is expected to be handled by a downstream node
sinkB.reset := refClock.reset sinkB.reset := refClock.reset
} }
} }

View File

@@ -0,0 +1,30 @@
package chipyard.clocking
import chisel3._
import freechips.rocketchip.config.{Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.util.{ResetCatchAndSync}
/**
* Instantiates a reset synchronizer on all clock-reset pairs in a clock group
*/
class ClockGroupResetSynchronizer(implicit p: Parameters) extends LazyModule {
val node = ClockGroupIdentityNode()
lazy val module = new LazyRawModuleImp(this) {
(node.out zip node.in).map { case ((oG, _), (iG, _)) =>
(oG.member.data zip iG.member.data).foreach { case (o, i) =>
o.clock := i.clock
o.reset := ResetCatchAndSync(i.clock, i.reset.asBool)
}
}
}
}
object ClockGroupResetSynchronizer {
def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new ClockGroupResetSynchronizer()).node
}

View File

@@ -49,6 +49,6 @@ class AbstractConfig extends Config(
new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip)
new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache
new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts
new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ // hierarchical buses including mbus+l2 new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2
new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system

View File

@@ -179,6 +179,9 @@ class DividedClockRocketConfig extends Config(
new chipyard.config.WithTileFrequency(200.0) ++ new chipyard.config.WithTileFrequency(200.0) ++
new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++
new chipyard.config.WithMemoryBusFrequency(50.0) ++
new chipyard.config.WithAsynchrousMemoryBusCrossing ++
new testchipip.WithAsynchronousSerialSlaveCrossing ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
class LBWIFRocketConfig extends Config( class LBWIFRocketConfig extends Config(

View File

@@ -9,7 +9,7 @@ class Sodor1StageConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage1Factory) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage1Factory) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
@@ -18,7 +18,7 @@ class Sodor2StageConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage2Factory) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage2Factory) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
@@ -27,7 +27,7 @@ class Sodor3StageConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 2)) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 2)) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
@@ -36,7 +36,7 @@ class Sodor3StageSinglePortConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 1)) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage3Factory(ports = 1)) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
@@ -45,7 +45,7 @@ class Sodor5StageConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage5Factory) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.Stage5Factory) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)
@@ -54,6 +54,6 @@ class SodorUCodeConfig extends Config(
new sodor.common.WithNSodorCores(1, internalTile = sodor.common.UCodeFactory) ++ new sodor.common.WithNSodorCores(1, internalTile = sodor.common.UCodeFactory) ++
new testchipip.WithSerialPBusMem ++ new testchipip.WithSerialPBusMem ++
new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad new freechips.rocketchip.subsystem.WithScratchpadsOnly ++ // use sodor tile-internal scratchpad
new freechips.rocketchip.subsystem.WithNMemoryChannels(0) ++ // use no external memory new freechips.rocketchip.subsystem.WithNoMemPort ++ // use no external memory
new freechips.rocketchip.subsystem.WithNBanks(0) ++ new freechips.rocketchip.subsystem.WithNBanks(0) ++
new chipyard.config.AbstractConfig) new chipyard.config.AbstractConfig)

View File

@@ -12,10 +12,11 @@ private[stage] object UnderscoreDelimitedConfigsAnnotation extends HasShellOptio
new ShellOption[String]( new ShellOption[String](
longOption = "legacy-configs", longOption = "legacy-configs",
toAnnotationSeq = a => { toAnnotationSeq = a => {
val split = a.split('.') val split = a.split(':')
val packageName = split.init.mkString(".") assert(split.length == 2)
val packageName = split.head
val configs = split.last.split("_") val configs = split.last.split("_")
Seq(new ConfigsAnnotation(configs map { config => s"${packageName}.${config}" } )) Seq(new ConfigsAnnotation(configs map { config => if (config contains ".") s"${config}" else s"${packageName}.${config}" } ))
}, },
helpText = "A string of underscore-delimited configs (configs have decreasing precendence from left to right).", helpText = "A string of underscore-delimited configs (configs have decreasing precendence from left to right).",
shortOption = Some("LC") shortOption = Some("LC")

View File

@@ -18,7 +18,7 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon
import junctions.{NastiKey, NastiParameters} import junctions.{NastiKey, NastiParameters}
import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig} import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig}
import midas.targetutils.{FAMEModelAnnotation, MemModelAnnotation, EnableModelMultiThreadingAnnotation} import midas.targetutils.{MemModelAnnotation, EnableModelMultiThreadingAnnotation}
import firesim.bridges._ import firesim.bridges._
import firesim.configs.MemModelKey import firesim.configs.MemModelKey
import tracegen.{TraceGenSystemModuleImp} import tracegen.{TraceGenSystemModuleImp}
@@ -66,7 +66,7 @@ class WithFireSimIOCellModels extends Config((site, here, up) => {
}) })
class WithSerialBridge extends OverrideHarnessBinder({ class WithSerialBridge extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => {
ports.map { port => ports.map { port =>
implicit val p = GetSystemParameters(system) implicit val p = GetSystemParameters(system)
val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset) val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, port, th.harnessReset)
@@ -77,7 +77,7 @@ class WithSerialBridge extends OverrideHarnessBinder({
}) })
class WithNICBridge extends OverrideHarnessBinder({ class WithNICBridge extends OverrideHarnessBinder({
(system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { (system: CanHavePeripheryIceNIC, th: FireSim, ports: Seq[ClockedIO[NICIOvonly]]) => {
val p: Parameters = GetSystemParameters(system) val p: Parameters = GetSystemParameters(system)
ports.map { n => NICBridge(n.clock, n.bits)(p) } ports.map { n => NICBridge(n.clock, n.bits)(p) }
Nil Nil
@@ -85,12 +85,12 @@ class WithNICBridge extends OverrideHarnessBinder({
}) })
class WithUARTBridge extends OverrideHarnessBinder({ class WithUARTBridge extends OverrideHarnessBinder({
(system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => (system: HasPeripheryUARTModuleImp, th: FireSim, ports: Seq[UARTPortIO]) =>
ports.map { p => UARTBridge(th.harnessClock, p)(system.p) }; Nil ports.map { p => UARTBridge(th.harnessClock, p)(system.p) }; Nil
}) })
class WithBlockDeviceBridge extends OverrideHarnessBinder({ class WithBlockDeviceBridge extends OverrideHarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { (system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.toBool) } ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.toBool) }
Nil Nil
@@ -98,14 +98,14 @@ class WithBlockDeviceBridge extends OverrideHarnessBinder({
}) })
class WithFASEDBridge extends OverrideHarnessBinder({ class WithFASEDBridge extends OverrideHarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { (system: CanHaveMasterAXI4MemPort, th: FireSim, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => {
implicit val p: Parameters = GetSystemParameters(system) implicit val p: Parameters = GetSystemParameters(system)
(ports zip system.memAXI4Node.edges.in).map { case (axi4, edge) => (ports zip system.memAXI4Node.edges.in).map { case (axi4, edge) =>
val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth, val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth,
axi4.bits.ar.bits.addr.getWidth, axi4.bits.ar.bits.addr.getWidth,
axi4.bits.ar.bits.id.getWidth) axi4.bits.ar.bits.id.getWidth)
system match { system match {
case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, th.harnessReset.asBool, case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, axi4.reset.asBool,
CompleteConfig(p(firesim.configs.MemModelKey), CompleteConfig(p(firesim.configs.MemModelKey),
nastiKey, nastiKey,
Some(AXI4EdgeSummary(edge)), Some(AXI4EdgeSummary(edge)),
@@ -118,20 +118,20 @@ class WithFASEDBridge extends OverrideHarnessBinder({
}) })
class WithTracerVBridge extends ComposeHarnessBinder({ class WithTracerVBridge extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { (system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) => {
ports.map { p => p.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p)) } ports.map { p => p.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p)) }
Nil Nil
} }
}) })
class WithDromajoBridge extends ComposeHarnessBinder({ class WithDromajoBridge extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => (system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) =>
ports.map { p => p.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p)) }; Nil ports.map { p => p.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p)) }; Nil
}) })
class WithTraceGenBridge extends OverrideHarnessBinder({ class WithTraceGenBridge extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => (system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) =>
ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil
}) })
@@ -161,10 +161,8 @@ class WithFireSimFAME5 extends ComposeIOBinder({
(system: HasTilesModuleImp) => { (system: HasTilesModuleImp) => {
system.outer.tiles.map { system.outer.tiles.map {
case b: BoomTile => case b: BoomTile =>
annotate(FAMEModelAnnotation(b.module))
annotate(EnableModelMultiThreadingAnnotation(b.module)) annotate(EnableModelMultiThreadingAnnotation(b.module))
case r: RocketTile => case r: RocketTile =>
annotate(FAMEModelAnnotation(r.module))
annotate(EnableModelMultiThreadingAnnotation(r.module)) annotate(EnableModelMultiThreadingAnnotation(r.module))
} }
(Nil, Nil) (Nil, Nil)

View File

@@ -16,7 +16,7 @@ import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock
import chipyard._ import chipyard._
import chipyard.harness._ import chipyard.harness._
import chipyard.iobinders._ import chipyard.iobinders._
import chipyard.clocking.{FrequencyUtils, ClockGroupNamePrefixer, ClockGroupFrequencySpecifier, SimplePllConfiguration} import chipyard.clocking._
// Determines the number of times to instantiate the DUT in the harness. // Determines the number of times to instantiate the DUT in the harness.
// Subsumes legacy supernode support // Subsumes legacy supernode support
@@ -96,11 +96,12 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => {
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
(chiptop.implicitClockSinkNode := ClockGroup() := aggregator) (chiptop.implicitClockSinkNode := ClockGroup() := aggregator)
(systemAsyncClockGroup := ClockGroupNamePrefixer() := aggregator) (systemAsyncClockGroup :*= ClockGroupNamePrefixer() :*= aggregator)
val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters()))
(aggregator (aggregator
:= ClockGroupResetSynchronizer()
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) := ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey))
:= inputClockSource) := inputClockSource)
@@ -113,15 +114,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => {
(clockGroupBundle.member.data zip input_clocks.data).foreach { case (clockBundle, inputClock) => (clockGroupBundle.member.data zip input_clocks.data).foreach { case (clockBundle, inputClock) =>
clockBundle.clock := inputClock clockBundle.clock := inputClock
} clockBundle.reset := reset
// Assign resets. The synchronization scheme is still WIP.
for ((name, clockBundle) <- clockGroupBundle.member.elements) {
if (name.contains("core")) {
clockBundle.reset := ResetCatchAndSync(clockBundle.clock, reset.asBool)
} else {
clockBundle.reset := reset
}
} }
val pllConfig = new SimplePllConfiguration("FireSim RationalClockBridge", clockGroupEdge.sink.members) val pllConfig = new SimplePllConfiguration("FireSim RationalClockBridge", clockGroupEdge.sink.members)
@@ -160,7 +153,9 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna
lazyModule match { case d: HasTestHarnessFunctions => lazyModule match { case d: HasTestHarnessFunctions =>
require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset") require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset")
d.harnessFunctions.foreach(_(this)) d.harnessFunctions.foreach(_(this))
ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) }
lazyModule match { case d: HasIOBinders =>
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
} }
NodeIdx.increment() NodeIdx.increment()
} }

View File

@@ -37,10 +37,6 @@ class WithBootROM extends Config((site, here, up) => {
} }
}) })
class WithPeripheryBusFrequency(freq: BigInt) extends Config((site, here, up) => {
case PeripheryBusKey => up(PeripheryBusKey).copy(dtsFrequency = Some(freq))
})
// 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))
@@ -66,13 +62,23 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small")
// Tweaks that are generally applied to all firesim configs // Tweaks that are generally applied to all firesim configs
class WithFireSimConfigTweaks extends Config( class WithFireSimConfigTweaks extends Config(
// Required: Bake in the default FASED memory model
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 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 ++
// Optional*: Removing this will require adjusting the UART baud rate and // Optional*: Removing this will require adjusting the UART baud rate and
// potential target-software changes to properly capture UART output // potential target-software changes to properly capture UART output
new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ new chipyard.config.WithPeripheryBusFrequency(3200.0) ++
// Optional: These three configs put the DRAM memory system in it's own clock domian.
// Removing the first config will result in the FASED timing model running
// at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades.
// 1 GHz matches the FASED default, using some other frequency will require
// runnings the FASED runtime configuration generator to generate faithful DDR3 timing values.
new chipyard.config.WithMemoryBusFrequency(1000.0) ++
new chipyard.config.WithAsynchrousMemoryBusCrossing ++
new testchipip.WithAsynchronousSerialSlaveCrossing ++
// Required: Existing FAME-1 transform cannot handle black-box clock gates // Required: Existing FAME-1 transform cannot handle black-box clock gates
new WithoutClockGating ++ new WithoutClockGating ++
// Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix) // Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix)
@@ -127,7 +133,7 @@ class FireSimSmallSystemConfig extends Config(
new WithDefaultFireSimBridges ++ new WithDefaultFireSimBridges ++
new WithDefaultMemModel ++ new WithDefaultMemModel ++
new WithBootROM ++ new WithBootROM ++
new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ new chipyard.config.WithPeripheryBusFrequency(3200.0) ++
new WithoutClockGating ++ new WithoutClockGating ++
new WithoutTLMonitors ++ new WithoutTLMonitors ++
new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++ new freechips.rocketchip.subsystem.WithExtMemSize(1 << 28) ++

View File

@@ -8,7 +8,7 @@ binary=$1
segments=`readelf --segments --wide $binary` segments=`readelf --segments --wide $binary`
entry_hex=`echo -e "$segments" | grep "Entry point" | cut -f3 -d' ' | sed 's/0x//' | tr [:lower:] [:upper:]` entry_hex=`echo -e "$segments" | grep "Entry point" | cut -f3 -d' ' | sed 's/0x//' | tr [:lower:] [:upper:]`
entry_dec=`bc <<< "ibase=16;$entry_hex"` entry_dec=`bc <<< "ibase=16;$entry_hex"`
length_hex=`echo "$segments" | grep "LOAD\|TLS" | tail -n 1 | tr -s [:space:] | cut -f4,6 -d' '` length_hex=`echo "$segments" | grep "LOAD\|TLS" | tail -n 1 | tr -s [:space:] | cut -f4,7 -d' '`
length_dec=`echo $length_hex | tr -d x | tr [:lower:] [:upper:] | tr ' ' + | sed 's/^/ibase=16;/' | sed "s/$/-$entry_hex/" | bc` length_dec=`echo $length_hex | tr -d x | tr [:lower:] [:upper:] | tr ' ' + | sed 's/^/ibase=16;/' | sed "s/$/-$entry_hex/" | bc`
power_2_length=`echo "x=l($length_dec)/l(2); scale=0; 2^((x+1)/1)" | bc -l` power_2_length=`echo "x=l($length_dec)/l(2); scale=0; 2^((x+1)/1)" | bc -l`
width=64 width=64