1
0

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:
Henry Cook
2017-07-23 08:31:04 -07:00
committed by Yunsup Lee
parent f2002839eb
commit 01ca3efc2b
59 changed files with 1536 additions and 1632 deletions

View File

@ -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("")
}
}

View File

@ -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
})

View File

@ -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
}

View File

@ -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
}

View 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) }
}

View 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
}
}

View 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
}

View 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
}
}
}

View File

@ -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)
}

View 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
}

View 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))
}

View 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

View File

@ -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

View File

@ -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) }
}

View 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
}