Add ChipLikeRocketConfig ... improve harness clocking APIs
This commit is contained in:
@@ -154,7 +154,7 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({
|
|||||||
ports.map({ port =>
|
ports.map({ port =>
|
||||||
// DOC include start: HarnessClockInstantiatorEx
|
// DOC include start: HarnessClockInstantiatorEx
|
||||||
withClockAndReset(th.buildtopClock, th.buildtopReset) {
|
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 serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset)
|
||||||
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
|
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
|
||||||
system.serdesser.get,
|
system.serdesser.get,
|
||||||
|
|||||||
85
generators/chipyard/src/main/scala/HarnessClocks.scala
Normal file
85
generators/chipyard/src/main/scala/HarnessClocks.scala
Normal file
@@ -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
|
||||||
|
})
|
||||||
@@ -18,9 +18,11 @@ import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
|
|||||||
|
|
||||||
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
|
||||||
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
|
case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz
|
||||||
|
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator](() => new DividerOnlyHarnessClockInstantiator)
|
||||||
|
|
||||||
trait HasHarnessSignalReferences {
|
trait HasHarnessSignalReferences {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
|
val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()
|
||||||
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
// clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
|
||||||
var refClockFreq: Double = p(DefaultClockFrequencyKey)
|
var refClockFreq: Double = p(DefaultClockFrequencyKey)
|
||||||
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
|
def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz }
|
||||||
@@ -30,53 +32,6 @@ trait HasHarnessSignalReferences {
|
|||||||
def success: Bool
|
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 {
|
class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences {
|
||||||
val io = IO(new Bundle {
|
val io = IO(new Bundle {
|
||||||
val success = Output(Bool())
|
val success = Output(Bool())
|
||||||
@@ -96,7 +51,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign
|
|||||||
ApplyHarnessBinders(this, d.lazySystem, d.portMap)
|
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
|
buildtopClock := refClkBundle.clock
|
||||||
buildtopReset := WireInit(refClkBundle.reset)
|
buildtopReset := WireInit(refClkBundle.reset)
|
||||||
@@ -104,5 +59,5 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign
|
|||||||
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
|
||||||
implicitHarnessClockBundle.clock := clock
|
implicitHarnessClockBundle.clock := clock
|
||||||
implicitHarnessClockBundle.reset := reset
|
implicitHarnessClockBundle.reset := reset
|
||||||
p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle)
|
harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey}
|
|||||||
import freechips.rocketchip.prci._
|
import freechips.rocketchip.prci._
|
||||||
import freechips.rocketchip.diplomacy._
|
import freechips.rocketchip.diplomacy._
|
||||||
import freechips.rocketchip.subsystem._
|
import freechips.rocketchip.subsystem._
|
||||||
|
import freechips.rocketchip.tilelink._
|
||||||
import barstools.iocell.chisel._
|
import barstools.iocell.chisel._
|
||||||
|
|
||||||
class ClockWithFreq(val freqMHz: Double) extends Bundle {
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
36
generators/chipyard/src/main/scala/clocking/FakePLL.scala
Normal file
36
generators/chipyard/src/main/scala/clocking/FakePLL.scala
Normal file
@@ -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))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}: _*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}: _*)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ class TileClockGater(address: BigInt, beatBytes: Int, enable: Boolean)(implicit
|
|||||||
val sinkName = sinks(i)._1
|
val sinkName = sinks(i)._1
|
||||||
val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) }
|
val reg = withReset(sources(i).reset) { Module(new AsyncResetRegVec(w=1, init=1)) }
|
||||||
if (sinkName.contains("tile") && enable) {
|
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.clock := ClockGate(sources(i).clock, reg.io.q.asBool)
|
||||||
sinks(i)._2.reset := sources(i).reset
|
sinks(i)._2.reset := sources(i).reset
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -39,16 +39,16 @@ class TileResetSetter(address: BigInt, beatBytes: Int, tileNames: Seq[String], i
|
|||||||
}): _*)
|
}): _*)
|
||||||
|
|
||||||
val tileMap = tileNames.zipWithIndex.map({ case (n, 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, _)) =>
|
(clockNode.out zip clockNode.in).map { case ((o, _), (i, _)) =>
|
||||||
(o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) =>
|
(o.member.elements zip i.member.elements).foreach { case ((name, oD), (_, iD)) =>
|
||||||
oD.clock := iD.clock
|
oD.clock := iD.clock
|
||||||
oD.reset := iD.reset
|
oD.reset := iD.reset
|
||||||
for ((n, (rIn, rOut)) <- tileMap) {
|
for ((n, (rIn, rOut, addr)) <- tileMap) {
|
||||||
if (name.contains(n)) {
|
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
|
// Async because the reset coming out of the AsyncResetRegVec is
|
||||||
// clocked to the bus this is attached to, not the clock in this
|
// clocked to the bus this is attached to, not the clock in this
|
||||||
// clock bundle. We expect a ClockGroupResetSynchronizer downstream
|
// clock bundle. We expect a ClockGroupResetSynchronizer downstream
|
||||||
|
|||||||
Reference in New Issue
Block a user