diff --git a/.github/scripts/defaults.sh b/.github/scripts/defaults.sh index 176d20d5b7..d2362dbd17 100755 --- a/.github/scripts/defaults.sh +++ b/.github/scripts/defaults.sh @@ -47,7 +47,7 @@ mapping["chipyard-manymmioaccels"]=" CONFIG=ManyMMIOAcceleratorRocketConfig" mapping["chipyard-hetero"]=" CONFIG=LargeBoomAndRocketConfig" mapping["chipyard-boom"]=" CONFIG=MediumBoomCosimConfig" mapping["chipyard-dmiboom"]=" CONFIG=dmiMediumBoomCosimConfig" -mapping["chipyard-spike"]=" CONFIG=SpikeFastUARTConfig EXTRA_SIM_FLAGS='+spike-ipc=10'" +mapping["chipyard-spike"]=" CONFIG=SpikeConfig EXTRA_SIM_FLAGS='+spike-ipc=10'" mapping["chipyard-hwacha"]=" CONFIG=HwachaRocketConfig" mapping["chipyard-gemmini"]=" CONFIG=GemminiRocketConfig" mapping["chipyard-cva6"]=" CONFIG=CVA6Config" diff --git a/fpga/src/main/scala/arty/Configs.scala b/fpga/src/main/scala/arty/Configs.scala index 10af02237e..ad8b9a328b 100644 --- a/fpga/src/main/scala/arty/Configs.scala +++ b/fpga/src/main/scala/arty/Configs.scala @@ -21,7 +21,7 @@ class WithArtyTweaks extends Config( new WithArtyJTAGHarnessBinder ++ new WithArtyUARTHarnessBinder ++ new WithDebugResetPassthrough ++ - + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new chipyard.config.WithDTSTimebase(32768) ++ new testchipip.WithNoSerialTL ) diff --git a/fpga/src/main/scala/arty/TestHarness.scala b/fpga/src/main/scala/arty/TestHarness.scala index d368ec5568..6f7c5ea5a1 100644 --- a/fpga/src/main/scala/arty/TestHarness.scala +++ b/fpga/src/main/scala/arty/TestHarness.scala @@ -3,6 +3,7 @@ package chipyard.fpga.arty import chisel3._ import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import org.chipsalliance.cde.config.{Parameters} import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell} @@ -36,4 +37,9 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell lazyDut match { case d: HasIOBinders => ApplyHarnessBinders(this, d.lazySystem, d.portMap) } + + val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + implicitHarnessClockBundle.clock := buildtopClock + implicitHarnessClockBundle.reset := buildtopReset + harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) } diff --git a/fpga/src/main/scala/arty100t/Configs.scala b/fpga/src/main/scala/arty100t/Configs.scala index 673b8b58cd..16683141b6 100644 --- a/fpga/src/main/scala/arty100t/Configs.scala +++ b/fpga/src/main/scala/arty100t/Configs.scala @@ -22,6 +22,7 @@ class WithNoDesignKey extends Config((site, here, up) => { }) class WithArty100TTweaks extends Config( + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new WithArty100TUARTTSI ++ new WithArty100TDDRTL ++ new WithNoDesignKey ++ diff --git a/fpga/src/main/scala/arty100t/Harness.scala b/fpga/src/main/scala/arty100t/Harness.scala index dd76589a5c..d4e7ebc9a0 100644 --- a/fpga/src/main/scala/arty100t/Harness.scala +++ b/fpga/src/main/scala/arty100t/Harness.scala @@ -5,6 +5,7 @@ import chisel3.util._ import freechips.rocketchip.diplomacy._ import org.chipsalliance.cde.config.{Parameters} import freechips.rocketchip.tilelink.{TLClientNode, TLBlockDuringReset} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import sifive.fpgashells.shell.xilinx._ import sifive.fpgashells.shell._ @@ -87,6 +88,11 @@ class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell chiptop match { case d: HasIOBinders => ApplyHarnessBinders(this, d.lazySystem, d.portMap) } + + val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + implicitHarnessClockBundle.clock := buildtopClock + implicitHarnessClockBundle.reset := buildtopReset + harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) } } diff --git a/fpga/src/main/scala/vc707/Configs.scala b/fpga/src/main/scala/vc707/Configs.scala index c029861094..70bd7073a7 100644 --- a/fpga/src/main/scala/vc707/Configs.scala +++ b/fpga/src/main/scala/vc707/Configs.scala @@ -40,6 +40,7 @@ class WithSystemModifications extends Config((site, here, up) => { class WithVC707Tweaks extends Config ( // harness binders + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new WithVC707UARTHarnessBinder ++ new WithVC707SPISDCardHarnessBinder ++ new WithVC707DDRMemHarnessBinder ++ diff --git a/fpga/src/main/scala/vc707/TestHarness.scala b/fpga/src/main/scala/vc707/TestHarness.scala index 8e0bd5bf59..553cf06eb2 100644 --- a/fpga/src/main/scala/vc707/TestHarness.scala +++ b/fpga/src/main/scala/vc707/TestHarness.scala @@ -6,6 +6,7 @@ import chisel3.experimental.{IO} import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} import org.chipsalliance.cde.config.{Parameters} import freechips.rocketchip.tilelink.{TLClientNode} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import sifive.fpgashells.shell.xilinx.{VC707Shell, UARTVC707ShellPlacer, PCIeVC707ShellPlacer, ChipLinkVC707PlacedOverlay} import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} @@ -132,4 +133,9 @@ class VC707FPGATestHarnessImp(_outer: VC707FPGATestHarness) extends LazyRawModul // check the top-level reference clock is equal to the default // non-exhaustive since you need all ChipTop clocks to equal the default require(getRefClockFreq == p(DefaultClockFrequencyKey)) + + val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + implicitHarnessClockBundle.clock := buildtopClock + implicitHarnessClockBundle.reset := buildtopReset + harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) } diff --git a/fpga/src/main/scala/vcu118/Configs.scala b/fpga/src/main/scala/vcu118/Configs.scala index ea6df6c3a5..0d82e1076e 100644 --- a/fpga/src/main/scala/vcu118/Configs.scala +++ b/fpga/src/main/scala/vcu118/Configs.scala @@ -42,6 +42,7 @@ class WithSystemModifications extends Config((site, here, up) => { // DOC include start: AbstractVCU118 and Rocket class WithVCU118Tweaks extends Config( // harness binders + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new WithUART ++ new WithSPISDCard ++ new WithDDRMem ++ diff --git a/fpga/src/main/scala/vcu118/TestHarness.scala b/fpga/src/main/scala/vcu118/TestHarness.scala index 9e7529dddb..5ca3d4a03b 100644 --- a/fpga/src/main/scala/vcu118/TestHarness.scala +++ b/fpga/src/main/scala/vcu118/TestHarness.scala @@ -6,6 +6,7 @@ import chisel3.experimental.{IO} import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} import org.chipsalliance.cde.config.{Parameters} import freechips.rocketchip.tilelink.{TLClientNode} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import sifive.fpgashells.shell.xilinx._ import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} @@ -134,4 +135,9 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod // check the top-level reference clock is equal to the default // non-exhaustive since you need all ChipTop clocks to equal the default require(getRefClockFreq == p(DefaultClockFrequencyKey)) + + val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + implicitHarnessClockBundle.clock := buildtopClock + implicitHarnessClockBundle.reset := buildtopReset + harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) } diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 1e234144d0..8dd0020ea7 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 5a02277c31..5a53051e73 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())) + require(clockGroupAggNode.out.size == 1) + val (bundle, edge) = clockGroupAggNode.out(0) + + val clock_ios = (bundle.member.data zip edge.sink.members).map { case (b, m) => + val freq = m.take.get.freqMHz + val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}") + b.clock := clock_io.clock + b.reset := reset_io + clock_io + }.toSeq + ((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 121cca24f9..0458c62146 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 ceee4c0fa9..4b179fd0ad 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -12,17 +12,18 @@ import org.chipsalliance.cde.config.{Config} class AbstractConfig extends Config( // The HarnessBinders control generation of hardware in the TestHarness - new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present - new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled - new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM - new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled - new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present - new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled - new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled - new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present - new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present - new chipyard.harness.WithCustomBootPinPlusArg ++ - new chipyard.harness.WithClockAndResetFromHarness ++ + new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present + new chipyard.harness.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled + new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM + new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled + new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present + new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled + new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled + new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present + new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present + new chipyard.harness.WithCustomBootPinPlusArg ++ // drive custom-boot pin with a plusarg, if custom-boot-pin is present + new chipyard.harness.WithClockAndResetFromHarness ++ // all Clock/Reset I/O in ChipTop should be driven by harnessClockInstantiator + new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // generate clocks in harness with unsynthesizable ClockSourceAtFreqMHz // 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 @@ -57,8 +56,8 @@ class AbstractConfig extends Config( new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks new chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set) - new chipyard.config.WithMemoryBusFrequency(100.0) ++ // Default 100 MHz mbus - new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus + new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus + new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++ // Default 2 memory channels new freechips.rocketchip.subsystem.WithClockGateModel ++ // add default EICG_wrapper clock gate model new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 965a81fcbe..ea00f8b27e 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -86,7 +86,7 @@ class MbusScratchpadRocketConfig extends Config( // DOC include end: mbusscratchpadrocket class MulticlockRocketConfig extends Config( - new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore + new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add async crossings between RocketTile and uncore new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // Frequency specifications new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540 diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index b92b2f4601..3c2b9a0cd4 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/HarnessBinders.scala b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala index e4e8391b43..d78318f8d1 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala @@ -393,8 +393,8 @@ class WithClockAndResetFromHarness extends OverrideHarnessBinder({ implicit val p = GetSystemParameters(system) ports.map ({ case c: ClockWithFreq => { - th.setRefClockFreq(c.freqMHz) - c.clock := th.buildtopClock + val clock = th.harnessClockInstantiator.requestClockBundle(s"clock_${c.freqMHz}MHz", c.freqMHz * (1000 * 1000)) + c.clock := clock.clock } case r: AsyncReset => r := th.buildtopReset.asAsyncReset }) diff --git a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala index 513ca38c79..4fb7ea9ed2 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala @@ -1,7 +1,8 @@ package chipyard.harness import chisel3._ - +import chisel3.util._ +import chisel3.experimental.DoubleParam import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} import freechips.rocketchip.diplomacy.{LazyModule} import org.chipsalliance.cde.config.{Field, Parameters, Config} @@ -36,44 +37,27 @@ 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 - } - } +class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map( + "PERIOD" -> DoubleParam(1000/freqMHz) +)) with HasBlackBoxInline { + val io = IO(new ClockSourceIO) + val moduleName = this.getClass.getSimpleName + + setInline(s"$moduleName.v", + s""" + |module $moduleName #(parameter PERIOD="") ( + | input power, + | input gate, + | output clk); + | timeunit 1ns/1ps; + | reg clk_i = 1'b0; + | always #(PERIOD/2.0) clk_i = ~clk_i & (power & ~gate); + | assign clk = clk_i; + |endmodule + |""".stripMargin) } + // The AbsoluteFreqHarnessClockInstantiator uses a Verilog blackbox to // provide the precise requested frequency. // This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim @@ -86,7 +70,7 @@ class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator { // connect wires to clock source for (sinkParams <- sinks) { - val source = Module(new ClockSourceAtFreq(sinkParams.take.get.freqMHz)) + val source = Module(new ClockSourceAtFreqMHz(sinkParams.take.get.freqMHz)) source.io.power := true.B source.io.gate := false.B @@ -99,3 +83,18 @@ class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator { class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) => { case HarnessClockInstantiatorKey => () => new AbsoluteFreqHarnessClockInstantiator }) + +class AllClocksFromHarnessClockInstantiator extends HarnessClockInstantiator { + def instantiateHarnessClocks(refClock: ClockBundle): Unit = { + val freqs = _clockMap.map(_._2._1) + freqs.tail.foreach(t => require(t == freqs.head, s"Mismatching clocks $t != ${freqs.head}")) + for ((_, (_, bundle)) <- _clockMap) { + bundle.clock := refClock.clock + bundle.reset := refClock.reset + } + } +} + +class WithAllClocksFromHarnessClockInstantiator extends Config((site, here, up) => { + case HarnessClockInstantiatorKey => () => new AllClocksFromHarnessClockInstantiator +}) diff --git a/generators/chipyard/src/main/scala/harness/TestHarness.scala b/generators/chipyard/src/main/scala/harness/TestHarness.scala index 22bcc1670a..cb8cfe4765 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