Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch RTL sims to absolute clock-generators #1472

Merged
merged 12 commits into from
May 12, 2023
Merged
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
Loading