Combine Coreplex and System Module Hierarchies (#875)
* coreplex collapse: peripherals now in coreplex * coreplex: better factoring of TLBusWrapper attachement points * diplomacy: allow monitorless :*= and :=* * rocket: don't connect monitors to tile tim slave ports * rename chip package to system * coreplex: only sbus has a splitter * TLFragmenter: Continuing my spot battles on requires without explanatory strings * pbus: toFixedWidthSingleBeatSlave * tilelink: more verbose requires * use the new system package for regression * sbus: add more explicit FIFO attachment points * delete leftover top-level utils * cleanup ResetVector and RTC
This commit is contained in:
@ -3,83 +3,133 @@
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tile.{ XLen, TileInterrupts}
|
||||
import freechips.rocketchip.rocket.PAddrBits
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Widths of various points in the SoC */
|
||||
case class TLBusConfig(beatBytes: Int)
|
||||
case object CBusConfig extends Field[TLBusConfig]
|
||||
case object L1toL2Config extends Field[TLBusConfig]
|
||||
/** Enumerates the three types of clock crossing between tiles and system bus */
|
||||
sealed trait CoreplexClockCrossing
|
||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||
case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends CoreplexClockCrossing
|
||||
|
||||
// These parameters apply to all caches, for now
|
||||
case object CacheBlockBytes extends Field[Int]
|
||||
|
||||
/** L2 Broadcast Hub configuration */
|
||||
case class BroadcastConfig(
|
||||
nTrackers: Int = 4,
|
||||
bufferless: Boolean = false)
|
||||
case object BroadcastConfig extends Field[BroadcastConfig]
|
||||
|
||||
/** L2 memory subsystem configuration */
|
||||
case class BankedL2Config(
|
||||
nMemoryChannels: Int = 1,
|
||||
nBanksPerChannel: Int = 1,
|
||||
coherenceManager: (Parameters, CoreplexNetwork) => (TLInwardNode, TLOutwardNode) = { case (q, _) =>
|
||||
implicit val p = q
|
||||
val BroadcastConfig(nTrackers, bufferless) = p(BroadcastConfig)
|
||||
val bh = LazyModule(new TLBroadcast(p(CacheBlockBytes), nTrackers, bufferless))
|
||||
val ww = LazyModule(new TLWidthWidget(p(L1toL2Config).beatBytes))
|
||||
ww.node :*= bh.node
|
||||
(bh.node, ww.node)
|
||||
}) {
|
||||
val nBanks = nMemoryChannels*nBanksPerChannel
|
||||
}
|
||||
case object BankedL2Config extends Field[BankedL2Config]
|
||||
|
||||
/** The file to read the BootROM contents from */
|
||||
case object BootROMFile extends Field[String]
|
||||
|
||||
trait HasCoreplexParameters {
|
||||
implicit val p: Parameters
|
||||
lazy val tilesParams = p(RocketTilesKey)
|
||||
lazy val sbusConfig = p(L1toL2Config)
|
||||
lazy val pbusConfig = p(CBusConfig)
|
||||
lazy val nTiles = tilesParams.size
|
||||
lazy val l2Config = p(BankedL2Config)
|
||||
def sbusBeatBytes = sbusConfig.beatBytes
|
||||
def sbusBlockBytes = p(CacheBlockBytes)
|
||||
def pbusBeatBytes = pbusConfig.beatBytes
|
||||
def pbusBlockBytes = sbusBlockBytes
|
||||
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
||||
lazy val dts = DTS(bindingTree)
|
||||
lazy val dtb = DTB(dts)
|
||||
lazy val json = JSON(bindingTree)
|
||||
}
|
||||
|
||||
case class CoreplexParameters(implicit val p: Parameters) extends HasCoreplexParameters
|
||||
|
||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope
|
||||
|
||||
abstract class BareCoreplexBundle[+L <: BareCoreplex](_outer: L) extends GenericParameterizedBundle(_outer) {
|
||||
abstract class BareCoreplexModule[+L <: BareCoreplex](_outer: L) extends LazyMultiIOModuleImp(_outer) {
|
||||
val outer = _outer
|
||||
implicit val p = outer.p
|
||||
}
|
||||
|
||||
abstract class BareCoreplexModule[+L <: BareCoreplex, +B <: BareCoreplexBundle[L]](_outer: L, _io: () => B) extends LazyModuleImp(_outer) {
|
||||
val outer = _outer
|
||||
val io = _io ()
|
||||
ElaborationArtefacts.add("graphml", outer.graphML)
|
||||
ElaborationArtefacts.add("dts", outer.dts)
|
||||
ElaborationArtefacts.add("json", outer.json)
|
||||
println(outer.dts)
|
||||
}
|
||||
|
||||
/** Base Coreplex class with no peripheral devices or ports added */
|
||||
abstract class BaseCoreplex(implicit p: Parameters) extends BareCoreplex
|
||||
with CoreplexNetwork
|
||||
with BankedL2CoherenceManagers {
|
||||
override lazy val module = new BaseCoreplexModule(this, () => new BaseCoreplexBundle(this))
|
||||
with HasInterruptBus
|
||||
with HasSystemBus
|
||||
with HasPeripheryBus
|
||||
with HasMemoryBus {
|
||||
override val module: BaseCoreplexModule[BaseCoreplex]
|
||||
|
||||
val root = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
val width = resources("width").map(_.value)
|
||||
Description("/", Map(
|
||||
"#address-cells" -> width,
|
||||
"#size-cells" -> width,
|
||||
"model" -> Seq(ResourceString(p(DTSModel))),
|
||||
"compatible" -> (p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-dev"))))
|
||||
}
|
||||
}
|
||||
|
||||
val soc = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
val width = resources("width").map(_.value)
|
||||
Description("soc", Map(
|
||||
"#address-cells" -> width,
|
||||
"#size-cells" -> width,
|
||||
"compatible" -> ((p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-soc")) :+ ResourceString("simple-bus")),
|
||||
"ranges" -> Nil))
|
||||
}
|
||||
}
|
||||
|
||||
val cpus = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
Description("cpus", Map(
|
||||
"#address-cells" -> Seq(ResourceInt(1)),
|
||||
"#size-cells" -> Seq(ResourceInt(0)),
|
||||
"timebase-frequency" -> Seq(ResourceInt(p(DTSTimebase)))))
|
||||
}
|
||||
}
|
||||
|
||||
// Make topManagers an Option[] so as to avoid LM name reflection evaluating it...
|
||||
lazy val topManagers = Some(ManagerUnification(sharedMemoryTLEdge.manager.managers))
|
||||
ResourceBinding {
|
||||
val managers = topManagers.get
|
||||
val max = managers.flatMap(_.address).map(_.max).max
|
||||
val width = ResourceInt((log2Ceil(max)+31) / 32)
|
||||
Resource(root, "width").bind(width)
|
||||
Resource(soc, "width").bind(width)
|
||||
Resource(cpus, "null").bind(ResourceString(""))
|
||||
|
||||
managers.foreach { case manager =>
|
||||
val value = manager.toResource
|
||||
manager.resources.foreach { case resource =>
|
||||
resource.bind(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BaseCoreplexBundle[+L <: BaseCoreplex](_outer: L) extends BareCoreplexBundle(_outer)
|
||||
with CoreplexNetworkBundle
|
||||
with BankedL2CoherenceManagersBundle
|
||||
abstract class BaseCoreplexModule[+L <: BaseCoreplex](_outer: L) extends BareCoreplexModule(_outer) {
|
||||
println("Generated Address Map")
|
||||
private val aw = (outer.sharedMemoryTLEdge.bundle.addressBits-1)/4 + 1
|
||||
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c %s"
|
||||
|
||||
class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle[L]](_outer: L, _io: () => B) extends BareCoreplexModule(_outer, _io)
|
||||
with CoreplexNetworkModule
|
||||
with BankedL2CoherenceManagersModule
|
||||
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
||||
value match {
|
||||
case r: ResourceAddress => List((path(1), r))
|
||||
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
|
||||
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
private val ranges = collect(Nil, outer.bindingTree).groupBy(_._2).toList.flatMap { case (key, seq) =>
|
||||
AddressRange.fromSets(key.address).map { r => (r, key.permissions, seq.map(_._1)) }
|
||||
}.sortBy(_._1)
|
||||
private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c), names) =>
|
||||
println(fmt.format(
|
||||
range.base,
|
||||
range.base+range.size,
|
||||
if (r) 'R' else ' ',
|
||||
if (w) 'W' else ' ',
|
||||
if (x) 'X' else ' ',
|
||||
if (c) 'C' else ' ',
|
||||
names.mkString(", ")))
|
||||
s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"names":[${names.map('"'+_+'"').mkString(",")}]}"""
|
||||
}
|
||||
println("")
|
||||
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${json.mkString(",")}]}""")
|
||||
|
||||
// Confirm that all of memory was described by DTS
|
||||
private val dtsRanges = AddressRange.unify(ranges.map(_._1))
|
||||
private val allRanges = AddressRange.unify(outer.topManagers.get.flatMap { m => AddressRange.fromSets(m.address) })
|
||||
|
||||
if (dtsRanges != allRanges) {
|
||||
println("Address map described by DTS differs from physical implementation:")
|
||||
AddressRange.subtract(allRanges, dtsRanges).foreach { case r =>
|
||||
println(s"\texists, but undescribed by DTS: ${r}")
|
||||
}
|
||||
AddressRange.subtract(dtsRanges, allRanges).foreach { case r =>
|
||||
println(s"\tdoes not exist, but described by DTS: ${r}")
|
||||
}
|
||||
println("")
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.devices.debug._
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
@ -15,6 +14,7 @@ import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class BaseCoreplexConfig extends Config ((site, here, up) => {
|
||||
// Tile parameters
|
||||
case PAddrBits => 32
|
||||
case PgLevels => if (site(XLen) == 64) 3 /* Sv39 */ else 2 /* Sv32 */
|
||||
case ASIdBits => 0
|
||||
@ -22,19 +22,26 @@ class BaseCoreplexConfig extends Config ((site, here, up) => {
|
||||
case ResetVectorBits => site(PAddrBits)
|
||||
case MaxHartIdBits => log2Up(site(RocketTilesKey).size)
|
||||
case BuildCore => (p: Parameters) => new Rocket()(p)
|
||||
case RocketTilesKey => Nil // Will be added by partial configs found below
|
||||
// Interconnect parameters
|
||||
case RocketCrossing => SynchronousCrossing()
|
||||
case RocketTilesKey => Nil
|
||||
case DMKey => DefaultDebugModuleConfig(site(XLen))
|
||||
case PLICKey => PLICParams()
|
||||
case ClintKey => ClintParams()
|
||||
case CBusConfig => TLBusConfig(beatBytes = site(XLen)/8)
|
||||
case L1toL2Config => TLBusConfig(beatBytes = site(XLen)/8) // increase for more PCIe bandwidth
|
||||
case BootROMFile => "./bootrom/bootrom.img"
|
||||
case BroadcastConfig => BroadcastConfig()
|
||||
case BankedL2Config => BankedL2Config()
|
||||
case BroadcastParams => BroadcastParams()
|
||||
case BankedL2Params => BankedL2Params()
|
||||
case SystemBusParams => SystemBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
|
||||
case PeripheryBusParams => PeripheryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
|
||||
case MemoryBusParams => MemoryBusParams(beatBytes = 8, blockBytes = site(CacheBlockBytes))
|
||||
case CacheBlockBytes => 64
|
||||
// Device parameters
|
||||
case DebugModuleParams => DefaultDebugModuleParams(site(XLen))
|
||||
case PLICParams => PLICParams()
|
||||
case ClintParams => ClintParams()
|
||||
// TileLink connection global parameters
|
||||
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
||||
case TLCombinationalCheck => false
|
||||
})
|
||||
|
||||
/* Composable partial function Configs to set individual parameters */
|
||||
|
||||
class WithNBigCores(n: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => {
|
||||
val big = RocketTileParams(
|
||||
@ -43,11 +50,11 @@ class WithNBigCores(n: Int) extends Config((site, here, up) => {
|
||||
mulEarlyOut = true,
|
||||
divEarlyOut = true))),
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(L1toL2Config).beatBytes*8,
|
||||
nMSHRs = 0,
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(L1toL2Config).beatBytes*8,
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
blockBytes = site(CacheBlockBytes))))
|
||||
List.fill(n)(big) ++ up(RocketTilesKey, site)
|
||||
}
|
||||
@ -59,14 +66,14 @@ class WithNSmallCores(n: Int) extends Config((site, here, up) => {
|
||||
core = RocketCoreParams(useVM = false, fpu = None),
|
||||
btb = None,
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(L1toL2Config).beatBytes*8,
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(L1toL2Config).beatBytes*8,
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
@ -75,12 +82,39 @@ class WithNSmallCores(n: Int) extends Config((site, here, up) => {
|
||||
}
|
||||
})
|
||||
|
||||
class WithNTinyCores(n: Int) extends Config((site, here, up) => {
|
||||
case XLen => 32
|
||||
case RocketTilesKey => {
|
||||
val tiny = RocketTileParams(
|
||||
core = RocketCoreParams(
|
||||
useVM = false,
|
||||
fpu = None,
|
||||
mulDiv = Some(MulDivParams(mulUnroll = 8))),
|
||||
btb = None,
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
nSets = 256, // 16Kb scratchpad
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes),
|
||||
scratch = Some(0x80000000L))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(SystemBusParams).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
blockBytes = site(CacheBlockBytes))))
|
||||
List.fill(n)(tiny) ++ up(RocketTilesKey, site)
|
||||
}
|
||||
})
|
||||
|
||||
class WithNBanksPerMemChannel(n: Int) extends Config((site, here, up) => {
|
||||
case BankedL2Config => up(BankedL2Config, site).copy(nBanksPerChannel = n)
|
||||
case BankedL2Params => up(BankedL2Params, site).copy(nBanksPerChannel = n)
|
||||
})
|
||||
|
||||
class WithNTrackersPerBank(n: Int) extends Config((site, here, up) => {
|
||||
case BroadcastConfig => up(BroadcastConfig, site).copy(nTrackers = n)
|
||||
case BroadcastParams => up(BroadcastParams, site).copy(nTrackers = n)
|
||||
})
|
||||
|
||||
// This is the number of icache sets for all Rocket tiles
|
||||
@ -112,7 +146,7 @@ class WithCacheBlockBytes(linesize: Int) extends Config((site, here, up) => {
|
||||
})
|
||||
|
||||
class WithBufferlessBroadcastHub extends Config((site, here, up) => {
|
||||
case BroadcastConfig => up(BroadcastConfig, site).copy(bufferless = true)
|
||||
case BroadcastParams => up(BroadcastParams, site).copy(bufferless = true)
|
||||
})
|
||||
|
||||
/**
|
||||
@ -128,12 +162,10 @@ class WithBufferlessBroadcastHub extends Config((site, here, up) => {
|
||||
* DO NOT use this configuration.
|
||||
*/
|
||||
class WithStatelessBridge extends Config((site, here, up) => {
|
||||
case BankedL2Config => up(BankedL2Config, site).copy(coherenceManager = { case (q, _) =>
|
||||
case BankedL2Params => up(BankedL2Params, site).copy(coherenceManager = { case (q, _) =>
|
||||
implicit val p = q
|
||||
val cork = LazyModule(new TLCacheCork(unsafe = true))
|
||||
val ww = LazyModule(new TLWidthWidget(p(L1toL2Config).beatBytes))
|
||||
ww.node :*= cork.node
|
||||
(cork.node, ww.node)
|
||||
(cork.node, cork.node)
|
||||
})
|
||||
})
|
||||
|
||||
@ -208,7 +240,7 @@ class WithFPUWithoutDivSqrt extends Config((site, here, up) => {
|
||||
})
|
||||
|
||||
class WithBootROMFile(bootROMFile: String) extends Config((site, here, up) => {
|
||||
case BootROMFile => bootROMFile
|
||||
case BootROMParams => up(BootROMParams, site).copy(contentFileName = bootROMFile)
|
||||
})
|
||||
|
||||
class WithSynchronousRocketTiles extends Config((site, here, up) => {
|
||||
@ -223,3 +255,49 @@ class WithRationalRocketTiles extends Config((site, here, up) => {
|
||||
case RocketCrossing => RationalCrossing()
|
||||
})
|
||||
|
||||
class WithEdgeDataBits(dataBits: Int) extends Config((site, here, up) => {
|
||||
case MemoryBusParams => up(MemoryBusParams, site).copy(beatBytes = dataBits/8)
|
||||
case ExtIn => up(ExtIn, site).copy(beatBytes = dataBits/8)
|
||||
|
||||
})
|
||||
|
||||
class WithJtagDTM extends Config ((site, here, up) => {
|
||||
case IncludeJtagDTM => true
|
||||
})
|
||||
|
||||
class WithNoPeripheryArithAMO extends Config ((site, here, up) => {
|
||||
case PeripheryBusParams => up(PeripheryBusParams, site).copy(arithmetic = false)
|
||||
})
|
||||
|
||||
class WithNBitPeripheryBus(nBits: Int) extends Config ((site, here, up) => {
|
||||
case PeripheryBusParams => up(PeripheryBusParams, site).copy(beatBytes = nBits/8)
|
||||
})
|
||||
|
||||
class WithoutTLMonitors extends Config ((site, here, up) => {
|
||||
case TLMonitorBuilder => (args: TLMonitorArgs) => None
|
||||
})
|
||||
|
||||
class WithNExtTopInterrupts(nExtInts: Int) extends Config((site, here, up) => {
|
||||
case NExtTopInterrupts => nExtInts
|
||||
})
|
||||
|
||||
class WithRTCPeriod(nCycles: Int) extends Config((site, here, up) => {
|
||||
case RTCPeriod => nCycles
|
||||
})
|
||||
|
||||
class WithNMemoryChannels(n: Int) extends Config((site, here, up) => {
|
||||
case BankedL2Params => up(BankedL2Params, site).copy(nMemoryChannels = n)
|
||||
})
|
||||
|
||||
class WithExtMemSize(n: Long) extends Config((site, here, up) => {
|
||||
case ExtMem => up(ExtMem, site).copy(size = n)
|
||||
})
|
||||
|
||||
class WithDTS(model: String, compat: Seq[String]) extends Config((site, here, up) => {
|
||||
case DTSModel => model
|
||||
case DTSCompat => compat
|
||||
})
|
||||
|
||||
class WithTimebase(hertz: BigInt) extends Config((site, here, up) => {
|
||||
case DTSTimebase => hertz
|
||||
})
|
||||
|
@ -1,190 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.rocket.PAddrBits
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
trait CoreplexNetwork extends HasCoreplexParameters {
|
||||
val module: CoreplexNetworkModule
|
||||
def bindingTree: ResourceMap
|
||||
|
||||
// TODO: do we need one of these? val cbus = LazyModule(new TLXbar) // Locally-visible peripheral devices
|
||||
val sbus = LazyModule(new TLXbar) // Globally-visible high-bandwidth devices
|
||||
val pbus = LazyModule(new TLXbar) // Globally-visible low-bandwidth devices
|
||||
val tile_splitter = LazyModule(new TLSplitter) // Allows cycle-free connection to external networks
|
||||
val int_xbar = LazyModule(new IntXbar) // Interrupt crossbar
|
||||
|
||||
val mmio = TLOutputNode() // Exernal memory-mapped IO slaves
|
||||
val mmioInt = IntInputNode() // Exernal devices' interrupts
|
||||
val l2in = TLInputNode() // External masters talking to the frontside of the shared cache
|
||||
val l2out = TLOutputNode() // External slaves hanging off the backside of the shared cache
|
||||
|
||||
int_xbar.intnode := mmioInt
|
||||
|
||||
// Allows a variable number of inputs from outside to the Xbar
|
||||
private val l2in_buffer = LazyModule(new TLBuffer)
|
||||
private val l2in_fifo = LazyModule(new TLFIFOFixer)
|
||||
sbus.node :=* l2in_fifo.node
|
||||
sbus.node :=* tile_splitter.node
|
||||
l2in_fifo.node :=* l2in_buffer.node
|
||||
l2in_buffer.node :=* l2in
|
||||
|
||||
private val l2out_buffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none))
|
||||
l2out :*= l2out_buffer.node
|
||||
l2out_buffer.node :*= sbus.node
|
||||
|
||||
pbus.node :=
|
||||
TLBuffer()(
|
||||
TLAtomicAutomata(arithmetic = true)( // disable once TLB uses TL2 metadata
|
||||
TLWidthWidget(sbusBeatBytes)(
|
||||
sbus.node)))
|
||||
|
||||
mmio :=
|
||||
TLWidthWidget(sbusBeatBytes)(
|
||||
sbus.node)
|
||||
|
||||
val root = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
val width = resources("width").map(_.value)
|
||||
Description("/", Map(
|
||||
"#address-cells" -> width,
|
||||
"#size-cells" -> width,
|
||||
"model" -> Seq(ResourceString(p(DTSModel))),
|
||||
"compatible" -> (p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-dev"))))
|
||||
}
|
||||
}
|
||||
|
||||
val soc = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
val width = resources("width").map(_.value)
|
||||
Description("soc", Map(
|
||||
"#address-cells" -> width,
|
||||
"#size-cells" -> width,
|
||||
"compatible" -> ((p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-soc")) :+ ResourceString("simple-bus")),
|
||||
"ranges" -> Nil))
|
||||
}
|
||||
}
|
||||
|
||||
val cpus = new Device {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
Description("cpus", Map(
|
||||
"#address-cells" -> Seq(ResourceInt(1)),
|
||||
"#size-cells" -> Seq(ResourceInt(0)),
|
||||
"timebase-frequency" -> Seq(ResourceInt(p(DTSTimebase)))))
|
||||
}
|
||||
}
|
||||
|
||||
// Make topManagers an Option[] so as to avoid LM name reflection evaluating it...
|
||||
lazy val topManagers = Some(ManagerUnification(tile_splitter.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil)))
|
||||
ResourceBinding {
|
||||
val managers = topManagers.get
|
||||
val max = managers.flatMap(_.address).map(_.max).max
|
||||
val width = ResourceInt((log2Ceil(max)+31) / 32)
|
||||
Resource(root, "width").bind(width)
|
||||
Resource(soc, "width").bind(width)
|
||||
Resource(cpus, "null").bind(ResourceString(""))
|
||||
|
||||
managers.foreach { case manager =>
|
||||
val value = manager.toResource
|
||||
manager.resources.foreach { case resource =>
|
||||
resource.bind(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait CoreplexNetworkBundle extends HasCoreplexParameters {
|
||||
val outer: CoreplexNetwork
|
||||
|
||||
val mmio = outer.mmio.bundleOut
|
||||
val interrupts = outer.mmioInt.bundleIn
|
||||
val l2in = outer.l2in.bundleIn
|
||||
val l2out = outer.l2out.bundleOut
|
||||
}
|
||||
|
||||
trait CoreplexNetworkModule extends HasCoreplexParameters {
|
||||
val outer: CoreplexNetwork
|
||||
val io: CoreplexNetworkBundle
|
||||
|
||||
println("Generated Address Map")
|
||||
private val aw = (outer.p(PAddrBits)-1)/4 + 1
|
||||
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c %s"
|
||||
|
||||
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
|
||||
value match {
|
||||
case r: ResourceAddress => List((path(1), r))
|
||||
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
|
||||
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
|
||||
case _ => Nil
|
||||
}
|
||||
}
|
||||
private val ranges = collect(Nil, outer.bindingTree).groupBy(_._2).toList.flatMap { case (key, seq) =>
|
||||
AddressRange.fromSets(key.address).map { r => (r, key.permissions, seq.map(_._1)) }
|
||||
}.sortBy(_._1)
|
||||
private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c), names) =>
|
||||
println(fmt.format(
|
||||
range.base,
|
||||
range.base+range.size,
|
||||
if (r) 'R' else ' ',
|
||||
if (w) 'W' else ' ',
|
||||
if (x) 'X' else ' ',
|
||||
if (c) 'C' else ' ',
|
||||
names.mkString(", ")))
|
||||
s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"names":[${names.map('"'+_+'"').mkString(",")}]}"""
|
||||
}
|
||||
println("")
|
||||
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${json.mkString(",")}]}""")
|
||||
|
||||
// Confirm that all of memory was described by DTS
|
||||
private val dtsRanges = AddressRange.unify(ranges.map(_._1))
|
||||
private val allRanges = AddressRange.unify(outer.topManagers.get.flatMap { m => AddressRange.fromSets(m.address) })
|
||||
|
||||
if (dtsRanges != allRanges) {
|
||||
println("Address map described by DTS differs from physical implementation:")
|
||||
AddressRange.subtract(allRanges, dtsRanges).foreach { case r =>
|
||||
println(s"\texists, but undescribed by DTS: ${r}")
|
||||
}
|
||||
AddressRange.subtract(dtsRanges, allRanges).foreach { case r =>
|
||||
println(s"\tdoes not exist, but described by DTS: ${r}")
|
||||
}
|
||||
println("")
|
||||
}
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
trait BankedL2CoherenceManagers extends CoreplexNetwork {
|
||||
val module: BankedL2CoherenceManagersModule
|
||||
|
||||
require (isPow2(l2Config.nMemoryChannels) || l2Config.nMemoryChannels == 0)
|
||||
require (isPow2(l2Config.nBanksPerChannel))
|
||||
require (isPow2(sbusBlockBytes))
|
||||
|
||||
private val (in, out) = l2Config.coherenceManager(p, this)
|
||||
private val mask = ~BigInt((l2Config.nBanks-1) * sbusBlockBytes)
|
||||
val mem = Seq.tabulate(l2Config.nMemoryChannels) { channel =>
|
||||
val node = TLOutputNode()
|
||||
for (bank <- 0 until l2Config.nBanksPerChannel) {
|
||||
val offset = (bank * l2Config.nMemoryChannels) + channel
|
||||
in := sbus.node
|
||||
node := TLFilter(AddressSet(offset * sbusBlockBytes, mask))(out)
|
||||
}
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
trait BankedL2CoherenceManagersBundle extends CoreplexNetworkBundle {
|
||||
val outer: BankedL2CoherenceManagers
|
||||
val mem = HeterogeneousBag(outer.mem.map(_.bundleOut))
|
||||
}
|
||||
|
||||
trait BankedL2CoherenceManagersModule extends CoreplexNetworkModule {
|
||||
val outer: BankedL2CoherenceManagers
|
||||
val io: BankedL2CoherenceManagersBundle
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.diplomacy.LazyModule
|
||||
import freechips.rocketchip.tilelink._
|
||||
|
||||
trait HasISPPort extends CoreplexNetwork {
|
||||
val module: HasISPPortModule
|
||||
|
||||
// TODO: use ChipLink instead of AsyncTileLink
|
||||
val isp_in = TLAsyncInputNode()
|
||||
val isp_out = TLAsyncOutputNode()
|
||||
|
||||
private val out_xbar = LazyModule(new TLXbar)
|
||||
private val out_nums = LazyModule(new TLNodeNumberer)
|
||||
private val out_async = LazyModule(new TLAsyncCrossingSource)
|
||||
out_xbar.node :=* tile_splitter.node
|
||||
out_nums.node :*= out_xbar.node
|
||||
out_async.node :*= out_nums.node
|
||||
isp_out :*= out_async.node
|
||||
|
||||
private val in_async = LazyModule(new TLAsyncCrossingSink)
|
||||
in_async.node :=* isp_in
|
||||
sbus.node :=* in_async.node
|
||||
}
|
||||
|
||||
trait HasISPPortBundle extends CoreplexNetworkBundle {
|
||||
val outer: HasISPPort
|
||||
|
||||
// TODO: move to IO(...) in Module?
|
||||
val isp_in = outer.isp_in.bundleIn
|
||||
val isp_out = outer.isp_out.bundleOut
|
||||
}
|
||||
|
||||
trait HasISPPortModule extends CoreplexNetworkModule {
|
||||
val outer: HasISPPort
|
||||
val io: HasISPPortBundle
|
||||
}
|
85
src/main/scala/coreplex/InterruptBus.scala
Normal file
85
src/main/scala/coreplex/InterruptBus.scala
Normal file
@ -0,0 +1,85 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
|
||||
/** Collects interrupts from internal and external devices and feeds them into the PLIC */
|
||||
class InterruptBusWrapper(implicit p: Parameters) {
|
||||
|
||||
val int_bus = LazyModule(new IntXbar) // Interrupt crossbar
|
||||
|
||||
private def synchronize(sync: Int): IntInwardNode = {
|
||||
val asyncXing = LazyModule(new IntXing(sync))
|
||||
int_bus.intnode := asyncXing.intnode
|
||||
asyncXing.intnode
|
||||
}
|
||||
|
||||
def fromAsync: IntInwardNode = synchronize(3)
|
||||
def fromRational: IntInwardNode = synchronize(1)
|
||||
def fromSync: IntInwardNode = int_bus.intnode
|
||||
def toPLIC: IntOutwardNode = int_bus.intnode
|
||||
}
|
||||
|
||||
trait HasInterruptBus {
|
||||
implicit val p: Parameters
|
||||
val ibus = new InterruptBusWrapper
|
||||
}
|
||||
|
||||
/** Specifies the number of external interrupts */
|
||||
case object NExtTopInterrupts extends Field[Int]
|
||||
|
||||
/** This trait adds externally driven interrupts to the system.
|
||||
* However, it should not be used directly; instead one of the below
|
||||
* synchronization wiring child traits should be used.
|
||||
*/
|
||||
abstract trait HasExtInterrupts extends HasInterruptBus {
|
||||
private val device = new Device with DeviceInterrupts {
|
||||
def describe(resources: ResourceBindings): Description = {
|
||||
Description("soc/external-interrupts", describeInterrupts(resources))
|
||||
}
|
||||
}
|
||||
|
||||
val nExtInterrupts = p(NExtTopInterrupts)
|
||||
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
||||
}
|
||||
|
||||
/** This trait should be used if the External Interrupts have NOT
|
||||
* already been synchronized to the Periphery (PLIC) Clock.
|
||||
*/
|
||||
trait HasAsyncExtInterrupts extends HasExtInterrupts {
|
||||
if (nExtInterrupts > 0) {
|
||||
ibus.fromAsync := extInterrupts
|
||||
}
|
||||
}
|
||||
|
||||
/** This trait can be used if the External Interrupts have already been synchronized
|
||||
* to the Periphery (PLIC) Clock.
|
||||
*/
|
||||
trait HasSyncExtInterrupts extends HasExtInterrupts {
|
||||
if (nExtInterrupts > 0) {
|
||||
ibus.fromSync := extInterrupts
|
||||
}
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasExtInterruptsBundle {
|
||||
val interrupts: UInt
|
||||
|
||||
def tieOffInterrupts(dummy: Int = 1) {
|
||||
interrupts := UInt(0)
|
||||
}
|
||||
}
|
||||
|
||||
/** This trait performs the translation from a UInt IO into Diplomatic Interrupts.
|
||||
* The wiring must be done in the concrete LazyModuleImp.
|
||||
*/
|
||||
trait HasExtInterruptsModuleImp extends LazyMultiIOModuleImp with HasExtInterruptsBundle {
|
||||
val outer: HasExtInterrupts
|
||||
val interrupts = IO(UInt(INPUT, width = outer.nExtInterrupts))
|
||||
|
||||
outer.extInterrupts.bundleIn.flatten.zipWithIndex.foreach { case(o, i) => o := interrupts(i) }
|
||||
}
|
75
src/main/scala/coreplex/MemoryBus.scala
Normal file
75
src/main/scala/coreplex/MemoryBus.scala
Normal file
@ -0,0 +1,75 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
// TODO: applies to all caches, for now
|
||||
case object CacheBlockBytes extends Field[Int]
|
||||
|
||||
/** L2 Broadcast Hub configuration */
|
||||
case class BroadcastParams(
|
||||
nTrackers: Int = 4,
|
||||
bufferless: Boolean = false)
|
||||
case object BroadcastParams extends Field[BroadcastParams]
|
||||
|
||||
/** L2 memory subsystem configuration */
|
||||
case class BankedL2Params(
|
||||
nMemoryChannels: Int = 1,
|
||||
nBanksPerChannel: Int = 1,
|
||||
coherenceManager: (Parameters, HasMemoryBus) => (TLInwardNode, TLOutwardNode) = { case (q, _) =>
|
||||
implicit val p = q
|
||||
val MemoryBusParams(_, blockBytes, _, _) = p(MemoryBusParams)
|
||||
val BroadcastParams(nTrackers, bufferless) = p(BroadcastParams)
|
||||
val bh = LazyModule(new TLBroadcast(blockBytes, nTrackers, bufferless))
|
||||
(bh.node, bh.node)
|
||||
}) {
|
||||
val nBanks = nMemoryChannels*nBanksPerChannel
|
||||
}
|
||||
case object BankedL2Params extends Field[BankedL2Params]
|
||||
|
||||
/** Parameterization of the memory-side bus created for each memory channel */
|
||||
case class MemoryBusParams(
|
||||
beatBytes: Int,
|
||||
blockBytes: Int,
|
||||
masterBuffering: BufferParams = BufferParams.none,
|
||||
slaveBuffering: BufferParams = BufferParams.none
|
||||
) extends TLBusParams
|
||||
|
||||
case object MemoryBusParams extends Field[MemoryBusParams]
|
||||
|
||||
/** Wrapper for creating TL nodes from a bus connected to the back of each mem channel */
|
||||
class MemoryBus(params: MemoryBusParams)(implicit p: Parameters) extends TLBusWrapper(params)(p) {
|
||||
def fromCoherenceManager: TLInwardNode = inwardBufNode
|
||||
def toDRAMController: TLOutwardNode = outwardBufNode
|
||||
def toVariableWidthSlave: TLOutwardNode = outwardFragNode
|
||||
}
|
||||
|
||||
trait HasMemoryBus extends HasSystemBus with HasPeripheryBus with HasInterruptBus {
|
||||
private val mbusParams = p(MemoryBusParams)
|
||||
private val MemoryBusParams(beatBytes, blockBytes, _, _) = mbusParams
|
||||
private val l2Params = p(BankedL2Params)
|
||||
val BankedL2Params(nMemoryChannels, nBanksPerChannel, coherenceManager) = l2Params
|
||||
val nBanks = l2Params.nBanks
|
||||
val cacheBlockBytes = blockBytes
|
||||
|
||||
require (isPow2(nMemoryChannels) || nMemoryChannels == 0)
|
||||
require (isPow2(nBanksPerChannel))
|
||||
require (isPow2(blockBytes))
|
||||
|
||||
private val (in, out) = coherenceManager(p, this)
|
||||
private val mask = ~BigInt((nBanks-1) * blockBytes)
|
||||
val memBuses = Seq.tabulate(nMemoryChannels) { channel =>
|
||||
val mbus = new MemoryBus(mbusParams)
|
||||
for (bank <- 0 until nBanksPerChannel) {
|
||||
val offset = (bank * nMemoryChannels) + channel
|
||||
in := sbus.toMemoryBus
|
||||
mbus.fromCoherenceManager := TLFilter(AddressSet(offset * blockBytes, mask))(out)
|
||||
}
|
||||
mbus
|
||||
}
|
||||
}
|
48
src/main/scala/coreplex/PeripheryBus.scala
Normal file
48
src/main/scala/coreplex/PeripheryBus.scala
Normal file
@ -0,0 +1,48 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
|
||||
case class PeripheryBusParams(
|
||||
beatBytes: Int,
|
||||
blockBytes: Int,
|
||||
masterBuffering: BufferParams = BufferParams.default,
|
||||
slaveBuffering: BufferParams = BufferParams.none,
|
||||
arithmetic: Boolean = true
|
||||
) extends TLBusParams {
|
||||
}
|
||||
|
||||
case object PeripheryBusParams extends Field[PeripheryBusParams]
|
||||
|
||||
class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends TLBusWrapper(params) {
|
||||
def toFixedWidthSingleBeatSlave(widthBytes: Int) = {
|
||||
TLFragmenter(widthBytes, params.blockBytes)(outwardWWNode)
|
||||
}
|
||||
|
||||
def toLargeBurstSlave(maxXferBytes: Int) = {
|
||||
TLFragmenter(params.beatBytes, maxXferBytes)(outwardBufNode)
|
||||
}
|
||||
|
||||
val fromSystemBus: TLInwardNode = {
|
||||
val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic))
|
||||
inwardBufNode := atomics.node
|
||||
atomics.node
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides buses that serve as attachment points,
|
||||
* for use in traits that connect individual devices or external ports.
|
||||
*/
|
||||
trait HasPeripheryBus extends HasSystemBus {
|
||||
private val pbusParams = p(PeripheryBusParams)
|
||||
val pbusBeatBytes = pbusParams.beatBytes
|
||||
|
||||
val pbus = new PeripheryBus(pbusParams)
|
||||
|
||||
// The peripheryBus hangs off of systemBus; here we convert TL-UH -> TL-UL
|
||||
pbus.fromSystemBus := sbus.toPeripheryBus
|
||||
}
|
261
src/main/scala/coreplex/Ports.scala
Normal file
261
src/main/scala/coreplex/Ports.scala
Normal file
@ -0,0 +1,261 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.amba.axi4._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Specifies the size and width of external memory ports */
|
||||
case class MasterPortParams(
|
||||
base: Long,
|
||||
size: Long,
|
||||
beatBytes: Int,
|
||||
idBits: Int,
|
||||
maxXferBytes: Int = 256,
|
||||
executable: Boolean = true)
|
||||
case object ExtMem extends Field[MasterPortParams]
|
||||
case object ExtBus extends Field[MasterPortParams]
|
||||
|
||||
/** Specifies the width of external slave ports */
|
||||
case class SlavePortParams(beatBytes: Int, idBits: Int, sourceBits: Int)
|
||||
case object ExtIn extends Field[SlavePortParams]
|
||||
|
||||
///// The following traits add ports to the sytem, in some cases converting to different interconnect standards
|
||||
|
||||
/** Adds a port to the system intended to master an AXI4 DRAM controller. */
|
||||
trait HasMasterAXI4MemPort extends HasMemoryBus {
|
||||
val module: HasMasterAXI4MemPortModuleImp
|
||||
|
||||
private val params = p(ExtMem)
|
||||
private val device = new MemoryDevice
|
||||
|
||||
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(nMemoryChannels) { channel =>
|
||||
val base = AddressSet(params.base, params.size-1)
|
||||
val filter = AddressSet(channel * cacheBlockBytes, ~((nMemoryChannels-1) * cacheBlockBytes))
|
||||
|
||||
AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = base.intersect(filter).toList,
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED, // cacheable
|
||||
executable = true,
|
||||
supportsWrite = TransferSizes(1, cacheBlockBytes),
|
||||
supportsRead = TransferSizes(1, cacheBlockBytes),
|
||||
interleavedId = Some(0))), // slave does not interleave read responses
|
||||
beatBytes = params.beatBytes)
|
||||
})
|
||||
|
||||
val converter = LazyModule(new TLToAXI4(params.beatBytes))
|
||||
val trim = LazyModule(new AXI4IdIndexer(params.idBits))
|
||||
val yank = LazyModule(new AXI4UserYanker)
|
||||
val buffer = LazyModule(new AXI4Buffer)
|
||||
|
||||
memBuses.map(_.toDRAMController).foreach { case node =>
|
||||
converter.node := node
|
||||
trim.node := converter.node
|
||||
yank.node := trim.node
|
||||
buffer.node := yank.node
|
||||
mem_axi4 := buffer.node
|
||||
}
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasMasterAXI4MemPortBundle {
|
||||
implicit val p: Parameters
|
||||
val mem_axi4: HeterogeneousBag[AXI4Bundle]
|
||||
val nMemoryChannels: Int
|
||||
def connectSimAXIMem(dummy: Int = 1) = {
|
||||
if (nMemoryChannels > 0) Module(LazyModule(new SimAXIMem(nMemoryChannels)).module).io.axi4 <> mem_axi4
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasMasterAXI4MemPortModuleImp extends LazyMultiIOModuleImp with HasMasterAXI4MemPortBundle {
|
||||
val outer: HasMasterAXI4MemPort
|
||||
val mem_axi4 = IO(outer.mem_axi4.bundleOut)
|
||||
val nMemoryChannels = outer.nMemoryChannels
|
||||
}
|
||||
|
||||
/** Adds a AXI4 port to the system intended to master an MMIO device bus */
|
||||
trait HasMasterAXI4MMIOPort extends HasSystemBus {
|
||||
private val params = p(ExtBus)
|
||||
private val device = new SimpleBus("mmio", Nil)
|
||||
val mmio_axi4 = AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = List(AddressSet(BigInt(params.base), params.size-1)),
|
||||
resources = device.ranges,
|
||||
executable = params.executable,
|
||||
supportsWrite = TransferSizes(1, params.maxXferBytes),
|
||||
supportsRead = TransferSizes(1, params.maxXferBytes))),
|
||||
beatBytes = params.beatBytes)))
|
||||
|
||||
mmio_axi4 :=
|
||||
AXI4Buffer()(
|
||||
AXI4UserYanker()(
|
||||
AXI4Deinterleaver(sbus.blockBytes)(
|
||||
AXI4IdIndexer(params.idBits)(
|
||||
TLToAXI4(params.beatBytes)(
|
||||
sbus.toFixedWidthPorts)))))
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasMasterAXI4MMIOPortBundle {
|
||||
implicit val p: Parameters
|
||||
val mmio_axi4: HeterogeneousBag[AXI4Bundle]
|
||||
def connectSimAXIMMIO(dummy: Int = 1) {
|
||||
Module(LazyModule(new SimAXIMem(1, 4096)).module).io.axi4 <> mmio_axi4
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasMasterAXI4MMIOPortModuleImp extends LazyMultiIOModuleImp with HasMasterAXI4MMIOPortBundle {
|
||||
val outer: HasMasterAXI4MMIOPort
|
||||
val mmio_axi4 = IO(outer.mmio_axi4.bundleOut)
|
||||
}
|
||||
|
||||
/** Adds an AXI4 port to the system intended to be a slave on an MMIO device bus */
|
||||
trait HasSlaveAXI4Port extends HasSystemBus {
|
||||
private val params = p(ExtIn)
|
||||
val l2FrontendAXI4Node = AXI4BlindInputNode(Seq(AXI4MasterPortParameters(
|
||||
masters = Seq(AXI4MasterParameters(
|
||||
name = "AXI4 periphery",
|
||||
id = IdRange(0, 1 << params.idBits))))))
|
||||
|
||||
private val fifoBits = 1
|
||||
sbus.fromSyncPorts() :=
|
||||
TLWidthWidget(params.beatBytes)(
|
||||
AXI4ToTL()(
|
||||
AXI4UserYanker(Some(1 << (params.sourceBits - fifoBits - 1)))(
|
||||
AXI4Fragmenter()(
|
||||
AXI4IdIndexer(fifoBits)(
|
||||
l2FrontendAXI4Node)))))
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasSlaveAXI4PortBundle {
|
||||
implicit val p: Parameters
|
||||
val l2_frontend_bus_axi4: HeterogeneousBag[AXI4Bundle]
|
||||
def tieOffAXI4SlavePort(dummy: Int = 1) {
|
||||
l2_frontend_bus_axi4.foreach { l2_axi4 =>
|
||||
l2_axi4.ar.valid := Bool(false)
|
||||
l2_axi4.aw.valid := Bool(false)
|
||||
l2_axi4.w .valid := Bool(false)
|
||||
l2_axi4.r .ready := Bool(true)
|
||||
l2_axi4.b .ready := Bool(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasSlaveAXI4PortModuleImp extends LazyMultiIOModuleImp with HasSlaveAXI4PortBundle {
|
||||
val outer: HasSlaveAXI4Port
|
||||
val l2_frontend_bus_axi4 = IO(outer.l2FrontendAXI4Node.bundleIn)
|
||||
}
|
||||
|
||||
/** Adds a TileLink port to the system intended to master an MMIO device bus */
|
||||
trait HasMasterTLMMIOPort extends HasSystemBus {
|
||||
private val params = p(ExtBus)
|
||||
private val device = new SimpleBus("mmio", Nil)
|
||||
val mmio_tl = TLBlindOutputNode(Seq(TLManagerPortParameters(
|
||||
managers = Seq(TLManagerParameters(
|
||||
address = List(AddressSet(BigInt(params.base), params.size-1)),
|
||||
resources = device.ranges,
|
||||
executable = params.executable,
|
||||
supportsGet = TransferSizes(1, sbus.blockBytes),
|
||||
supportsPutFull = TransferSizes(1, sbus.blockBytes),
|
||||
supportsPutPartial = TransferSizes(1, sbus.blockBytes))),
|
||||
beatBytes = params.beatBytes)))
|
||||
|
||||
mmio_tl :=
|
||||
TLBuffer()(
|
||||
TLSourceShrinker(1 << params.idBits)(
|
||||
sbus.toFixedWidthPorts))
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasMasterTLMMIOPortBundle {
|
||||
implicit val p: Parameters
|
||||
val mmio_tl: HeterogeneousBag[TLBundle]
|
||||
def tieOffTLMMIO(dummy: Int = 1) {
|
||||
mmio_tl.foreach { tl =>
|
||||
tl.a.ready := Bool(true)
|
||||
tl.b.valid := Bool(false)
|
||||
tl.c.ready := Bool(true)
|
||||
tl.d.valid := Bool(false)
|
||||
tl.e.ready := Bool(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasMasterTLMMIOPortModuleImp extends LazyMultiIOModuleImp with HasMasterTLMMIOPortBundle {
|
||||
val outer: HasMasterTLMMIOPort
|
||||
val mmio_tl = IO(outer.mmio_tl.bundleOut)
|
||||
}
|
||||
|
||||
/** Adds an TL port to the system intended to be a slave on an MMIO device bus.
|
||||
* NOTE: this port is NOT allowed to issue Acquires.
|
||||
*/
|
||||
trait HasSlaveTLPort extends HasSystemBus {
|
||||
private val params = p(ExtIn)
|
||||
val l2FrontendTLNode = TLBlindInputNode(Seq(TLClientPortParameters(
|
||||
clients = Seq(TLClientParameters(
|
||||
name = "Front Port (TL)",
|
||||
sourceId = IdRange(0, 1 << params.idBits))))))
|
||||
|
||||
sbus.fromSyncPorts() :=
|
||||
TLSourceShrinker(1 << params.sourceBits)(
|
||||
TLWidthWidget(params.beatBytes)(
|
||||
l2FrontendTLNode))
|
||||
}
|
||||
|
||||
/** Common io name and methods for propagating or tying off the port bundle */
|
||||
trait HasSlaveTLPortBundle {
|
||||
implicit val p: Parameters
|
||||
val l2_frontend_bus_tl: HeterogeneousBag[TLBundle]
|
||||
def tieOffSlaveTLPort(dummy: Int = 1) {
|
||||
l2_frontend_bus_tl.foreach { tl =>
|
||||
tl.a.valid := Bool(false)
|
||||
tl.b.ready := Bool(true)
|
||||
tl.c.valid := Bool(false)
|
||||
tl.d.ready := Bool(true)
|
||||
tl.e.valid := Bool(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasSlaveTLPortModuleImp extends LazyMultiIOModuleImp with HasSlaveTLPortBundle {
|
||||
val outer: HasSlaveTLPort
|
||||
val l2_frontend_bus_tl = IO(outer.l2FrontendTLNode.bundleIn)
|
||||
}
|
||||
|
||||
/** Memory with AXI port for use in elaboratable test harnesses. */
|
||||
class SimAXIMem(channels: Int, forceSize: BigInt = 0)(implicit p: Parameters) extends LazyModule {
|
||||
val config = p(ExtMem)
|
||||
val totalSize = if (forceSize > 0) forceSize else BigInt(config.size)
|
||||
val size = totalSize / channels
|
||||
require(totalSize % channels == 0)
|
||||
|
||||
val node = AXI4BlindInputNode(Seq.fill(channels) {
|
||||
AXI4MasterPortParameters(Seq(AXI4MasterParameters(
|
||||
name = "dut",
|
||||
id = IdRange(0, 1 << config.idBits)
|
||||
)))
|
||||
})
|
||||
|
||||
for (i <- 0 until channels) {
|
||||
val sram = LazyModule(new AXI4RAM(AddressSet(0, size-1), beatBytes = config.beatBytes))
|
||||
sram.node := AXI4Buffer()(AXI4Fragmenter()(node))
|
||||
}
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new Bundle {
|
||||
val axi4 = node.bundleIn
|
||||
}
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config.Field
|
||||
import freechips.rocketchip.devices.debug._
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case object PLICKey extends Field[PLICParams]
|
||||
case object ClintKey extends Field[ClintParams]
|
||||
|
||||
trait CoreplexRISCVPlatform extends CoreplexNetwork {
|
||||
val module: CoreplexRISCVPlatformModule
|
||||
|
||||
val debug = LazyModule(new TLDebugModule())
|
||||
debug.node := TLFragmenter(pbusBeatBytes, pbusBlockBytes)(pbus.node)
|
||||
|
||||
val plic = LazyModule(new TLPLIC(p(PLICKey)))
|
||||
plic.node := TLFragmenter(pbusBeatBytes, pbusBlockBytes)(pbus.node)
|
||||
plic.intnode := int_xbar.intnode
|
||||
|
||||
val clint = LazyModule(new CoreplexLocalInterrupter(p(ClintKey)))
|
||||
clint.node := TLFragmenter(pbusBeatBytes, pbusBlockBytes)(pbus.node)
|
||||
|
||||
lazy val dts = DTS(bindingTree)
|
||||
lazy val dtb = DTB(dts)
|
||||
lazy val json = JSON(bindingTree)
|
||||
}
|
||||
|
||||
trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle {
|
||||
val outer: CoreplexRISCVPlatform
|
||||
|
||||
val debug = new ClockedDMIIO().flip
|
||||
val rtcToggle = Bool(INPUT)
|
||||
val resetVector = UInt(INPUT, p(ResetVectorBits))
|
||||
val ndreset = Bool(OUTPUT)
|
||||
val dmactive = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
trait CoreplexRISCVPlatformModule extends CoreplexNetworkModule {
|
||||
val outer: CoreplexRISCVPlatform
|
||||
val io: CoreplexRISCVPlatformBundle
|
||||
|
||||
outer.debug.module.io.dmi <> io.debug
|
||||
// TODO in inheriting traits: Set this to something meaningful, e.g. "component is in reset or powered down"
|
||||
val nDebugComponents = outer.debug.intnode.bundleOut.size
|
||||
outer.debug.module.io.ctrl.debugUnavail := Vec.fill(nDebugComponents){Bool(false)}
|
||||
io.dmactive := outer.debug.module.io.ctrl.dmactive
|
||||
io.ndreset := outer.debug.module.io.ctrl.ndreset
|
||||
|
||||
// Synchronize the rtc into the coreplex
|
||||
val rtcSync = ShiftRegister(io.rtcToggle, 3)
|
||||
val rtcLast = Reg(init = Bool(false), next=rtcSync)
|
||||
outer.clint.module.io.rtcTick := Reg(init = Bool(false), next=(rtcSync & (~rtcLast)))
|
||||
|
||||
println(outer.dts)
|
||||
ElaborationArtefacts.add("dts", outer.dts)
|
||||
ElaborationArtefacts.add("json", outer.json)
|
||||
}
|
24
src/main/scala/coreplex/RTC.scala
Normal file
24
src/main/scala/coreplex/RTC.scala
Normal file
@ -0,0 +1,24 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Field
|
||||
import freechips.rocketchip.diplomacy.LazyMultiIOModuleImp
|
||||
import freechips.rocketchip.devices.tilelink.HasPeripheryClint
|
||||
|
||||
/** Real-time clock is based on RTCPeriod relative to system clock.
|
||||
*/
|
||||
case object RTCPeriod extends Field[Option[Int]]
|
||||
|
||||
trait HasRTCModuleImp extends LazyMultiIOModuleImp {
|
||||
val outer: HasPeripheryClint
|
||||
private val internalPeriod: Option[Int] = outer.p(RTCPeriod)
|
||||
require(internalPeriod.isDefined, "RTCPeriod is not defined")
|
||||
|
||||
// Use the static period to toggle the RTC
|
||||
val (rtc_counter, _) = Counter(true.B, internalPeriod.get)
|
||||
val tick = rtc_counter(log2Up(internalPeriod.get)-1)
|
||||
|
||||
outer.clint.module.io.rtcTick := tick
|
||||
}
|
14
src/main/scala/coreplex/ResetVector.scala
Normal file
14
src/main/scala/coreplex/ResetVector.scala
Normal file
@ -0,0 +1,14 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.tile.ResetVectorBits
|
||||
|
||||
/** A single place for all tiles to find out the reset vector */
|
||||
trait HasResetVectorWire {
|
||||
implicit val p: Parameters
|
||||
val resetVectorBits = p(ResetVectorBits)
|
||||
val global_reset_vector = Wire(UInt(width = resetVectorBits))
|
||||
}
|
130
src/main/scala/coreplex/RocketCoreplex.scala
Normal file
130
src/main/scala/coreplex/RocketCoreplex.scala
Normal file
@ -0,0 +1,130 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case object RocketTilesKey extends Field[Seq[RocketTileParams]]
|
||||
case object RocketCrossing extends Field[CoreplexClockCrossing]
|
||||
|
||||
trait HasRocketTiles extends HasSystemBus
|
||||
with HasPeripheryBus
|
||||
with HasPeripheryPLIC
|
||||
with HasPeripheryClint
|
||||
with HasPeripheryDebug {
|
||||
val module: HasRocketTilesModuleImp
|
||||
|
||||
private val crossing = p(RocketCrossing)
|
||||
private val tileParams = p(RocketTilesKey)
|
||||
val nRocketTiles = tileParams.size
|
||||
|
||||
// Handle interrupts to be routed directly into each tile
|
||||
// TODO: figure out how to merge the localIntNodes and coreIntXbar below
|
||||
val localIntCounts = tileParams.map(_.core.nLocalInterrupts)
|
||||
val localIntNodes = tileParams map { t =>
|
||||
(t.core.nLocalInterrupts > 0).option(LazyModule(new IntXbar).intnode)
|
||||
}
|
||||
|
||||
// Make a wrapper for each tile that will wire it to coreplex devices and crossbars,
|
||||
// according to the specified type of clock crossing.
|
||||
val wiringTuple = localIntNodes.zip(tileParams).zipWithIndex
|
||||
val wrappers: Seq[RocketTileWrapper] = wiringTuple.map { case ((lip, c), i) =>
|
||||
val pWithExtra = p.alterPartial {
|
||||
case TileKey => c
|
||||
case BuildRoCC => c.rocc
|
||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||
}
|
||||
|
||||
val wrapper = crossing match {
|
||||
case SynchronousCrossing(params) => {
|
||||
val wrapper = LazyModule(new SyncRocketTile(c, i)(pWithExtra))
|
||||
sbus.fromSyncTiles(params) :=* wrapper.masterNode
|
||||
wrapper.slaveNode :*= pbus.bufferToSlaves
|
||||
wrapper
|
||||
}
|
||||
case AsynchronousCrossing(depth, sync) => {
|
||||
val wrapper = LazyModule(new AsyncRocketTile(c, i)(pWithExtra))
|
||||
sbus.fromAsyncTiles(depth, sync) :=* wrapper.masterNode
|
||||
wrapper.slaveNode :*= pbus.toAsyncSlaves(sync)
|
||||
wrapper
|
||||
}
|
||||
case RationalCrossing(direction) => {
|
||||
val wrapper = LazyModule(new RationalRocketTile(c, i)(pWithExtra))
|
||||
val sink = LazyModule(new TLRationalCrossingSink(direction))
|
||||
val source = LazyModule(new TLRationalCrossingSource)
|
||||
sbus.fromRationalTiles(direction) :=* wrapper.masterNode
|
||||
wrapper.slaveNode :*= pbus.toRationalSlaves
|
||||
wrapper
|
||||
}
|
||||
}
|
||||
|
||||
// Local Interrupts must be synchronized to the core clock
|
||||
// before being passed into this module.
|
||||
// This allows faster latency for interrupts which are already synchronized.
|
||||
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
||||
// so may or may not need to be synchronized depending on the Tile's crossing type.
|
||||
// Debug interrupt is definitely asynchronous in all cases.
|
||||
val asyncIntXbar = LazyModule(new IntXbar)
|
||||
asyncIntXbar.intnode := debug.intnode // debug
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
|
||||
val periphIntXbar = LazyModule(new IntXbar)
|
||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
||||
periphIntXbar.intnode := plic.intnode // meip
|
||||
if (c.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
|
||||
val coreIntXbar = LazyModule(new IntXbar)
|
||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
|
||||
wrapper
|
||||
}
|
||||
}
|
||||
|
||||
class ClockedRocketTileInputs(implicit val p: Parameters) extends ParameterizedBundle
|
||||
with HasExternallyDrivenTileConstants
|
||||
with Clocked
|
||||
|
||||
trait HasRocketTilesBundle {
|
||||
val rocket_tile_inputs: Vec[ClockedRocketTileInputs]
|
||||
}
|
||||
|
||||
trait HasRocketTilesModuleImp extends LazyMultiIOModuleImp
|
||||
with HasRocketTilesBundle
|
||||
with HasResetVectorWire
|
||||
with HasPeripheryDebugModuleImp {
|
||||
val outer: HasRocketTiles
|
||||
val rocket_tile_inputs = Wire(Vec(outer.nRocketTiles, new ClockedRocketTileInputs))
|
||||
|
||||
// Unconditionally wire up the non-diplomatic tile inputs
|
||||
outer.wrappers.map(_.module).zip(rocket_tile_inputs).foreach { case(tile, wire) =>
|
||||
tile.clock := wire.clock
|
||||
tile.reset := wire.reset
|
||||
tile.io.hartid := wire.hartid
|
||||
tile.io.resetVector := wire.resetVector
|
||||
}
|
||||
|
||||
// Default values for tile inputs; may be overriden in other traits
|
||||
rocket_tile_inputs.zipWithIndex.foreach { case(wire, i) =>
|
||||
wire.clock := clock
|
||||
wire.reset := reset
|
||||
wire.hartid := UInt(i)
|
||||
wire.resetVector := global_reset_vector
|
||||
}
|
||||
}
|
||||
|
||||
class RocketCoreplex(implicit p: Parameters) extends BaseCoreplex
|
||||
with HasRocketTiles {
|
||||
override lazy val module = new RocketCoreplexModule(this)
|
||||
}
|
||||
|
||||
class RocketCoreplexModule[+L <: RocketCoreplex](_outer: L) extends BaseCoreplexModule(_outer)
|
||||
with HasRocketTilesModuleImp
|
@ -1,21 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
|
||||
import freechips.rocketchip.config.Parameters
|
||||
|
||||
class RocketPlex(implicit p: Parameters) extends BaseCoreplex
|
||||
with CoreplexRISCVPlatform
|
||||
with HasRocketTiles {
|
||||
override lazy val module = new RocketPlexModule(this, () => new RocketPlexBundle(this))
|
||||
}
|
||||
|
||||
class RocketPlexBundle[+L <: RocketPlex](_outer: L) extends BaseCoreplexBundle(_outer)
|
||||
with CoreplexRISCVPlatformBundle
|
||||
with HasRocketTilesBundle
|
||||
|
||||
class RocketPlexModule[+L <: RocketPlex, +B <: RocketPlexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io)
|
||||
with CoreplexRISCVPlatformModule
|
||||
with HasRocketTilesModule
|
@ -1,135 +0,0 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Field
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.rocket._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
sealed trait CoreplexClockCrossing
|
||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
||||
case class AsynchronousCrossing(depth: Int, sync: Int = 2) extends CoreplexClockCrossing
|
||||
|
||||
case object RocketTilesKey extends Field[Seq[RocketTileParams]]
|
||||
case object RocketCrossing extends Field[CoreplexClockCrossing]
|
||||
|
||||
trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
val module: HasRocketTilesModule
|
||||
|
||||
private val crossing = p(RocketCrossing)
|
||||
val tileParams = p(RocketTilesKey)
|
||||
|
||||
// Handle interrupts to be routed directly into each tile
|
||||
val localIntNodes = tileParams map { t =>
|
||||
(t.core.nLocalInterrupts > 0).option(IntInputNode())
|
||||
}
|
||||
|
||||
// Make a function for each tile that will wire it to coreplex devices and crossbars,
|
||||
// according to the specified type of clock crossing.
|
||||
val wiringTuple = localIntNodes.zip(tileParams).zipWithIndex
|
||||
val rocketWires: Seq[HasRocketTilesBundle => Unit] = wiringTuple.map { case ((lip, c), i) =>
|
||||
val pWithExtra = p.alterPartial {
|
||||
case TileKey => c
|
||||
case BuildRoCC => c.rocc
|
||||
case SharedMemoryTLEdge => tile_splitter.node.edgesIn(0)
|
||||
}
|
||||
|
||||
val asyncIntXbar = LazyModule(new IntXbar)
|
||||
val periphIntXbar = LazyModule(new IntXbar)
|
||||
val coreIntXbar = LazyModule(new IntXbar)
|
||||
|
||||
// Local Interrupts must be synchronized to the core clock
|
||||
// before being passed into this module.
|
||||
// This allows faster latency for interrupts which are already synchronized.
|
||||
// The CLINT and PLIC outputs interrupts that are synchronous to the periphery clock,
|
||||
// so may or may not need to be synchronized depending on the Tile's
|
||||
// synchronization type.
|
||||
// Debug interrupt is definitely asynchronous in all cases.
|
||||
|
||||
asyncIntXbar.intnode := debug.intnode // debug
|
||||
periphIntXbar.intnode := clint.intnode // msip+mtip
|
||||
periphIntXbar.intnode := plic.intnode // meip
|
||||
if (c.core.useVM) periphIntXbar.intnode := plic.intnode // seip
|
||||
lip.foreach { coreIntXbar.intnode := _ } // lip
|
||||
|
||||
crossing match {
|
||||
case SynchronousCrossing(params) => {
|
||||
val wrapper = LazyModule(new SyncRocketTile(c, i)(pWithExtra))
|
||||
val buffer = LazyModule(new TLBuffer(params))
|
||||
val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
buffer.node :=* wrapper.masterNode
|
||||
fixer.node :=* buffer.node
|
||||
tile_splitter.node :=* fixer.node
|
||||
wrapper.slaveNode :*= pbus.node
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
(io: HasRocketTilesBundle) => {
|
||||
// leave clock as default (simpler for hierarchical PnR)
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
wrapper.module.io.resetVector := io.resetVector
|
||||
}
|
||||
}
|
||||
case AsynchronousCrossing(depth, sync) => {
|
||||
val wrapper = LazyModule(new AsyncRocketTile(c, i)(pWithExtra))
|
||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
sink.node :=* wrapper.masterNode
|
||||
fixer.node :=* sink.node
|
||||
tile_splitter.node :=* fixer.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
source.node :*= pbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
wrapper.module.reset := io.tcrs(i).reset
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
wrapper.module.io.resetVector := io.resetVector
|
||||
}
|
||||
}
|
||||
case RationalCrossing(direction) => {
|
||||
val wrapper = LazyModule(new RationalRocketTile(c, i)(pWithExtra))
|
||||
val sink = LazyModule(new TLRationalCrossingSink(direction))
|
||||
val source = LazyModule(new TLRationalCrossingSource)
|
||||
val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
sink.node :=* wrapper.masterNode
|
||||
fixer.node :=* sink.node
|
||||
tile_splitter.node :=* fixer.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.asyncIntNode := asyncIntXbar.intnode
|
||||
wrapper.periphIntNode := periphIntXbar.intnode
|
||||
wrapper.coreIntNode := coreIntXbar.intnode
|
||||
source.node :*= pbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
wrapper.module.reset := io.tcrs(i).reset
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
wrapper.module.io.resetVector := io.resetVector
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait HasRocketTilesBundle extends CoreplexRISCVPlatformBundle {
|
||||
val outer: HasRocketTiles
|
||||
val local_interrupts = HeterogeneousBag(outer.localIntNodes.flatten.map(_.bundleIn))
|
||||
val tcrs = Vec(p(RocketTilesKey).size, new Bundle {
|
||||
val clock = Clock(INPUT)
|
||||
val reset = Bool(INPUT)
|
||||
})
|
||||
}
|
||||
|
||||
trait HasRocketTilesModule extends CoreplexRISCVPlatformModule {
|
||||
val outer: HasRocketTiles
|
||||
val io: HasRocketTilesBundle
|
||||
outer.rocketWires.foreach { _(io) }
|
||||
}
|
97
src/main/scala/coreplex/SystemBus.scala
Normal file
97
src/main/scala/coreplex/SystemBus.scala
Normal file
@ -0,0 +1,97 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.coreplex
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case class SystemBusParams(
|
||||
beatBytes: Int,
|
||||
blockBytes: Int,
|
||||
masterBuffering: BufferParams = BufferParams.default,
|
||||
slaveBuffering: BufferParams = BufferParams.flow // TODO should be BufferParams.none on BCE
|
||||
) extends TLBusParams
|
||||
|
||||
case object SystemBusParams extends Field[SystemBusParams]
|
||||
|
||||
class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWrapper(params) {
|
||||
private val master_splitter = LazyModule(new TLSplitter) // Allows cycle-free connection to external networks
|
||||
inwardBufNode :=* master_splitter.node
|
||||
|
||||
protected def inwardSplitNode: TLInwardNode = master_splitter.node
|
||||
protected def outwardSplitNode: TLOutwardNode = master_splitter.node
|
||||
|
||||
private val tile_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
private val port_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all))
|
||||
master_splitter.node :=* tile_fixer.node
|
||||
master_splitter.node :=* port_fixer.node
|
||||
|
||||
def toSplitSlaves: TLOutwardNode = outwardSplitNode
|
||||
|
||||
val toPeripheryBus: TLOutwardNode = outwardWWNode
|
||||
|
||||
val toMemoryBus: TLOutwardNode = outwardNode
|
||||
|
||||
def fromAsyncMasters(depth: Int = 8, sync: Int = 3): TLAsyncInwardNode = {
|
||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
inwardNode :=* sink.node
|
||||
sink.node
|
||||
}
|
||||
|
||||
def fromSyncTiles(params: BufferParams): TLInwardNode = {
|
||||
val buf = LazyModule(new TLBuffer(params))
|
||||
tile_fixer.node :=* buf.node
|
||||
buf.node
|
||||
}
|
||||
|
||||
def fromRationalTiles(dir: RationalDirection): TLRationalInwardNode = {
|
||||
val sink = LazyModule(new TLRationalCrossingSink(direction = dir))
|
||||
tile_fixer.node :=* sink.node
|
||||
sink.node
|
||||
}
|
||||
|
||||
def fromAsyncTiles(depth: Int, sync: Int): TLAsyncInwardNode = {
|
||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
tile_fixer.node :=* sink.node
|
||||
sink.node
|
||||
}
|
||||
|
||||
def fromSyncPorts(params: BufferParams = BufferParams.default): TLInwardNode = {
|
||||
val buffer = LazyModule(new TLBuffer(params))
|
||||
port_fixer.node :=* buffer.node
|
||||
buffer.node
|
||||
}
|
||||
|
||||
def fromSyncFIFOMaster(params: BufferParams = BufferParams.default): TLInwardNode = fromSyncPorts(params)
|
||||
|
||||
def fromAsyncPorts(depth: Int = 8, sync: Int = 3): TLAsyncInwardNode = {
|
||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
port_fixer.node :=* sink.node
|
||||
sink.node
|
||||
}
|
||||
|
||||
def fromAsyncFIFOMaster(depth: Int = 8, sync: Int = 3): TLAsyncInwardNode = fromAsyncPorts(depth, sync)
|
||||
|
||||
def fromRationalPorts(dir: RationalDirection): TLRationalInwardNode = {
|
||||
val sink = LazyModule(new TLRationalCrossingSink(dir))
|
||||
port_fixer.node :=* sink.node
|
||||
sink.node
|
||||
}
|
||||
|
||||
def fromRationalFIFOMaster(dir: RationalDirection): TLRationalInwardNode = fromRationalPorts(dir)
|
||||
}
|
||||
|
||||
/** Provides buses that serve as attachment points,
|
||||
* for use in traits that connect individual devices or external ports.
|
||||
*/
|
||||
trait HasSystemBus extends HasInterruptBus {
|
||||
private val sbusParams = p(SystemBusParams)
|
||||
val sbusBeatBytes = sbusParams.beatBytes
|
||||
|
||||
val sbus = new SystemBus(sbusParams)
|
||||
|
||||
def sharedMemoryTLEdge: TLEdge = sbus.edgesIn.head
|
||||
}
|
Reference in New Issue
Block a user