From 8a1ebb090cad661cbf9b17d902f061dae8f4f7e7 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 5 Apr 2023 11:42:41 -0700 Subject: [PATCH 1/9] Move Clock binders to separate file --- .../src/main/scala/HarnessBinders.scala | 4 +- .../chipyard/src/main/scala/IOBinders.scala | 41 --------------- .../main/scala/clocking/ClockBinders.scala | 52 +++++++++++++++++++ .../main/scala/config/AbstractConfig.scala | 6 ++- .../main/scala/config/TracegenConfigs.scala | 2 +- 5 files changed, 60 insertions(+), 45 deletions(-) create mode 100644 generators/chipyard/src/main/scala/clocking/ClockBinders.scala diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 1992bc1e..51d39ce4 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -22,8 +22,8 @@ import barstools.iocell.chisel._ import testchipip._ import chipyard._ -import chipyard.clocking.{HasChipyardPRCI} -import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, ClockWithFreq} +import chipyard.clocking.{HasChipyardPRCI, ClockWithFreq} +import chipyard.iobinders.{GetSystemParameters, JTAGChipIO} import tracegen.{TraceGenSystemModuleImp} import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index f883931e..1e234144 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -425,45 +425,4 @@ class WithDontTouchPorts extends OverrideIOBinder({ (system: DontTouch) => system.dontTouchPorts(); (Nil, Nil) }) -class ClockWithFreq(val freqMHz: Double) extends Bundle { - val clock = Clock() -} -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) - } - } -}) diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala new file mode 100644 index 00000000..5aa7cbc8 --- /dev/null +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -0,0 +1,52 @@ +package chipyard.clocking + +import chisel3._ +import chisel3.util._ +import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey} +import freechips.rocketchip.prci._ +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.subsystem._ +import barstools.iocell.chisel._ + +class ClockWithFreq(val freqMHz: Double) extends Bundle { + val clock = Clock() +} + +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) + } + } +}) diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index c9a6e838..e270c978 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -40,7 +40,11 @@ class AbstractConfig extends Config( new chipyard.iobinders.WithTraceIOPunchthrough ++ new chipyard.iobinders.WithExtInterruptIOCells ++ new chipyard.iobinders.WithCustomBootPin ++ - new chipyard.iobinders.WithDividerOnlyClockGenerator ++ + + // 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 ++ new testchipip.WithSerialTLWidth(32) ++ // fatten the serialTL interface to improve testing performance new testchipip.WithDefaultSerialTL ++ // use serialized tilelink port to external serialadapter/harnessRAM diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index 605db4d3..b92b2f46 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -9,7 +9,7 @@ class AbstractTraceGenConfig extends Config( new chipyard.harness.WithClockAndResetFromHarness ++ new chipyard.iobinders.WithAXI4MemPunchthrough ++ new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ - new chipyard.iobinders.WithDividerOnlyClockGenerator ++ + new chipyard.clocking.WithDividerOnlyClockGenerator ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ From 70ea3b78ab72abb01b17f5907ff6f90f6463191d Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 5 Apr 2023 15:31:21 -0700 Subject: [PATCH 2/9] Add ChipLikeRocketConfig ... improve harness clocking APIs --- .../src/main/scala/HarnessBinders.scala | 2 +- .../src/main/scala/HarnessClocks.scala | 85 +++++++++++++++++++ .../chipyard/src/main/scala/TestHarness.scala | 53 +----------- .../main/scala/clocking/ClockBinders.scala | 61 +++++++++++++ .../src/main/scala/clocking/FakePLL.scala | 36 ++++++++ .../main/scala/clocking/TLClockDivider.scala | 52 ++++++++++++ .../main/scala/clocking/TLClockSelector.scala | 70 +++++++++++++++ .../main/scala/clocking/TileClockGater.scala | 2 +- .../main/scala/clocking/TileResetSetter.scala | 6 +- 9 files changed, 313 insertions(+), 54 deletions(-) create mode 100644 generators/chipyard/src/main/scala/HarnessClocks.scala create mode 100644 generators/chipyard/src/main/scala/clocking/FakePLL.scala create mode 100644 generators/chipyard/src/main/scala/clocking/TLClockDivider.scala create mode 100644 generators/chipyard/src/main/scala/clocking/TLClockSelector.scala diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 51d39ce4..c39242f9 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -154,7 +154,7 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ ports.map({ port => // DOC include start: HarnessClockInstantiatorEx withClockAndReset(th.buildtopClock, th.buildtopReset) { - val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).requestClockBundle("mem_over_serial_tl_clock", memFreq) + val memOverSerialTLClockBundle = th.harnessClockInstantiator.requestClockBundle("mem_over_serial_tl_clock", memFreq) val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, diff --git a/generators/chipyard/src/main/scala/HarnessClocks.scala b/generators/chipyard/src/main/scala/HarnessClocks.scala new file mode 100644 index 00000000..f973c292 --- /dev/null +++ b/generators/chipyard/src/main/scala/HarnessClocks.scala @@ -0,0 +1,85 @@ +package chipyard + +import chisel3._ + +import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} +import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.config.{Field, Parameters, Config} +import freechips.rocketchip.util.{ResetCatchAndSync} +import freechips.rocketchip.prci._ + +import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} +import chipyard.iobinders.HasIOBinders +import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} +import chipyard.HarnessClockInstantiatorKey + +trait HarnessClockInstantiator { + val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty + + // request a clock bundle at a particular frequency + def requestClockBundle(name: String, freqRequested: Double): ClockBundle = { + val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) + _clockMap(name) = (freqRequested, clockBundle) + clockBundle + } + + def instantiateHarnessClocks(refClock: ClockBundle): Unit +} + +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 AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator { + 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 + + // connect wires to clock source + for (sinkParams <- sinks) { + val source = Module(new ClockSourceAtFreq(sinkParams.take.get.freqMHz)) + source.io.power := true.B + source.io.gate := false.B + + _clockMap(sinkParams.name.get)._2.clock := source.io.clk + _clockMap(sinkParams.name.get)._2.reset := refClock.reset + } + } +} + +class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) => { + case HarnessClockInstantiatorKey => () => new AbsoluteFreqHarnessClockInstantiator +}) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 23bda680..a8b18d4f 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -18,9 +18,11 @@ import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} 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) trait HasHarnessSignalReferences { implicit val p: Parameters + val harnessClockInstantiator = p(HarnessClockInstantiatorKey)() // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset) var refClockFreq: Double = p(DefaultClockFrequencyKey) def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz } @@ -30,53 +32,6 @@ trait HasHarnessSignalReferences { def success: Bool } -class HarnessClockInstantiator { - private val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty - - // request a clock bundle at a particular frequency - def requestClockBundle(name: String, freqRequested: Double): ClockBundle = { - val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) - _clockMap(name) = (freqRequested, clockBundle) - clockBundle - } - - // connect all clock wires specified to a divider only PLL - def instantiateHarnessDividerPLL(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 - } - } -} - -case object HarnessClockInstantiatorKey extends Field[HarnessClockInstantiator](new HarnessClockInstantiator) - class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences { val io = IO(new Bundle { val success = Output(Bool()) @@ -96,7 +51,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign ApplyHarnessBinders(this, d.lazySystem, d.portMap) } - val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000)) + val refClkBundle = harnessClockInstantiator.requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000)) buildtopClock := refClkBundle.clock buildtopReset := WireInit(refClkBundle.reset) @@ -104,5 +59,5 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) implicitHarnessClockBundle.clock := clock implicitHarnessClockBundle.reset := reset - p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle) + harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) } diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index 5aa7cbc8..01eb261c 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -6,6 +6,7 @@ import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey} import freechips.rocketchip.prci._ import freechips.rocketchip.diplomacy._ import freechips.rocketchip.subsystem._ +import freechips.rocketchip.tilelink._ import barstools.iocell.chisel._ class ClockWithFreq(val freqMHz: Double) extends Bundle { @@ -50,3 +51,63 @@ class WithDividerOnlyClockGenerator extends OverrideLazyIOBinder({ } } }) + +// Note: This will not simulate properly with verilator or firesim +class WithPLLSelectorDividerClockGenerator 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 + }} + } + val tlbus = system.asInstanceOf[BaseSubsystem].locateTLBusWrapper(system.prciParams.slaveWhere) + val baseAddress = system.prciParams.baseAddress + val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) } + val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) } + val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) } + + tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() } + tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() } + tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() } + + system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode + + // Connect all other requested clocks + val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + + // The order of the connections to clockSelector.clockNode configures what + clockSelector.clockNode := slowClockSource + clockSelector.clockNode := pllClockSource + + val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]() + pllCtrlSink := pllCtrl.ctrlNode + + InModuleBody { + val clock_wire = Wire(Input(new ClockWithFreq(80))) + 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)) + + slowClockSource.out.unzip._1.map { o => + o.clock := clock_wire.clock + o.reset := reset_wire + } + + // For a real chip you should replace this ClockSourceAtFreqFromPlusArg + // with a blackbox of whatever PLL is being integrated + val fakeClockSource = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz")) + fakeClockSource.io.power := pllCtrlSink.in(0)._1.power + fakeClockSource.io.gate := pllCtrlSink.in(0)._1.gate + + (Seq(clock_io, reset_io), clockIOCell ++ resetIOCell) + } + } +}) diff --git a/generators/chipyard/src/main/scala/clocking/FakePLL.scala b/generators/chipyard/src/main/scala/clocking/FakePLL.scala new file mode 100644 index 00000000..a903ced6 --- /dev/null +++ b/generators/chipyard/src/main/scala/clocking/FakePLL.scala @@ -0,0 +1,36 @@ +package chipyard.clocking + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.util._ + +class FakePLLCtrlBundle extends Bundle { + val gate = Bool() + val power = Bool() +} + +class FakePLLCtrl(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule +{ + val device = new SimpleDevice(s"pll", Nil) + val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes) + val ctrlNode = BundleBridgeSource(() => Output(new FakePLLCtrlBundle)) + lazy val module = new LazyModuleImp(this) { + // This PLL only has 2 address, the gate and power + // Both should be set to turn on the PLL + // TODO: Should these be reset by the top level reset pin? + val gate_reg = Module(new AsyncResetRegVec(w=1, init=0)) + val power_reg = Module(new AsyncResetRegVec(w=1, init=0)) + + ctrlNode.out(0)._1.gate := gate_reg.io.q + ctrlNode.out(0)._1.power := power_reg.io.q + tlNode.regmap( + 0 -> Seq(RegField.rwReg(1, gate_reg.io)), + 4 -> Seq(RegField.rwReg(1, power_reg.io)) + ) + } +} diff --git a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala new file mode 100644 index 00000000..b9d62344 --- /dev/null +++ b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala @@ -0,0 +1,52 @@ +package chipyard.clocking + +import chisel3._ + +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.util._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.util.ElaborationArtefacts + +import testchipip._ + +class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice(s"clk-div-ctrl", Nil) + val clockNode = ClockGroupIdentityNode() + val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes) + + lazy val module = new LazyModuleImp(this) { + require (clockNode.out.size == 1) + val sources = clockNode.in.head._1.member.data.toSeq + val sinks = clockNode.out.head._1.member.elements.toSeq + require (sources.size == sinks.size) + val nSinks = sinks.size + + val regs = (0 until nSinks) .map { i => + val sinkName = sinks(i)._1 + val asyncReset = sources(i).reset + val reg = withReset (asyncReset) { + Module(new AsyncResetRegVec(w=divBits, init=0)) + } + println(s"${(address+i*4).toString(16)}: Clock domain $sinkName divider") + sinks(i)._2.clock := withClockAndReset(sources(i).clock, asyncReset) { + val divider = Module(new testchipip.ClockDivideOrPass(divBits, depth = 3, genClockGate = p(ClockGateImpl))) + divider.io.divisor := reg.io.q + divider.io.resetAsync := ResetStretcher(sources(i).clock, asyncReset, 20).asAsyncReset + divider.io.clockOut + } + + // Note this is not synchronized to the output clock, which takes time to appear + // so this is still asyncreset + sinks(i)._2.reset := ResetStretcher(sources(i).clock, asyncReset, 40).asAsyncReset + reg + } + + tlNode.regmap((0 until nSinks).map { i => + i * 4 -> Seq(RegField.rwReg(divBits, regs(i).io)) + }: _*) + } +} diff --git a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala new file mode 100644 index 00000000..22110e62 --- /dev/null +++ b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala @@ -0,0 +1,70 @@ +package chipyard.clocking + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.regmapper._ +import freechips.rocketchip.util._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.util.ElaborationArtefacts + +import testchipip._ + +object ResetStretcher { + def apply(clock: Clock, reset: Reset, cycles: Int): Reset = { + withClockAndReset(clock, reset) { + val n = log2Ceil(cycles) + val count = Module(new AsyncResetRegVec(w=n, init=0)) + val resetout = Module(new AsyncResetRegVec(w=1, init=1)) + count.io.en := resetout.io.q + count.io.d := count.io.q + 1.U + resetout.io.en := resetout.io.q + resetout.io.d := count.io.q < (cycles-1).U + + resetout.io.q.asBool + } + } +} + + +case class ClockSelNode()(implicit valName: ValName) + extends MixedNexusNode(ClockImp, ClockGroupImp)( + dFn = { d => ClockGroupSourceParameters() }, + uFn = { u => ClockSinkParameters() } +) + +class TLClockSelector(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule { + val device = new SimpleDevice("clk-sel-ctrl", Nil) + val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes) + + val clockNode = ClockSelNode() + + lazy val module = new LazyModuleImp(this) { + val asyncReset = clockNode.in.map(_._1).map(_.reset).toSeq(0) + val clocks = clockNode.in.map(_._1).map(_.clock) + val (outClocks, _) = clockNode.out.head + val (sinkNames, sinks) = outClocks.member.elements.toSeq.unzip + + val regs = (0 until sinks.size).map { i => + val sinkName = sinkNames(i) + val sel = Wire(UInt(log2Ceil(clocks.size).W)) + val reg = withReset(asyncReset) { Module(new AsyncResetRegVec(w=log2Ceil(clocks.size), init=0)) } + sel := reg.io.q + println(s"${(address+i*4).toString(16)}: Clock domain $sinkName clock mux") + + val mux = testchipip.ClockMutexMux(clocks).suggestName(s"${sinkName}_clkmux") + mux.io.sel := sel + mux.io.resetAsync := asyncReset.asAsyncReset + sinks(i).clock := mux.io.clockOut + sinks(i).reset := ResetStretcher(clocks(0), asyncReset, 20).asAsyncReset + + reg + } + tlNode.regmap((0 until sinks.size).map { i => + i * 4 -> Seq(RegField.rwReg(log2Ceil(clocks.size), regs(i).io)) + }: _*) + } +} diff --git a/generators/chipyard/src/main/scala/clocking/TileClockGater.scala b/generators/chipyard/src/main/scala/clocking/TileClockGater.scala index 9b7696fb..a77b02d5 100644 --- a/generators/chipyard/src/main/scala/clocking/TileClockGater.scala +++ b/generators/chipyard/src/main/scala/clocking/TileClockGater.scala @@ -32,7 +32,7 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit val sinkName = sinks(i)._1 val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) } if (sinkName.contains("tile") && enable) { - println(s"ClockGate for ${sinkName} regmapped at ${(address+i*4).toString(16)}") + println(s"${(address+i*4).toString(16)}: Tile $sinkName clock gate") sinks(i)._2.clock := ClockGate(sources(i).clock, reg.io.q.asBool) sinks(i)._2.reset := sources(i).reset } else { diff --git a/generators/chipyard/src/main/scala/clocking/TileResetSetter.scala b/generators/chipyard/src/main/scala/clocking/TileResetSetter.scala index d8243e37..9ea4bfd5 100644 --- a/generators/chipyard/src/main/scala/clocking/TileResetSetter.scala +++ b/generators/chipyard/src/main/scala/clocking/TileResetSetter.scala @@ -39,16 +39,16 @@ class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], i }): _*) val tileMap = tileNames.zipWithIndex.map({ case (n, i) => - n -> (tile_async_resets(i), r_tile_resets(i).io.q) + n -> (tile_async_resets(i), r_tile_resets(i).io.q, address + i * 4) }) (clockNode.out zip clockNode.in).map { case ((o, _), (i, _)) => (o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) => oD.clock := iD.clock oD.reset := iD.reset - for ((n, (rIn, rOut)) <- tileMap) { + for ((n, (rIn, rOut, addr)) <- tileMap) { if (name.contains(n)) { - println(name, n) + println(s"${addr.toString(16)}: Tile $name reset control") // Async because the reset coming out of the AsyncResetRegVec is // clocked to the bus this is attached to, not the clock in this // clock bundle. We expect a ClockGroupResetSynchronizer downstream From f1b17b533bf1a9e30c2b18e4d290e18a625fdf8a Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 5 Apr 2023 18:37:35 -0700 Subject: [PATCH 3/9] Add examples of ChipLikeRocketConfig/FlatChipTop/FlatTestHarness --- .../main/scala/clocking/ClockBinders.scala | 11 +- .../src/main/scala/config/ChipConfigs.scala | 44 ++++++ .../src/main/scala/example/FlatChipTop.scala | 143 ++++++++++++++++++ .../main/scala/example/FlatTestHarness.scala | 83 ++++++++++ 4 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 generators/chipyard/src/main/scala/config/ChipConfigs.scala create mode 100644 generators/chipyard/src/main/scala/example/FlatChipTop.scala create mode 100644 generators/chipyard/src/main/scala/example/FlatTestHarness.scala diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index 01eb261c..6d0ace69 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -103,9 +103,14 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ // For a real chip you should replace this ClockSourceAtFreqFromPlusArg // with a blackbox of whatever PLL is being integrated - val fakeClockSource = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz")) - fakeClockSource.io.power := pllCtrlSink.in(0)._1.power - fakeClockSource.io.gate := pllCtrlSink.in(0)._1.gate + val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz")) + fake_pll.io.power := pllCtrlSink.in(0)._1.power + fake_pll.io.gate := pllCtrlSink.in(0)._1.gate + + pllClockSource.out.unzip._1.map { o => + o.clock := fake_pll.io.clk + o.reset := reset_wire + } (Seq(clock_io, reset_io), clockIOCell ++ resetIOCell) } diff --git a/generators/chipyard/src/main/scala/config/ChipConfigs.scala b/generators/chipyard/src/main/scala/config/ChipConfigs.scala new file mode 100644 index 00000000..1ed215f6 --- /dev/null +++ b/generators/chipyard/src/main/scala/config/ChipConfigs.scala @@ -0,0 +1,44 @@ +package chipyard + +import freechips.rocketchip.config.{Config} +import freechips.rocketchip.diplomacy._ + +// A simple config demonstrating how to set up a basic chip in Chipyard +class ChipLikeRocketConfig extends Config( + //================================== + // Set up TestHarness + //================================== + new chipyard.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness + // NOTE: This only simulates properly in VCS + + //================================== + // Set up tiles + //================================== + new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add rational crossings between RocketTile and uncore + new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles) + + //================================== + // Set up I/O + //================================== + new testchipip.WithSerialTLWidth(4) ++ + new chipyard.harness.WithSimAXIMemOverSerialTL ++ // Attach fast SimDRAM to TestHarness + new chipyard.config.WithSerialTLBackingMemory ++ // Backing memory is over serial TL protocol + new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++ // 4GB max external memory + + //================================== + // Set up clock./reset + //================================== + new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure + + // Create two clock groups, uncore and fbus, in addition to the tile clock groups + new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus") ++ + new chipyard.clocking.WithClockGroupsCombinedByName("fbus", "fbus", "pbus") ++ + + // Set up the crossings + new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS + new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS + new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS + new testchipip.WithSerialTLAsyncResetQueue ++ // Add Async reset queue to block ready while in reset + + new chipyard.config.AbstractConfig) + diff --git a/generators/chipyard/src/main/scala/example/FlatChipTop.scala b/generators/chipyard/src/main/scala/example/FlatChipTop.scala new file mode 100644 index 00000000..97ac5032 --- /dev/null +++ b/generators/chipyard/src/main/scala/example/FlatChipTop.scala @@ -0,0 +1,143 @@ +package chipyard.example + + +import chisel3._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.prci._ +import freechips.rocketchip.util._ +import freechips.rocketchip.devices.debug.{ExportDebug, JtagDTMKey, Debug} +import freechips.rocketchip.tilelink.{TLBuffer} +import chipyard.{BuildSystem, DigitalTop} +import chipyard.clocking._ +import chipyard.iobinders.{IOCellKey, JTAGChipIO} +import barstools.iocell.chisel._ + + +// This "FlatChipTop" uses no IOBinders, so all the IO have +// to be explicitly constructed. +// This only supports the base "DigitalTop" +class FlatChipTop(implicit p: Parameters) extends LazyModule { + override lazy val desiredName = "ChipTop" + val system = LazyModule(p(BuildSystem)(p)).suggestName("system").asInstanceOf[DigitalTop] + + //======================== + // Diplomatic clock stuff + //======================== + val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) + system.connectImplicitClockSinkNode(implicitClockSinkNode) + + val tlbus = system.locateTLBusWrapper(system.prciParams.slaveWhere) + val baseAddress = system.prciParams.baseAddress + val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) } + val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) } + val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) } + + tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() } + tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() } + tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() } + + system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode + + // Connect all other requested clocks + val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + + // The order of the connections to clockSelector.clockNode configures what + clockSelector.clockNode := slowClockSource + clockSelector.clockNode := pllClockSource + + val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]() + pllCtrlSink := pllCtrl.ctrlNode + + val debugClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters())) + debugClockSinkNode := system.locateTLBusWrapper(p(ExportDebug).slaveWhere).fixedClockNode + def debugClockBundle = debugClockSinkNode.in.head._1 + + override lazy val module = new FlatChipTopImpl + class FlatChipTopImpl extends LazyRawModuleImp(this) { + //========================= + // Clock/reset + //========================= + val implicit_clock = implicitClockSinkNode.in.head._1.clock + val implicit_reset = implicitClockSinkNode.in.head._1.reset + system.module match { case l: LazyModuleImp => { + l.clock := implicit_clock + l.reset := implicit_reset + }} + + val clock_wire = Wire(Input(new ClockWithFreq(80))) + val reset_wire = Wire(Input(AsyncReset())) + val (clock_pad, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey)) + val (reset_pad, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey)) + + slowClockSource.out.unzip._1.map { o => + o.clock := clock_wire.clock + o.reset := reset_wire + } + + // For a real chip you should replace this ClockSourceAtFreqFromPlusArg + // with a blackbox of whatever PLL is being integrated + val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz")) + fake_pll.io.power := pllCtrlSink.in(0)._1.power + fake_pll.io.gate := pllCtrlSink.in(0)._1.gate + + pllClockSource.out.unzip._1.map { o => + o.clock := fake_pll.io.clk + o.reset := reset_wire + } + + //========================= + // Custom Boot + //========================= + val (custom_boot_pad, customBootIOCell) = IOCell.generateIOFromSignal(system.custom_boot_pin.get.getWrappedValue, "custom_boot", p(IOCellKey)) + + //========================= + // Serialized TileLink + //========================= + val (serial_tl_pad, serialTLIOCells) = IOCell.generateIOFromSignal(system.serial_tl.get.getWrappedValue, "serial_tl", p(IOCellKey)) + + //========================= + // JTAG/Debug + //========================= + val debug = system.module.debug.get + // We never use the PSDIO, so tie it off on-chip + system.module.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } + system.module.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := false.B } } + + // Tie off extTrigger + debug.extTrigger.foreach { t => + t.in.req := false.B + t.out.ack := t.out.req + } + // Tie off disableDebug + debug.disableDebug.foreach { d => d := false.B } + // Drive JTAG on-chip IOs + debug.systemjtag.map { j => + j.reset := ResetCatchAndSync(j.jtag.TCK, debugClockBundle.reset.asBool) + j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W) + j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W) + j.version := p(JtagDTMKey).idcodeVersion.U(4.W) + } + + Debug.connectDebugClockAndReset(Some(debug), debugClockBundle.clock) + + // Add IOCells for the DMI/JTAG/APB ports + require(!debug.clockeddmi.isDefined) + require(!debug.apb.isDefined) + val (jtag_pad, jtagIOCells) = debug.systemjtag.map { j => + val jtag_wire = Wire(new JTAGChipIO) + j.jtag.TCK := jtag_wire.TCK + j.jtag.TMS := jtag_wire.TMS + j.jtag.TDI := jtag_wire.TDI + jtag_wire.TDO := j.jtag.TDO.data + IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true) + }.get + + //========================== + // UART + //========================== + require(system.uarts.size == 1) + val (uart_pad, uartIOCells) = IOCell.generateIOFromSignal(system.module.uart.head, "uart_0", p(IOCellKey)) + } +} diff --git a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala new file mode 100644 index 00000000..a45a4a3b --- /dev/null +++ b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala @@ -0,0 +1,83 @@ +package chipyard.example + +import chisel3._ + +import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} + +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy.{LazyModule} +import freechips.rocketchip.prci.{ClockSourceAtFreqFromPlusArg, ClockBundle, ClockBundleParameters} +import freechips.rocketchip.util.{PlusArg} +import freechips.rocketchip.subsystem.{CacheBlockBytes} +import freechips.rocketchip.devices.debug.{SimJTAG} +import freechips.rocketchip.jtag.{JTAGIO} +import testchipip.{SerialTLKey, SerialAdapter, UARTAdapter, SimDRAM} +import chipyard.{BuildTop} + +// A "flat" TestHarness that doesn't use IOBinders +// use with caution. +// This example is hard-coded to work only for FlatChipTop, and the ChipLikeRocketConfig +class FlatTestHarness(implicit val p: Parameters) extends Module { + val io = IO(new Bundle { + val success = Output(Bool()) + }) + + // This only works with FlatChipTop + val lazyDut = LazyModule(new FlatChipTop).suggestName("chiptop") + val dut = Module(lazyDut.module) + + // Clock + val clock_source = Module(new ClockSourceAtFreqFromPlusArg("slow_clk_freq_mhz")) + clock_source.io.power := true.B + clock_source.io.gate := false.B + dut.clock_pad.clock := clock_source.io.clk + + // Reset + dut.reset_pad := reset.asAsyncReset + + // Custom boot + dut.custom_boot_pad := PlusArg("custom_boot_pin", width=1) + + // Serialized TL + val sVal = p(SerialTLKey).get + require(sVal.axiMemOverSerialTLParams.isDefined) + require(sVal.isMemoryDevice) + val axiDomainParams = sVal.axiMemOverSerialTLParams.get + val memFreq = axiDomainParams.getMemFrequency(lazyDut.system) + + withClockAndReset(clock, reset) { + val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + memOverSerialTLClockBundle.clock := clock + memOverSerialTLClockBundle.reset := reset + val serial_bits = SerialAdapter.asyncQueue(dut.serial_tl_pad, clock, reset) + val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( + lazyDut.system.serdesser.get, + serial_bits, + memOverSerialTLClockBundle, + reset) + io.success := SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, clock, reset) + + // connect SimDRAM from the AXI port coming from the harness multi clock axi ram + (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) => + val memSize = sVal.memParams.size + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram") + mem.io.axi <> axi_port.bits + mem.io.clock := axi_port.clock + mem.io.reset := axi_port.reset + } + } + + // JTAG + val jtag_wire = Wire(new JTAGIO) + jtag_wire.TDO.data := dut.jtag_pad.TDO + jtag_wire.TDO.driven := true.B + dut.jtag_pad.TCK := jtag_wire.TCK + dut.jtag_pad.TMS := jtag_wire.TMS + dut.jtag_pad.TDI := jtag_wire.TDI + val dtm_success = WireInit(false.B) + val jtag = Module(new SimJTAG(tickDelay=3)).connect(jtag_wire, clock, reset.asBool, ~(reset.asBool), dtm_success) + + // UART + UARTAdapter.connect(Seq(dut.uart_pad)) +} From 70643335d2cb662104e2ecb3cbaf3b5d62446719 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Wed, 5 Apr 2023 19:29:03 -0700 Subject: [PATCH 4/9] Fix RationalRockettiles not getting picked up in MulticlockRocketConfig --- generators/chipyard/src/main/scala/config/RocketConfigs.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 01d901aa..8ed4acdc 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -86,6 +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.WithNBigCores(1) ++ // Frequency specifications new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540 @@ -96,7 +97,6 @@ class MulticlockRocketConfig extends Config( // Crossing specifications new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS - new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS new chipyard.config.AbstractConfig) From 32f0f8390060e000db2aa8002d5c2e70f76865ec Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Thu, 6 Apr 2023 12:53:15 -0700 Subject: [PATCH 5/9] [ci skip] Update comments for FakePLLClockBinder --- .../chipyard/src/main/scala/clocking/ClockBinders.scala | 4 +++- generators/chipyard/src/main/scala/example/FlatChipTop.scala | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index 6d0ace69..a0dbe482 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -83,7 +83,9 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters())) val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters())) - // The order of the connections to clockSelector.clockNode configures what + // The order of the connections to clockSelector.clockNode configures the inputs + // of the clockSelector's clockMux. Default to using the slowClockSource, + // software should enable the PLL, then switch to the pllClockSource clockSelector.clockNode := slowClockSource clockSelector.clockNode := pllClockSource diff --git a/generators/chipyard/src/main/scala/example/FlatChipTop.scala b/generators/chipyard/src/main/scala/example/FlatChipTop.scala index 97ac5032..9e142bda 100644 --- a/generators/chipyard/src/main/scala/example/FlatChipTop.scala +++ b/generators/chipyard/src/main/scala/example/FlatChipTop.scala @@ -43,7 +43,9 @@ class FlatChipTop(implicit p: Parameters) extends LazyModule { val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters())) val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters())) - // The order of the connections to clockSelector.clockNode configures what + // The order of the connections to clockSelector.clockNode configures the inputs + // of the clockSelector's clockMux. Default to using the slowClockSource, + // software should enable the PLL, then switch to the pllClockSource clockSelector.clockNode := slowClockSource clockSelector.clockNode := pllClockSource From b7b2a62d80fb7249b4a429f886a3ebd668db329e Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 8 Apr 2023 14:53:09 -0700 Subject: [PATCH 6/9] Update clocking stuff to chisel 3.5.6 --- generators/chipyard/src/main/scala/clocking/FakePLL.scala | 2 +- .../chipyard/src/main/scala/clocking/TLClockDivider.scala | 2 +- .../chipyard/src/main/scala/clocking/TLClockSelector.scala | 2 +- generators/chipyard/src/main/scala/config/ChipConfigs.scala | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/generators/chipyard/src/main/scala/clocking/FakePLL.scala b/generators/chipyard/src/main/scala/clocking/FakePLL.scala index a903ced6..ac8f8b44 100644 --- a/generators/chipyard/src/main/scala/clocking/FakePLL.scala +++ b/generators/chipyard/src/main/scala/clocking/FakePLL.scala @@ -2,7 +2,7 @@ package chipyard.clocking import chisel3._ import chisel3.util._ -import freechips.rocketchip.config.Parameters +import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.devices.tilelink._ diff --git a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala index b9d62344..00ad45b2 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala @@ -2,7 +2,7 @@ package chipyard.clocking import chisel3._ -import freechips.rocketchip.config.Parameters +import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.devices.tilelink._ diff --git a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala index 22110e62..988b702e 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala @@ -2,7 +2,7 @@ package chipyard.clocking import chisel3._ import chisel3.util._ -import freechips.rocketchip.config.Parameters +import org.chipsalliance.cde.config.Parameters import freechips.rocketchip.diplomacy._ import freechips.rocketchip.tilelink._ import freechips.rocketchip.devices.tilelink._ diff --git a/generators/chipyard/src/main/scala/config/ChipConfigs.scala b/generators/chipyard/src/main/scala/config/ChipConfigs.scala index 1ed215f6..564e07d8 100644 --- a/generators/chipyard/src/main/scala/config/ChipConfigs.scala +++ b/generators/chipyard/src/main/scala/config/ChipConfigs.scala @@ -1,6 +1,6 @@ package chipyard -import freechips.rocketchip.config.{Config} +import org.chipsalliance.cde.config.{Config} import freechips.rocketchip.diplomacy._ // A simple config demonstrating how to set up a basic chip in Chipyard From b88e1025e40d29a2e8528c218d9ef6af1c7fb45e Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 8 Apr 2023 14:54:25 -0700 Subject: [PATCH 7/9] Add comments on ResetStretchers --- .../chipyard/src/main/scala/clocking/TLClockDivider.scala | 2 ++ .../chipyard/src/main/scala/clocking/TLClockSelector.scala | 1 + 2 files changed, 3 insertions(+) diff --git a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala index 00ad45b2..93a476c6 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala @@ -41,6 +41,8 @@ class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit // Note this is not synchronized to the output clock, which takes time to appear // so this is still asyncreset + // Stretch the reset for 40 cycles, to give enough time to reset any downstream + // digital logic sinks(i)._2.reset := ResetStretcher(sources(i).clock, asyncReset, 40).asAsyncReset reg } diff --git a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala index 988b702e..0893f120 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala @@ -59,6 +59,7 @@ class TLClockSelector(address: BigInt, beatBytes: Int)(implicit p: Parameters) e mux.io.sel := sel mux.io.resetAsync := asyncReset.asAsyncReset sinks(i).clock := mux.io.clockOut + // Stretch the reset for 20 cycles, to give time to reset any downstream digital logic sinks(i).reset := ResetStretcher(clocks(0), asyncReset, 20).asAsyncReset reg From de293f5fdf84cf74dc0bb949d457f4c90aa031f9 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 8 Apr 2023 14:56:36 -0700 Subject: [PATCH 8/9] Add build of ChipLikeQuadRocketConfig to CI --- .github/scripts/defaults.sh | 3 ++- generators/chipyard/src/main/scala/HarnessClocks.scala | 2 +- .../chipyard/src/main/scala/config/ChipConfigs.scala | 2 +- .../chipyard/src/main/scala/example/FlatChipTop.scala | 8 ++++---- .../chipyard/src/main/scala/example/FlatTestHarness.scala | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/scripts/defaults.sh b/.github/scripts/defaults.sh index 6013d7d4..13bcf116 100755 --- a/.github/scripts/defaults.sh +++ b/.github/scripts/defaults.sh @@ -29,7 +29,7 @@ REMOTE_COURSIER_CACHE=$REMOTE_WORK_DIR/.coursier-cache # key value store to get the build groups declare -A grouping grouping["group-cores"]="chipyard-cva6 chipyard-ibex chipyard-rocket chipyard-hetero chipyard-boom chipyard-sodor chipyard-digitaltop chipyard-multiclock-rocket chipyard-nomem-scratchpad chipyard-spike chipyard-clone" -grouping["group-peripherals"]="chipyard-dmirocket chipyard-spiflashwrite chipyard-mmios chipyard-nocores chipyard-manyperipherals" +grouping["group-peripherals"]="chipyard-dmirocket chipyard-spiflashwrite chipyard-mmios chipyard-nocores chipyard-manyperipherals chipyard-chiplike" grouping["group-accels"]="chipyard-mempress chipyard-sha3 chipyard-hwacha chipyard-gemmini chipyard-manymmioaccels" grouping["group-constellation"]="chipyard-constellation" grouping["group-tracegen"]="tracegen tracegen-boom" @@ -53,6 +53,7 @@ mapping["chipyard-cva6"]=" CONFIG=CVA6Config" mapping["chipyard-ibex"]=" CONFIG=IbexConfig" mapping["chipyard-spiflashwrite"]=" CONFIG=SmallSPIFlashRocketConfig EXTRA_SIM_FLAGS='+spiflash0=${LOCAL_CHIPYARD_DIR}/tests/spiflash.img'" mapping["chipyard-manyperipherals"]=" CONFIG=ManyPeripheralsRocketConfig EXTRA_SIM_FLAGS='+spiflash0=${LOCAL_CHIPYARD_DIR}/tests/spiflash.img'" +mapping["chipyard-chiplike"]=" CONFIG=ChipLikeQuadRocketConfig verilog" mapping["chipyard-cloneboom"]=" CONFIG=Cloned64MegaBoomConfig verilog" mapping["chipyard-nocores"]=" CONFIG=NoCoresConfig verilog" mapping["tracegen"]=" CONFIG=NonBlockingTraceGenL2Config" diff --git a/generators/chipyard/src/main/scala/HarnessClocks.scala b/generators/chipyard/src/main/scala/HarnessClocks.scala index f973c292..4b3ebaa5 100644 --- a/generators/chipyard/src/main/scala/HarnessClocks.scala +++ b/generators/chipyard/src/main/scala/HarnessClocks.scala @@ -4,7 +4,7 @@ import chisel3._ import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} import freechips.rocketchip.diplomacy.{LazyModule} -import freechips.rocketchip.config.{Field, Parameters, Config} +import org.chipsalliance.cde.config.{Field, Parameters, Config} import freechips.rocketchip.util.{ResetCatchAndSync} import freechips.rocketchip.prci._ diff --git a/generators/chipyard/src/main/scala/config/ChipConfigs.scala b/generators/chipyard/src/main/scala/config/ChipConfigs.scala index 564e07d8..7f875584 100644 --- a/generators/chipyard/src/main/scala/config/ChipConfigs.scala +++ b/generators/chipyard/src/main/scala/config/ChipConfigs.scala @@ -4,7 +4,7 @@ import org.chipsalliance.cde.config.{Config} import freechips.rocketchip.diplomacy._ // A simple config demonstrating how to set up a basic chip in Chipyard -class ChipLikeRocketConfig extends Config( +class ChipLikeQuadRocketConfig extends Config( //================================== // Set up TestHarness //================================== diff --git a/generators/chipyard/src/main/scala/example/FlatChipTop.scala b/generators/chipyard/src/main/scala/example/FlatChipTop.scala index 9e142bda..c10baab4 100644 --- a/generators/chipyard/src/main/scala/example/FlatChipTop.scala +++ b/generators/chipyard/src/main/scala/example/FlatChipTop.scala @@ -2,7 +2,7 @@ package chipyard.example import chisel3._ -import freechips.rocketchip.config.{Field, Parameters} +import org.chipsalliance.cde.config.{Field, Parameters} import freechips.rocketchip.diplomacy._ import freechips.rocketchip.prci._ import freechips.rocketchip.util._ @@ -102,10 +102,10 @@ class FlatChipTop(implicit p: Parameters) extends LazyModule { //========================= // JTAG/Debug //========================= - val debug = system.module.debug.get + val debug = system.debug.get // We never use the PSDIO, so tie it off on-chip - system.module.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } - system.module.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := false.B } } + system.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) } + system.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := false.B } } // Tie off extTrigger debug.extTrigger.foreach { t => diff --git a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala index a45a4a3b..3954931e 100644 --- a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala +++ b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala @@ -4,7 +4,7 @@ import chisel3._ import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} -import freechips.rocketchip.config.{Field, Parameters} +import org.chipsalliance.cde.config.{Field, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.prci.{ClockSourceAtFreqFromPlusArg, ClockBundle, ClockBundleParameters} import freechips.rocketchip.util.{PlusArg} From 0ffc3c77708d1218f065bf23e152775f68957b50 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sat, 8 Apr 2023 17:19:25 -0700 Subject: [PATCH 9/9] Add some comments on harness/chiptop clocking APIs --- .../chipyard/src/main/scala/HarnessClocks.scala | 11 +++++++++++ .../src/main/scala/clocking/ClockBinders.scala | 7 +++++++ .../src/main/scala/clocking/TLClockDivider.scala | 2 ++ .../src/main/scala/clocking/TLClockSelector.scala | 2 ++ 4 files changed, 22 insertions(+) diff --git a/generators/chipyard/src/main/scala/HarnessClocks.scala b/generators/chipyard/src/main/scala/HarnessClocks.scala index 4b3ebaa5..c256caba 100644 --- a/generators/chipyard/src/main/scala/HarnessClocks.scala +++ b/generators/chipyard/src/main/scala/HarnessClocks.scala @@ -13,6 +13,9 @@ import chipyard.iobinders.HasIOBinders import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} import chipyard.HarnessClockInstantiatorKey + +// HarnessClockInstantiators are classes which generate clocks that drive +// TestHarness simulation models and any Clock inputs to the ChipTop trait HarnessClockInstantiator { val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty @@ -23,9 +26,13 @@ trait HarnessClockInstantiator { clockBundle } + // refClock is the clock generated by TestDriver that is + // passed to the TestHarness as its implicit clock 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 = { @@ -62,6 +69,10 @@ class DividerOnlyHarnessClockInstantiator extends HarnessClockInstantiator { } } +// The AbsoluteFreqHarnessClockInstantiator uses a Verilog blackbox to +// provide the precise requested frequency. +// This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim +// It is useful for VCS/Xcelium-driven RTL simulations class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator { def instantiateHarnessClocks(refClock: ClockBundle): Unit = { val sinks = _clockMap.map({ case (name, (freq, bundle)) => diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index a0dbe482..5a02277c 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -13,6 +13,9 @@ 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 @@ -52,6 +55,10 @@ class WithDividerOnlyClockGenerator extends OverrideLazyIOBinder({ } }) +// 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 class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({ (system: HasChipyardPRCI) => { diff --git a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala index 93a476c6..bc722799 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockDivider.scala @@ -13,6 +13,8 @@ import freechips.rocketchip.util.ElaborationArtefacts import testchipip._ +// This module adds a TileLink memory-mapped clock divider to the clock graph +// The output clock/reset pairs from this module should be synchronized later class TLClockDivider(address: BigInt, beatBytes: Int, divBits: Int = 8)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice(s"clk-div-ctrl", Nil) val clockNode = ClockGroupIdentityNode() diff --git a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala index 0893f120..06821ead 100644 --- a/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala +++ b/generators/chipyard/src/main/scala/clocking/TLClockSelector.scala @@ -36,6 +36,8 @@ case class ClockSelNode()(implicit valName: ValName) uFn = { u => ClockSinkParameters() } ) +// This module adds a TileLink memory-mapped clock mux for each downstream clock domain +// in the clock graph. The output clock/reset should be synchronized downstream class TLClockSelector(address: BigInt, beatBytes: Int)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice("clk-sel-ctrl", Nil) val tlNode = TLRegisterNode(Seq(AddressSet(address, 4096-1)), device, "reg/control", beatBytes=beatBytes)