diff --git a/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala b/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala index f1936d487c..bb261e250d 100644 --- a/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala +++ b/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala @@ -20,6 +20,7 @@ import testchipip.clocking.{ClockGroupFakeResetSynchronizer} case class ChipyardPRCIControlParams( slaveWhere: TLBusWrapperLocation = CBUS, baseAddress: BigInt = 0x100000, + resetPipeStages: Int = 0, enableTileClockGating: Boolean = true, enableTileResetSetting: Boolean = true, enableResetSynchronizers: Boolean = true // this should only be disabled to work around verilator async-reset initialization problems @@ -66,6 +67,7 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesHierarchicalElement // diplomatic IOBinder should drive val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey)) val clockGroupCombiner = ClockGroupCombiner() + val resetPipeline = prci_ctrl_domain { LazyModule(new ResetPipeline(prciParams.resetPipeStages)) } val resetSynchronizer = prci_ctrl_domain { if (prciParams.enableResetSynchronizers) ClockGroupResetSynchronizer() else ClockGroupFakeResetSynchronizer() } @@ -105,6 +107,7 @@ RTL SIMULATORS, NAMELY VERILATOR. (aggregator := frequencySpecifier + := resetPipeline.node := clockGroupCombiner := resetSynchronizer := tileClockGater.map(_.clockNode).getOrElse(ClockGroupEphemeralNode()(ValName("temp"))) diff --git a/generators/chipyard/src/main/scala/clocking/ResetPipeline.scala b/generators/chipyard/src/main/scala/clocking/ResetPipeline.scala new file mode 100644 index 0000000000..1933c428db --- /dev/null +++ b/generators/chipyard/src/main/scala/clocking/ResetPipeline.scala @@ -0,0 +1,34 @@ +package chipyard.clocking + +import chisel3._ +import chisel3.util._ +import org.chipsalliance.cde.config._ +import org.chipsalliance.diplomacy._ +import org.chipsalliance.diplomacy.lazymodule._ +import freechips.rocketchip.prci.{ClockGroupAdapterNode} + +/** This adapter takes input synchronous resets and stretch them via a reset pipeline + * This is useful for distributing a synchronous reset across the chip + */ +class ResetPipeline(stages: Int)(implicit p: Parameters) extends LazyModule { + val node = ClockGroupAdapterNode()(ValName(s"reset_pipeline_$stages")) + override lazy val desiredName = s"ResetPipeline$stages" + lazy val module = new Impl + class Impl extends LazyRawModuleImp(this) { + (node.in zip node.out).foreach { case ((iG, _), (oG, _)) => + (oG.member.data zip iG.member.data).foreach { case (out, in) => + out.clock := in.clock + withClock (in.clock) { + if (stages == 0) { + out.reset := in.reset + } else { + val regs = Seq.fill(stages)(Reg(Bool())) + regs.head := in.reset + out.reset := regs.last + (regs.init zip regs.tail).foreach(t => t._2 := t._1) + } + } + } + } + } +} diff --git a/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala b/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala index 83a42146ae..f98a3f5dcd 100644 --- a/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala +++ b/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala @@ -133,3 +133,11 @@ class WithNoResetSynchronizers extends Config((site, here, up) => { class WithNoClockTap extends Config((site, here, up) => { case ClockTapKey => false }) + +// Adds a reset pipeline after the ResetSynchronizer in chipyard's clock/reset path +// This assists with PD and timing of sync reset +// NOTE: This will likely result in spurious early assertions when reset-assertion +// is propagating through the pipeline. You may ignore these in RTL simulators +class WithSyncResetPipeStages(stages: Int) extends Config((site, here, up) => { + case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey).copy(resetPipeStages = stages) +})