141 lines
5.4 KiB
Scala
141 lines
5.4 KiB
Scala
package chipyard
|
|
|
|
import chisel3._
|
|
|
|
import scala.collection.mutable.{ArrayBuffer}
|
|
|
|
import freechips.rocketchip.prci._
|
|
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey}
|
|
import freechips.rocketchip.config.{Parameters, Field, Config}
|
|
import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule}
|
|
import freechips.rocketchip.util.{ResetCatchAndSync, Pow2ClockDivider}
|
|
|
|
import barstools.iocell.chisel._
|
|
|
|
import chipyard.clocking.{IdealizedPLL, ClockGroupDealiaser, ClockGroupNamePrefixer, ClockGroupFrequencySpecifier}
|
|
|
|
/**
|
|
* Chipyard provides three baseline, top-level reset schemes, set using the
|
|
* [[GlobalResetSchemeKey]] in a Parameters instance. These are:
|
|
*
|
|
* 1) Synchronous: The input coming to the chip is synchronous to the provided
|
|
* clocks and will be used without modification as a synchronous reset.
|
|
* This is safe only for use in FireSim and SW simulation.
|
|
*
|
|
* 2) Asynchronous: The input reset is asynchronous to the input clock, but it
|
|
* is caught and synchronized to that clock before it is dissemenated.
|
|
* Thus, downsteam modules will be emitted with synchronously reset state
|
|
* elements.
|
|
*
|
|
* 3) Asynchronous Full: The input reset is asynchronous to the input clock,
|
|
* and is used globally as an async reset. Downstream modules will be emitted
|
|
* with asynchronously reset state elements.
|
|
*
|
|
*/
|
|
sealed trait GlobalResetScheme {
|
|
def pinIsAsync: Boolean
|
|
}
|
|
sealed trait HasAsyncInput { self: GlobalResetScheme =>
|
|
def pinIsAsync = true
|
|
}
|
|
|
|
sealed trait HasSyncInput { self: GlobalResetScheme =>
|
|
def pinIsAsync = false
|
|
}
|
|
|
|
case object GlobalResetSynchronous extends GlobalResetScheme with HasSyncInput
|
|
case object GlobalResetAsynchronous extends GlobalResetScheme with HasAsyncInput
|
|
case object GlobalResetAsynchronousFull extends GlobalResetScheme with HasAsyncInput
|
|
case object GlobalResetSchemeKey extends Field[GlobalResetScheme](GlobalResetSynchronous)
|
|
|
|
/**
|
|
* A simple reset implementation that punches out reset ports
|
|
* for standard Module classes. Three basic reset schemes
|
|
* are provided. See [[GlobalResetScheme]].
|
|
*/
|
|
object GenerateReset {
|
|
def apply(chiptop: ChipTop, clock: Clock): Reset = {
|
|
implicit val p = chiptop.p
|
|
// this needs directionality so generateIOFromSignal works
|
|
val reset_wire = Wire(Input(Reset()))
|
|
val (reset_io, resetIOCell) = p(GlobalResetSchemeKey) match {
|
|
case GlobalResetSynchronous =>
|
|
IOCell.generateIOFromSignal(reset_wire, Some("iocell_reset"))
|
|
case GlobalResetAsynchronousFull =>
|
|
IOCell.generateIOFromSignal(reset_wire, Some("iocell_reset"), abstractResetAsAsync = true)
|
|
case GlobalResetAsynchronous => {
|
|
val async_reset_wire = Wire(Input(AsyncReset()))
|
|
reset_wire := ResetCatchAndSync(clock, async_reset_wire.asBool())
|
|
IOCell.generateIOFromSignal(async_reset_wire, Some("iocell_reset"), abstractResetAsAsync = true)
|
|
}
|
|
}
|
|
reset_io.suggestName("reset")
|
|
chiptop.iocells ++= resetIOCell
|
|
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
|
reset_io := th.dutReset
|
|
Nil
|
|
})
|
|
reset_wire
|
|
}
|
|
}
|
|
|
|
|
|
case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGenerators.idealizedPLL)
|
|
/**
|
|
* This is a dictionary of clock name to clock frequency in MHz. Names
|
|
* correspond to the IO coming off digital top. If the map is undefined for the given name,
|
|
* it will return a default value -- DFU.
|
|
*/
|
|
case object ClockFrequencyAssignment extends Field[Seq[(String) => Option[Double]]](Seq.empty)
|
|
case object DefaultClockFrequencyKey extends Field[Double](100.0)
|
|
|
|
class ClockNameMatchesAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
|
case ClockFrequencyAssignment => up(ClockFrequencyAssignment, site) ++
|
|
Seq((cName: String) => if (cName == name) Some(fMHz) else None)
|
|
})
|
|
|
|
class ClockNameContainsAssignment(name: String, fMHz: Double) extends Config((site, here, up) => {
|
|
case ClockFrequencyAssignment => up(ClockFrequencyAssignment, site) ++
|
|
Seq((cName: String) => if (cName.contains(name)) Some(fMHz) else None)
|
|
})
|
|
|
|
object ClockingSchemeGenerators {
|
|
val idealizedPLL: ChipTop => Unit = { 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
|
|
}
|
|
|
|
val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node
|
|
chiptop.implicitClockSinkNode := ClockGroup() := aggregator
|
|
systemAsyncClockGroup := ClockGroupNamePrefixer() := aggregator
|
|
|
|
val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
|
|
(aggregator
|
|
:= ClockGroupFrequencySpecifier(p(ClockFrequencyAssignment), p(DefaultClockFrequencyKey))
|
|
:= IdealizedPLL()
|
|
:= referenceClockSource)
|
|
|
|
|
|
InModuleBody {
|
|
val clock_wire = Wire(Input(Clock()))
|
|
val reset_wire = GenerateReset(chiptop, clock_wire)
|
|
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, Some("iocell_clock"))
|
|
chiptop.iocells ++= clockIOCell
|
|
clock_io.suggestName("clock")
|
|
|
|
referenceClockSource.out.unzip._1.map { o =>
|
|
o.clock := clock_wire
|
|
o.reset := reset_wire
|
|
}
|
|
|
|
chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => {
|
|
clock_io := th.harnessClock
|
|
Nil })
|
|
}
|
|
}
|
|
}
|