Skip to content

Commit

Permalink
Merge pull request #1472 from ucb-bar/simpleclocks
Browse files Browse the repository at this point in the history
Switch RTL sims to absolute clock-generators
  • Loading branch information
jerryz123 authored May 12, 2023
2 parents 335a50d + d673c61 commit 27f78da
Show file tree
Hide file tree
Showing 18 changed files with 128 additions and 161 deletions.
2 changes: 1 addition & 1 deletion .github/scripts/defaults.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion fpga/src/main/scala/arty/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
6 changes: 6 additions & 0 deletions fpga/src/main/scala/arty/TestHarness.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions fpga/src/main/scala/arty100t/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++
Expand Down
6 changes: 6 additions & 0 deletions fpga/src/main/scala/arty100t/Harness.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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)
}

}
1 change: 1 addition & 0 deletions fpga/src/main/scala/vc707/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++
Expand Down
6 changes: 6 additions & 0 deletions fpga/src/main/scala/vc707/TestHarness.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions fpga/src/main/scala/vcu118/Configs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++
Expand Down
6 changes: 6 additions & 0 deletions fpga/src/main/scala/vcu118/TestHarness.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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)
}
1 change: 0 additions & 1 deletion generators/chipyard/src/main/scala/IOBinders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
84 changes: 40 additions & 44 deletions generators/chipyard/src/main/scala/clocking/ClockBinders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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)
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
33 changes: 16 additions & 17 deletions generators/chipyard/src/main/scala/config/AbstractConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 ++
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
Loading

0 comments on commit 27f78da

Please sign in to comment.