108 lines
4.0 KiB
Scala
108 lines
4.0 KiB
Scala
//See LICENSE for license details.
|
|
|
|
package firesim.firesim
|
|
|
|
import chisel3._
|
|
|
|
import freechips.rocketchip.config.{Field, Config, Parameters}
|
|
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, RationalCrossing}
|
|
import freechips.rocketchip.subsystem._
|
|
import freechips.rocketchip.util.{ResetCatchAndSync}
|
|
|
|
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock}
|
|
import firesim.configs._
|
|
|
|
import boom.common.{WithRationalBoomTiles}
|
|
|
|
import chipyard.{BuildSystem, DigitalTop, DigitalTopModule}
|
|
import chipyard.config.ConfigValName._
|
|
import chipyard.iobinders.{IOBinders}
|
|
|
|
// WIP! This file is a sketch of one means of defining a multiclock target-design
|
|
// that can be simulated in FireSim, pending a canonicalized form in Chipyard.
|
|
//
|
|
// Note, the main prerequisite for supporting an additional clock domain in a
|
|
// FireSim simulation is to supply an additional clock parameter
|
|
// (RationalClock) to the clock bridge (RationalClockBridge). The bridge
|
|
// produces a vector of clocks, based on the provided parameter list, which you
|
|
// may use freely without further modifications to your target design.
|
|
|
|
case class FireSimClockParameters(additionalClocks: Seq[RationalClock]) {
|
|
def numClocks(): Int = additionalClocks.size + 1
|
|
}
|
|
case object FireSimClockKey extends Field[FireSimClockParameters](FireSimClockParameters(Seq()))
|
|
|
|
trait HasAdditionalClocks extends LazyModuleImp {
|
|
val clocks = IO(Vec(p(FireSimClockKey).numClocks, Input(Clock())))
|
|
}
|
|
|
|
// Presupposes only 1 or 2 clocks.
|
|
trait HasFireSimClockingImp extends HasAdditionalClocks {
|
|
val outer: HasTiles
|
|
val (tileClock, tileReset) = p(FireSimClockKey).additionalClocks.headOption match {
|
|
case Some(RationalClock(_, numer, denom)) if numer != denom => (clocks(1), ResetCatchAndSync(clocks(1), reset.toBool))
|
|
case None => (clocks.head, reset)
|
|
}
|
|
|
|
outer.tiles.foreach({ case tile =>
|
|
tile.module.clock := tileClock
|
|
tile.module.reset := tileReset
|
|
})
|
|
}
|
|
|
|
// Config Fragment
|
|
class WithSingleRationalTileDomain(multiplier: Int, divisor: Int) extends Config(
|
|
new WithRationalRocketTiles ++
|
|
new WithRationalBoomTiles ++
|
|
new Config((site, here, up) => {
|
|
case FireSimClockKey => FireSimClockParameters(Seq(RationalClock("TileDomain", multiplier, divisor)))
|
|
})
|
|
)
|
|
|
|
class HalfRateUncore extends WithSingleRationalTileDomain(2,1)
|
|
|
|
class WithFiresimMulticlockTop extends Config((site, here, up) => {
|
|
case BuildSystem => (p: Parameters) => LazyModule(new FiresimMulticlockTop()(p)).suggestName("system")
|
|
})
|
|
|
|
// Complete Config
|
|
class FireSimQuadRocketMulticlockConfig extends Config(
|
|
new HalfRateUncore ++
|
|
new WithFiresimMulticlockTop ++
|
|
new FireSimQuadRocketConfig)
|
|
|
|
// Top Definition
|
|
class FiresimMulticlockTop(implicit p: Parameters) extends chipyard.DigitalTop
|
|
{
|
|
override lazy val module = new FiresimMulticlockTopModule(this)
|
|
}
|
|
|
|
|
|
class FiresimMulticlockTopModule[+L <: DigitalTop](l: L) extends chipyard.DigitalTopModule(l) with HasFireSimClockingImp
|
|
|
|
// Harness Definition
|
|
class FireSimMulticlockPOC(implicit val p: Parameters) extends RawModule {
|
|
freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary())
|
|
val clockBridge = Module(new RationalClockBridge(p(FireSimClockKey).additionalClocks:_*))
|
|
val refClock = clockBridge.io.clocks.head
|
|
val reset = WireInit(false.B)
|
|
withClockAndReset(refClock, reset) {
|
|
// Instantiate multiple instances of the DUT to implement supernode
|
|
val targets = Seq.fill(p(NumNodes)) {
|
|
val lazyModule = p(BuildSystem)(p)
|
|
(lazyModule, Module(lazyModule.module))
|
|
}
|
|
val peekPokeBridge = PeekPokeBridge(refClock, reset)
|
|
// A Seq of partial functions that will instantiate the right bridge only
|
|
// if that Mixin trait is present in the target's class instance
|
|
//
|
|
// Apply each partial function to each DUT instance
|
|
for ((lazyModule, module) <- targets) {
|
|
p(IOBinders).values.foreach(f => f(lazyModule) ++ f(module))
|
|
}
|
|
targets.collect({ case (_, t: HasAdditionalClocks) => t.clocks := clockBridge.io.clocks })
|
|
}
|
|
}
|
|
|
|
|