diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 1e234144..8dd0020e 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -25,7 +25,6 @@ import barstools.iocell.chisel._ import testchipip._ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} import chipyard.{CanHaveMasterTLMemPort} -import chipyard.clocking.{HasChipyardPRCI, DividerOnlyClockGenerator} import scala.reflect.{ClassTag} diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index 5a02277c..c91f5cb4 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -13,53 +13,11 @@ class ClockWithFreq(val freqMHz: Double) extends Bundle { val clock = Clock() } -// This uses synthesizable clock divisors to approximate frequency rations -// between the requested clocks. This is currently the defualt clock generator "model", -// as it can be used in VCS/Xcelium/Verilator/FireSim -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) - } - } -}) - // This uses the FakePLL, which uses a ClockAtFreq Verilog blackbox to generate // the requested clocks. This also adds TileLink ClockDivider and ClockSelector // blocks, which allow memory-mapped control of clock division, and clock muxing // between the FakePLL and the slow off-chip clock -// Note: This will not simulate properly with verilator or firesim +// Note: This will not simulate properly with firesim class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ (system: HasChipyardPRCI) => { // Connect the implicit clock @@ -100,7 +58,7 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ pllCtrlSink := pllCtrl.ctrlNode InModuleBody { - val clock_wire = Wire(Input(new ClockWithFreq(80))) + val clock_wire = Wire(Input(new ClockWithFreq(100))) 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)) @@ -125,3 +83,41 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ } } }) + +// This passes all clocks through to the TestHarness +class WithPassthroughClockGenerator 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 + }} + } + + // This aggregate node should do nothing + val clockGroupAggNode = ClockGroupAggregateNode("fake") + val clockGroupsSourceNode = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) + system.allClockGroupsNode :*= clockGroupAggNode := clockGroupsSourceNode + + InModuleBody { + val reset_io = IO(Input(AsyncReset())) + val clock_ios = clockGroupAggNode.out.map { case (bundle, edge) => + val freqs = edge.sink.members.map(_.take.map(_.freqMHz)).flatten + require(freqs.distinct.size == 1) + val clock_io = IO(Input(new ClockWithFreq(freqs.head))).suggestName(s"clock_${edge.sink.name}") + bundle.member.data.foreach { b => + b.clock := clock_io.clock + b.reset := reset_io + } + clock_io + } + ((clock_ios :+ reset_io), Nil) + } + } +}) diff --git a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala index 121cca24..0458c621 100644 --- a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala +++ b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala @@ -92,57 +92,3 @@ class SimplePllConfiguration( def referenceSinkParams(): ClockSinkParameters = sinkDividerMap.find(_._2 == 1).get._1 } -case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValName) - extends MixedNexusNode(ClockImp, ClockGroupImp)( - dFn = { _ => ClockGroupSourceParameters() }, - uFn = { u => - require(u.size == 1) - require(!u.head.members.contains(None), - "All output clocks in group must set their take parameters. Use a ClockGroupDealiaser") - ClockSinkParameters( - name = Some(s"${pllName}_reference_input"), - take = Some(ClockParameters(new SimplePllConfiguration(pllName, u.head.members).referenceFreqMHz))) } - ) - -/** - * Generates a digital-divider-only PLL model that verilator can simulate. - * Inspects all take-specified frequencies in the output ClockGroup, calculates a - * fast reference clock (roughly LCM(requested frequencies)) which is passed up the - * diplomatic graph, and then generates dividers for each unique requested - * 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 { - val node = DividerOnlyClockGeneratorNode(pllName) - - lazy val module = new Impl - class Impl extends LazyRawModuleImp(this) { - require(node.out.size == 1, "Idealized PLL expects to generate a single output clock group. Use a ClockGroupAggregator") - val (refClock, ClockEdgeParameters(_, refSinkParam, _, _)) = node.in.head - val (outClocks, ClockGroupEdgeParameters(_, outSinkParams, _, _)) = node.out.head - - val referenceFreq = refSinkParam.take.get.freqMHz - val pllConfig = new SimplePllConfiguration(pllName, outSinkParams.members) - pllConfig.emitSummaries() - - val dividedClocks = mutable.HashMap[Int, Clock]() - def instantiateDivider(div: Int): Clock = { - val divider = Module(new ClockDividerN(div)) - divider.suggestName(s"ClockDivideBy${div}") - divider.io.clk_in := refClock.clock - dividedClocks(div) = divider.io.clk_out - divider.io.clk_out - } - - for (((sinkBName, sinkB), sinkP) <- outClocks.member.elements.zip(outSinkParams.members)) { - val div = pllConfig.sinkDividerMap(sinkP) - sinkB.clock := dividedClocks.getOrElse(div, instantiateDivider(div)) - // Reset handling and synchronization is expected to be handled by a downstream node - sinkB.reset := refClock.reset - } - } -} diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index ceee4c0f..02ab9b5a 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -23,6 +23,7 @@ class AbstractConfig extends Config( new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present new chipyard.harness.WithCustomBootPinPlusArg ++ new chipyard.harness.WithClockAndResetFromHarness ++ + new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // 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 @@ -41,10 +42,8 @@ class AbstractConfig extends Config( new chipyard.iobinders.WithExtInterruptIOCells ++ new chipyard.iobinders.WithCustomBootPin ++ - // Default behavior is to use a divider-only clock-generator - // This works in VCS, Verilator, and FireSim/ - // This should get replaced with a PLL-like config instead - new chipyard.clocking.WithDividerOnlyClockGenerator ++ + // By default, punch out IOs to the Harness + new chipyard.clocking.WithPassthroughClockGenerator ++ new testchipip.WithCustomBootPin ++ // add a custom-boot-pin to support pin-driven boot address new testchipip.WithBootAddrReg ++ // add a boot-addr-reg for configurable boot address diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index b92b2f46..3c2b9a0c 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -4,12 +4,13 @@ import org.chipsalliance.cde.config.{Config} import freechips.rocketchip.rocket.{DCacheParams} class AbstractTraceGenConfig extends Config( + new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ new chipyard.harness.WithBlackBoxSimMem ++ new chipyard.harness.WithTraceGenSuccess ++ new chipyard.harness.WithClockAndResetFromHarness ++ new chipyard.iobinders.WithAXI4MemPunchthrough ++ new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ - new chipyard.clocking.WithDividerOnlyClockGenerator ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ diff --git a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala index 513ca38c..22c7417e 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala @@ -36,44 +36,6 @@ trait HarnessClockInstantiator { def instantiateHarnessClocks(refClock: ClockBundle): Unit } -// The DividerOnlyHarnessClockInstantiator uses synthesizable clock divisors -// to approximate frequency ratios between the requested clocks -class DividerOnlyHarnessClockInstantiator extends HarnessClockInstantiator { - // connect all clock wires specified to a divider only PLL - def instantiateHarnessClocks(refClock: ClockBundle): Unit = { - val sinks = _clockMap.map({ case (name, (freq, bundle)) => - ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name)) - }).toSeq - - val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks) - pllConfig.emitSummaries() - - val dividedClocks = LinkedHashMap[Int, Clock]() - def instantiateDivider(div: Int): Clock = { - val divider = Module(new ClockDividerN(div)) - divider.suggestName(s"ClockDivideBy${div}") - divider.io.clk_in := refClock.clock - dividedClocks(div) = divider.io.clk_out - divider.io.clk_out - } - - // connect wires to clock source - for (sinkParams <- sinks) { - // bypass the reference freq. (don't create a divider + reset sync) - val (divClock, divReset) = if (sinkParams.take.get.freqMHz != pllConfig.referenceFreqMHz) { - val div = pllConfig.sinkDividerMap(sinkParams) - val divClock = dividedClocks.getOrElse(div, instantiateDivider(div)) - (divClock, ResetCatchAndSync(divClock, refClock.reset.asBool)) - } else { - (refClock.clock, refClock.reset) - } - - _clockMap(sinkParams.name.get)._2.clock := divClock - _clockMap(sinkParams.name.get)._2.reset := divReset - } - } -} - // The AbsoluteFreqHarnessClockInstantiator uses a Verilog blackbox to // provide the precise requested frequency. // This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim diff --git a/generators/chipyard/src/main/scala/harness/TestHarness.scala b/generators/chipyard/src/main/scala/harness/TestHarness.scala index 22bcc167..cb8cfe47 100644 --- a/generators/chipyard/src/main/scala/harness/TestHarness.scala +++ b/generators/chipyard/src/main/scala/harness/TestHarness.scala @@ -19,7 +19,7 @@ import chipyard.{ChipTop} case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz -case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator](() => new DividerOnlyHarnessClockInstantiator) +case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]() trait HasHarnessSignalReferences { implicit val p: Parameters