coreplex => subsystem
This commit is contained in:
107
src/main/scala/subsystem/BaseSubsystem.scala
Normal file
107
src/main/scala/subsystem/BaseSubsystem.scala
Normal file
@ -0,0 +1,107 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** BareSubsystem is the root class for creating a subsystem */
|
||||
abstract class BareSubsystem(implicit p: Parameters) extends LazyModule with BindingScope {
|
||||
lazy val dts = DTS(bindingTree)
|
||||
lazy val dtb = DTB(dts)
|
||||
lazy val json = JSON(bindingTree)
|
||||
}
|
||||
|
||||
abstract class BareSubsystemModule[+L <: BareSubsystem](_outer: L) extends LazyModuleImp(_outer) {
|
||||
val outer = _outer
|
||||
ElaborationArtefacts.add("graphml", outer.graphML)
|
||||
ElaborationArtefacts.add("dts", outer.dts)
|
||||
ElaborationArtefacts.add("json", outer.json)
|
||||
ElaborationArtefacts.add("plusArgs", PlusArgArtefacts.serialize_cHeader)
|
||||
println(outer.dts)
|
||||
}
|
||||
|
||||
/** Base Subsystem class with no peripheral devices or ports added */
|
||||
abstract class BaseSubsystem(implicit p: Parameters) extends BareSubsystem
|
||||
with HasInterruptBus
|
||||
with HasSystemBus
|
||||
with HasPeripheryBus
|
||||
with HasMemoryBus {
|
||||
override val module: BaseSubsystemModule[BaseSubsystem]
|
||||
|
||||
// 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)
|
||||
val model = p(DTSModel)
|
||||
val compat = p(DTSCompat)
|
||||
val devCompat = (model +: compat).map(s => ResourceString(s + "-dev"))
|
||||
val socCompat = (model +: compat).map(s => ResourceString(s + "-soc"))
|
||||
devCompat.foreach { Resource(ResourceAnchors.root, "compat").bind(_) }
|
||||
socCompat.foreach { Resource(ResourceAnchors.soc, "compat").bind(_) }
|
||||
Resource(ResourceAnchors.root, "model").bind(ResourceString(model))
|
||||
Resource(ResourceAnchors.root, "width").bind(width)
|
||||
Resource(ResourceAnchors.soc, "width").bind(width)
|
||||
Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1))
|
||||
|
||||
managers.foreach { case manager =>
|
||||
val value = manager.toResource
|
||||
manager.resources.foreach { case resource =>
|
||||
resource.bind(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BaseSubsystemModule[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModule(_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%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, a), names) =>
|
||||
println(fmt.format(
|
||||
range.base,
|
||||
range.base+range.size,
|
||||
if (a) 'A' else ' ',
|
||||
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],"a":[$a],"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("")
|
||||
}
|
||||
}
|
304
src/main/scala/subsystem/Configs.scala
Normal file
304
src/main/scala/subsystem/Configs.scala
Normal file
@ -0,0 +1,304 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
// See LICENSE.Berkeley for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.devices.debug._
|
||||
import freechips.rocketchip.devices.tilelink._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.rocket._
|
||||
import freechips.rocketchip.tile._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class BaseSubsystemConfig extends Config ((site, here, up) => {
|
||||
// Tile parameters
|
||||
case PgLevels => if (site(XLen) == 64) 3 /* Sv39 */ else 2 /* Sv32 */
|
||||
case XLen => 64 // Applies to all cores
|
||||
case MaxHartIdBits => log2Up(site(RocketTilesKey).size)
|
||||
case BuildCore => (p: Parameters) => new Rocket()(p)
|
||||
// Interconnect parameters
|
||||
case SystemBusKey => SystemBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
|
||||
case PeripheryBusKey => PeripheryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
|
||||
case MemoryBusKey => MemoryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes))
|
||||
// Additional device Parameters
|
||||
case ErrorParams => ErrorParams(Seq(AddressSet(0x3000, 0xfff)), maxAtomic=site(XLen)/8, maxTransfer=4096)
|
||||
case BootROMParams => BootROMParams(contentFileName = "./bootrom/bootrom.img")
|
||||
case DebugModuleParams => DefaultDebugModuleParams(site(XLen))
|
||||
})
|
||||
|
||||
/* Composable partial function Configs to set individual parameters */
|
||||
|
||||
class WithNBigCores(n: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => {
|
||||
val big = RocketTileParams(
|
||||
core = RocketCoreParams(mulDiv = Some(MulDivParams(
|
||||
mulUnroll = 8,
|
||||
mulEarlyOut = true,
|
||||
divEarlyOut = true))),
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
blockBytes = site(CacheBlockBytes))))
|
||||
List.tabulate(n)(i => big.copy(hartId = i))
|
||||
}
|
||||
})
|
||||
|
||||
class WithNSmallCores(n: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => {
|
||||
val small = RocketTileParams(
|
||||
core = RocketCoreParams(useVM = false, fpu = None),
|
||||
btb = None,
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
blockBytes = site(CacheBlockBytes))))
|
||||
List.tabulate(n)(i => small.copy(hartId = i))
|
||||
}
|
||||
})
|
||||
|
||||
class With1TinyCore extends Config((site, here, up) => {
|
||||
case XLen => 32
|
||||
case RocketTilesKey => List(RocketTileParams(
|
||||
core = RocketCoreParams(
|
||||
useVM = false,
|
||||
fpu = None,
|
||||
mulDiv = Some(MulDivParams(mulUnroll = 8))),
|
||||
btb = None,
|
||||
dcache = Some(DCacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
nSets = 256, // 16Kb scratchpad
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
nMSHRs = 0,
|
||||
blockBytes = site(CacheBlockBytes),
|
||||
scratch = Some(0x80000000L))),
|
||||
icache = Some(ICacheParams(
|
||||
rowBits = site(SystemBusKey).beatBits,
|
||||
nSets = 64,
|
||||
nWays = 1,
|
||||
nTLBEntries = 4,
|
||||
blockBytes = site(CacheBlockBytes)))))
|
||||
case RocketCrossingKey => List(RocketCrossingParams(
|
||||
crossingType = SynchronousCrossing(),
|
||||
master = TileMasterPortParams(cork = Some(true))
|
||||
))
|
||||
})
|
||||
|
||||
class WithNBanksPerMemChannel(n: Int) extends Config((site, here, up) => {
|
||||
case BankedL2Key => up(BankedL2Key, site).copy(nBanksPerChannel = n)
|
||||
})
|
||||
|
||||
class WithNTrackersPerBank(n: Int) extends Config((site, here, up) => {
|
||||
case BroadcastKey => up(BroadcastKey, site).copy(nTrackers = n)
|
||||
})
|
||||
|
||||
// This is the number of icache sets for all Rocket tiles
|
||||
class WithL1ICacheSets(sets: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(icache = r.icache.map(_.copy(nSets = sets))) }
|
||||
})
|
||||
|
||||
// This is the number of icache sets for all Rocket tiles
|
||||
class WithL1DCacheSets(sets: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(dcache = r.dcache.map(_.copy(nSets = sets))) }
|
||||
})
|
||||
|
||||
class WithL1ICacheWays(ways: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(icache = r.icache.map(_.copy(nWays = ways)))
|
||||
}
|
||||
})
|
||||
|
||||
class WithL1DCacheWays(ways: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(dcache = r.dcache.map(_.copy(nWays = ways)))
|
||||
}
|
||||
})
|
||||
|
||||
class WithCacheBlockBytes(linesize: Int) extends Config((site, here, up) => {
|
||||
case CacheBlockBytes => linesize
|
||||
})
|
||||
|
||||
class WithBufferlessBroadcastHub extends Config((site, here, up) => {
|
||||
case BroadcastKey => up(BroadcastKey, site).copy(bufferless = true)
|
||||
})
|
||||
|
||||
/**
|
||||
* WARNING!!! IGNORE AT YOUR OWN PERIL!!!
|
||||
*
|
||||
* There is a very restrictive set of conditions under which the stateless
|
||||
* bridge will function properly. There can only be a single tile. This tile
|
||||
* MUST use the blocking data cache (L1D_MSHRS == 0) and MUST NOT have an
|
||||
* uncached channel capable of writes (i.e. a RoCC accelerator).
|
||||
*
|
||||
* This is because the stateless bridge CANNOT generate probes, so if your
|
||||
* system depends on coherence between channels in any way,
|
||||
* DO NOT use this configuration.
|
||||
*/
|
||||
class WithIncoherentTiles extends Config((site, here, up) => {
|
||||
case RocketCrossingKey => up(RocketCrossingKey, site) map { r =>
|
||||
r.copy(master = r.master.copy(cork = Some(true)))
|
||||
}
|
||||
case BankedL2Key => up(BankedL2Key, site).copy(coherenceManager = { subsystem =>
|
||||
val ww = LazyModule(new TLWidthWidget(subsystem.sbusBeatBytes)(subsystem.p))
|
||||
(ww.node, ww.node, () => None)
|
||||
})
|
||||
})
|
||||
|
||||
class WithRV32 extends Config((site, here, up) => {
|
||||
case XLen => 32
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(
|
||||
fpu = r.core.fpu.map(_.copy(fLen = 32)),
|
||||
mulDiv = Some(MulDivParams(mulUnroll = 8))))
|
||||
}
|
||||
})
|
||||
|
||||
class WithNonblockingL1(nMSHRs: Int) extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(dcache = r.dcache.map(_.copy(nMSHRs = nMSHRs)))
|
||||
}
|
||||
})
|
||||
|
||||
class WithNBreakpoints(hwbp: Int) extends Config ((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(nBreakpoints = hwbp))
|
||||
}
|
||||
})
|
||||
|
||||
class WithRoccExample extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(rocc =
|
||||
Seq(
|
||||
RoCCParams(
|
||||
opcodes = OpcodeSet.custom0,
|
||||
generator = (p: Parameters) => {
|
||||
val accumulator = LazyModule(new AccumulatorExample()(p))
|
||||
accumulator}),
|
||||
RoCCParams(
|
||||
opcodes = OpcodeSet.custom1,
|
||||
generator = (p: Parameters) => {
|
||||
val translator = LazyModule(new TranslatorExample()(p))
|
||||
translator},
|
||||
nPTWPorts = 1),
|
||||
RoCCParams(
|
||||
opcodes = OpcodeSet.custom2,
|
||||
generator = (p: Parameters) => {
|
||||
val counter = LazyModule(new CharacterCountExample()(p))
|
||||
counter
|
||||
})
|
||||
))
|
||||
}
|
||||
})
|
||||
|
||||
class WithDefaultBtb extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(btb = Some(BTBParams()))
|
||||
}
|
||||
})
|
||||
|
||||
class WithFastMulDiv extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(mulDiv = Some(
|
||||
MulDivParams(mulUnroll = 8, mulEarlyOut = (site(XLen) > 32), divEarlyOut = true)
|
||||
)))}
|
||||
})
|
||||
|
||||
class WithoutMulDiv extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(mulDiv = None))
|
||||
}
|
||||
})
|
||||
|
||||
class WithoutFPU extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(fpu = None))
|
||||
}
|
||||
})
|
||||
|
||||
class WithFPUWithoutDivSqrt extends Config((site, here, up) => {
|
||||
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
|
||||
r.copy(core = r.core.copy(fpu = r.core.fpu.map(_.copy(divSqrt = false))))
|
||||
}
|
||||
})
|
||||
|
||||
class WithBootROMFile(bootROMFile: String) extends Config((site, here, up) => {
|
||||
case BootROMParams => up(BootROMParams, site).copy(contentFileName = bootROMFile)
|
||||
})
|
||||
|
||||
class WithSynchronousRocketTiles extends Config((site, here, up) => {
|
||||
case RocketCrossingKey => up(RocketCrossingKey, site) map { r =>
|
||||
r.copy(crossingType = SynchronousCrossing())
|
||||
}
|
||||
})
|
||||
|
||||
class WithAsynchronousRocketTiles(depth: Int, sync: Int) extends Config((site, here, up) => {
|
||||
case RocketCrossingKey => up(RocketCrossingKey, site) map { r =>
|
||||
r.copy(crossingType = AsynchronousCrossing(depth, sync))
|
||||
}
|
||||
})
|
||||
|
||||
class WithRationalRocketTiles extends Config((site, here, up) => {
|
||||
case RocketCrossingKey => up(RocketCrossingKey, site) map { r =>
|
||||
r.copy(crossingType = RationalCrossing())
|
||||
}
|
||||
})
|
||||
|
||||
class WithEdgeDataBits(dataBits: Int) extends Config((site, here, up) => {
|
||||
case MemoryBusKey => up(MemoryBusKey, 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 PeripheryBusKey => up(PeripheryBusKey, site).copy(arithmetic = false)
|
||||
})
|
||||
|
||||
class WithNBitPeripheryBus(nBits: Int) extends Config ((site, here, up) => {
|
||||
case PeripheryBusKey => up(PeripheryBusKey, site).copy(beatBytes = nBits/8)
|
||||
})
|
||||
|
||||
class WithoutTLMonitors extends Config ((site, here, up) => {
|
||||
case MonitorsEnabled => false
|
||||
})
|
||||
|
||||
class WithNExtTopInterrupts(nExtInts: Int) extends Config((site, here, up) => {
|
||||
case NExtTopInterrupts => nExtInts
|
||||
})
|
||||
|
||||
class WithNMemoryChannels(n: Int) extends Config((site, here, up) => {
|
||||
case BankedL2Key => up(BankedL2Key, 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
|
||||
})
|
198
src/main/scala/subsystem/CrossingWrapper.scala
Normal file
198
src/main/scala/subsystem/CrossingWrapper.scala
Normal file
@ -0,0 +1,198 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.amba.axi4._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
/** Enumerates the three types of clock crossing between tiles and system bus */
|
||||
sealed trait SubsystemClockCrossing
|
||||
{
|
||||
def sameClock = this match {
|
||||
case _: SynchronousCrossing => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends SubsystemClockCrossing
|
||||
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends SubsystemClockCrossing
|
||||
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends SubsystemClockCrossing
|
||||
|
||||
private case class CrossingCheck(out: Boolean, source: BaseNode, sink: BaseNode)
|
||||
|
||||
trait HasCrossingMethods extends LazyModule with LazyScope
|
||||
{
|
||||
// Detect incorrect crossing connectivity
|
||||
|
||||
private var checks: List[CrossingCheck] = Nil
|
||||
private def inside(node: BaseNode) = node.parents.exists(_ eq this)
|
||||
override def instantiate() {
|
||||
super.instantiate()
|
||||
checks.foreach { case CrossingCheck(out, source, sink) =>
|
||||
source.inputs.foreach { case (syncSource, _) =>
|
||||
require (inside(syncSource) == out, s"${syncSource.name} must ${if(out)""else"not "}be inside ${name} (wrong .cross direction?)")
|
||||
}
|
||||
sink.outputs.foreach { case (syncSink, _) =>
|
||||
require (inside(syncSink) != out, s"${syncSink.name} must ${if(out)"not "else""}be inside ${name} (wrong .cross direction?)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TileLink
|
||||
|
||||
def crossTLSyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = {
|
||||
val node = this { LazyModule(new TLBuffer(params)).node }
|
||||
checks = CrossingCheck(out, node, node) :: checks
|
||||
node
|
||||
}
|
||||
|
||||
def crossTLAsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = {
|
||||
lazy val asource = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
lazy val asink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
val source = if (out) this { asource } else asource
|
||||
val sink = if (out) asink else this { asink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossTLRationalInOut(out: Boolean)(direction: RationalDirection)(implicit p: Parameters): TLNode = {
|
||||
lazy val rsource = LazyModule(new TLRationalCrossingSource)
|
||||
lazy val rsink = LazyModule(new TLRationalCrossingSink(if (out) direction else direction.flip))
|
||||
val source = if (out) this { rsource } else rsource
|
||||
val sink = if (out) rsink else this { rsink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossTLSyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(false)(params)
|
||||
def crossTLSyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(true )(params)
|
||||
def crossTLAsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(false)(depth, sync)
|
||||
def crossTLAsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(true )(depth, sync)
|
||||
def crossTLRationalIn (direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(false)(direction)
|
||||
def crossTLRationalOut(direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(true )(direction)
|
||||
|
||||
def crossTLIn(arg: SubsystemClockCrossing)(implicit p: Parameters): TLNode = arg match {
|
||||
case x: SynchronousCrossing => crossTLSyncIn(x.params)
|
||||
case x: AsynchronousCrossing => crossTLAsyncIn(x.depth, x.sync)
|
||||
case x: RationalCrossing => crossTLRationalIn(x.direction)
|
||||
}
|
||||
|
||||
def crossTLOut(arg: SubsystemClockCrossing)(implicit p: Parameters): TLNode = arg match {
|
||||
case x: SynchronousCrossing => crossTLSyncOut(x.params)
|
||||
case x: AsynchronousCrossing => crossTLAsyncOut(x.depth, x.sync)
|
||||
case x: RationalCrossing => crossTLRationalOut(x.direction)
|
||||
}
|
||||
|
||||
// AXI4
|
||||
|
||||
def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = {
|
||||
val node = this { LazyModule(new AXI4Buffer(params)).node }
|
||||
checks = CrossingCheck(out, node, node) :: checks
|
||||
node
|
||||
}
|
||||
|
||||
def crossAXI4AsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = {
|
||||
lazy val axi4asource = LazyModule(new AXI4AsyncCrossingSource(sync))
|
||||
lazy val axi4asink = LazyModule(new AXI4AsyncCrossingSink(depth, sync))
|
||||
val source = if (out) this { axi4asource } else axi4asource
|
||||
val sink = if (out) axi4asink else this { axi4asink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossAXI4SyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(false)(params)
|
||||
def crossAXI4SyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(true )(params)
|
||||
def crossAXI4AsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(false)(depth, sync)
|
||||
def crossAXI4AsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(true )(depth, sync)
|
||||
|
||||
def crossAXI4In(arg: SubsystemClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
|
||||
case x: SynchronousCrossing => crossAXI4SyncIn(x.params)
|
||||
case x: AsynchronousCrossing => crossAXI4AsyncIn(x.depth, x.sync)
|
||||
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
|
||||
}
|
||||
|
||||
def crossAXI4Out(arg: SubsystemClockCrossing)(implicit p: Parameters): AXI4Node = arg match {
|
||||
case x: SynchronousCrossing => crossAXI4SyncOut(x.params)
|
||||
case x: AsynchronousCrossing => crossAXI4AsyncOut(x.depth, x.sync)
|
||||
case x: RationalCrossing => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented")
|
||||
}
|
||||
|
||||
// Interrupts
|
||||
|
||||
def crossIntSyncInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
lazy val intssource = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
lazy val intssink = LazyModule(new IntSyncCrossingSink(0))
|
||||
val source = if (out) this { intssource } else intssource
|
||||
val sink = if (out) intssink else this { intssink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntAsyncInOut(out: Boolean)(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
lazy val intasource = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
lazy val intasink = LazyModule(new IntSyncCrossingSink(sync))
|
||||
val source = if (out) this { intasource } else intasource
|
||||
val sink = if (out) intasink else this { intasink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntRationalInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = {
|
||||
lazy val intrsource = LazyModule(new IntSyncCrossingSource(alreadyRegistered))
|
||||
lazy val intrsink = LazyModule(new IntSyncCrossingSink(1))
|
||||
val source = if (out) this { intrsource } else intrsource
|
||||
val sink = if (out) intrsink else this { intrsink }
|
||||
sink.node :*=* source.node
|
||||
checks = CrossingCheck(out, source.node, sink.node) :: checks
|
||||
NodeHandle(source.node, sink.node)
|
||||
}
|
||||
|
||||
def crossIntSyncIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(false)(alreadyRegistered)
|
||||
def crossIntSyncOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(true )(alreadyRegistered)
|
||||
def crossIntAsyncIn (sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(false)(sync, alreadyRegistered)
|
||||
def crossIntAsyncOut(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(true )(sync, alreadyRegistered)
|
||||
def crossIntRationalIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(false)(alreadyRegistered)
|
||||
def crossIntRationalOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(true )(alreadyRegistered)
|
||||
|
||||
def crossIntIn(arg: SubsystemClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
|
||||
case x: SynchronousCrossing => crossIntSyncIn(alreadyRegistered)
|
||||
case x: AsynchronousCrossing => crossIntAsyncIn(x.sync, alreadyRegistered)
|
||||
case x: RationalCrossing => crossIntRationalIn(alreadyRegistered)
|
||||
}
|
||||
|
||||
def crossIntOut(arg: SubsystemClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match {
|
||||
case x: SynchronousCrossing => crossIntSyncOut(alreadyRegistered)
|
||||
case x: AsynchronousCrossing => crossIntAsyncOut(x.sync, alreadyRegistered)
|
||||
case x: RationalCrossing => crossIntRationalOut(alreadyRegistered)
|
||||
}
|
||||
|
||||
def crossIntIn (arg: SubsystemClockCrossing)(implicit p: Parameters): IntNode = crossIntIn (arg, false)
|
||||
def crossIntOut(arg: SubsystemClockCrossing)(implicit p: Parameters): IntNode = crossIntOut(arg, false)
|
||||
}
|
||||
|
||||
trait HasCrossing extends HasCrossingMethods
|
||||
{
|
||||
this: LazyModule =>
|
||||
val crossing: SubsystemClockCrossing
|
||||
|
||||
def crossTLIn (implicit p: Parameters): TLNode = crossTLIn (crossing)
|
||||
def crossTLOut (implicit p: Parameters): TLNode = crossTLOut (crossing)
|
||||
def crossAXI4In (implicit p: Parameters): AXI4Node= crossAXI4In (crossing)
|
||||
def crossAXI4Out(implicit p: Parameters): AXI4Node= crossAXI4Out(crossing)
|
||||
def crossIntIn (implicit p: Parameters): IntNode = crossIntIn (crossing)
|
||||
def crossIntOut (implicit p: Parameters): IntNode = crossIntOut (crossing)
|
||||
|
||||
def crossIntIn (alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntIn (crossing, alreadyRegistered)
|
||||
def crossIntOut(alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntOut(crossing, alreadyRegistered)
|
||||
}
|
||||
|
||||
class CrossingWrapper(val crossing: SubsystemClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossing
|
55
src/main/scala/subsystem/FrontBus.scala
Normal file
55
src/main/scala/subsystem/FrontBus.scala
Normal file
@ -0,0 +1,55 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
case class FrontBusParams(
|
||||
beatBytes: Int,
|
||||
blockBytes: Int,
|
||||
masterBuffering: BufferParams = BufferParams.default,
|
||||
slaveBuffering: BufferParams = BufferParams.default
|
||||
) extends TLBusParams
|
||||
|
||||
case object FrontBusKey extends Field[FrontBusParams]
|
||||
|
||||
class FrontBus(params: FrontBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "FrontBus") {
|
||||
|
||||
private val master_buffer = LazyModule(new TLBuffer(params.masterBuffering))
|
||||
private val master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all))
|
||||
|
||||
master_buffer.suggestName(s"${busName}_master_TLBuffer")
|
||||
master_fixer.suggestName(s"${busName}_master_TLFIFOFixer")
|
||||
|
||||
master_fixer.node :=* master_buffer.node
|
||||
inwardNode :=* master_fixer.node
|
||||
|
||||
def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
||||
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _)
|
||||
}
|
||||
|
||||
def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = {
|
||||
TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _)
|
||||
}
|
||||
|
||||
def fromCoherentChip: TLInwardNode = inwardNode
|
||||
|
||||
def toSystemBus : TLOutwardNode = TLBuffer(params.slaveBuffering) :=* xbar.node
|
||||
|
||||
}
|
||||
|
||||
/** Provides buses that serve as attachment points,
|
||||
* for use in traits that connect individual devices or external ports.
|
||||
*/
|
||||
trait HasFrontBus extends HasSystemBus {
|
||||
private val frontbusParams = p(FrontBusKey)
|
||||
val frontbusBeatBytes = frontbusParams.beatBytes
|
||||
|
||||
val fbus = LazyModule(new FrontBus(frontbusParams))
|
||||
|
||||
FlipRendering { implicit p => sbus.fromFrontBus :=* fbus.toSystemBus }
|
||||
}
|
53
src/main/scala/subsystem/HasTiles.scala
Normal file
53
src/main/scala/subsystem/HasTiles.scala
Normal file
@ -0,0 +1,53 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import chisel3.experimental.dontTouch
|
||||
import freechips.rocketchip.config.Parameters
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.interrupts._
|
||||
import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants}
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
class ClockedTileInputs(implicit val p: Parameters) extends ParameterizedBundle
|
||||
with HasExternallyDrivenTileConstants
|
||||
with Clocked
|
||||
|
||||
trait HasTiles extends HasSystemBus {
|
||||
val tiles: Seq[BaseTile]
|
||||
protected def tileParams: Seq[TileParams] = tiles.map(_.tileParams)
|
||||
def nTiles: Int = tileParams.size
|
||||
def hartIdList: Seq[Int] = tileParams.map(_.hartId)
|
||||
def localIntCounts: Seq[Int] = tileParams.map(_.core.nLocalInterrupts)
|
||||
}
|
||||
|
||||
trait HasTilesBundle {
|
||||
val tile_inputs: Vec[ClockedTileInputs]
|
||||
}
|
||||
|
||||
trait HasTilesModuleImp extends LazyModuleImp
|
||||
with HasTilesBundle
|
||||
with HasResetVectorWire {
|
||||
val outer: HasTiles
|
||||
|
||||
def resetVectorBits: Int = {
|
||||
// Consider using the minimum over all widths, rather than enforcing homogeneity
|
||||
val vectors = outer.tiles.map(_.module.constants.reset_vector)
|
||||
require(vectors.tail.forall(_.getWidth == vectors.head.getWidth))
|
||||
vectors.head.getWidth
|
||||
}
|
||||
|
||||
val tile_inputs = dontTouch(Wire(Vec(outer.nTiles, new ClockedTileInputs()(p.alterPartial {
|
||||
case SharedMemoryTLEdge => outer.sharedMemoryTLEdge
|
||||
})))) // dontTouch keeps constant prop from sucking these signals into the tile
|
||||
|
||||
// Unconditionally wire up the non-diplomatic tile inputs
|
||||
outer.tiles.map(_.module).zip(tile_inputs).foreach { case(tile, wire) =>
|
||||
tile.clock := wire.clock
|
||||
tile.reset := wire.reset
|
||||
tile.constants.hartid := wire.hartid
|
||||
tile.constants.reset_vector := wire.reset_vector
|
||||
}
|
||||
}
|
||||
|
85
src/main/scala/subsystem/InterruptBus.scala
Normal file
85
src/main/scala/subsystem/InterruptBus.scala
Normal file
@ -0,0 +1,85 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.interrupts._
|
||||
|
||||
/** 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](0)
|
||||
|
||||
/** 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 = IntSourceNode(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 LazyModuleImp with HasExtInterruptsBundle {
|
||||
val outer: HasExtInterrupts
|
||||
val interrupts = IO(UInt(INPUT, width = outer.nExtInterrupts))
|
||||
|
||||
outer.extInterrupts.out.map(_._1).flatten.zipWithIndex.foreach { case(o, i) => o := interrupts(i) }
|
||||
}
|
79
src/main/scala/subsystem/MemoryBus.scala
Normal file
79
src/main/scala/subsystem/MemoryBus.scala
Normal file
@ -0,0 +1,79 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
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](64)
|
||||
|
||||
/** L2 Broadcast Hub configuration */
|
||||
case class BroadcastParams(
|
||||
nTrackers: Int = 4,
|
||||
bufferless: Boolean = false)
|
||||
|
||||
case object BroadcastKey extends Field(BroadcastParams())
|
||||
|
||||
/** L2 memory subsystem configuration */
|
||||
case class BankedL2Params(
|
||||
nMemoryChannels: Int = 1,
|
||||
nBanksPerChannel: Int = 1,
|
||||
coherenceManager: HasMemoryBus => (TLInwardNode, TLOutwardNode, () => Option[Bool]) = { subsystem =>
|
||||
implicit val p = subsystem.p
|
||||
val BroadcastParams(nTrackers, bufferless) = p(BroadcastKey)
|
||||
val bh = LazyModule(new TLBroadcast(subsystem.memBusBlockBytes, nTrackers, bufferless))
|
||||
val ww = LazyModule(new TLWidthWidget(subsystem.sbusBeatBytes))
|
||||
ww.node :*= bh.node
|
||||
(bh.node, ww.node, () => None)
|
||||
}) {
|
||||
val nBanks = nMemoryChannels*nBanksPerChannel
|
||||
}
|
||||
|
||||
case object BankedL2Key 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 MemoryBusKey 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, "MemoryBus")(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(MemoryBusKey)
|
||||
private val l2Params = p(BankedL2Key)
|
||||
val MemoryBusParams(memBusBeatBytes, memBusBlockBytes, _, _) = mbusParams
|
||||
val BankedL2Params(nMemoryChannels, nBanksPerChannel, coherenceManager) = l2Params
|
||||
val nBanks = l2Params.nBanks
|
||||
val cacheBlockBytes = memBusBlockBytes
|
||||
private val (in, out, halt) = coherenceManager(this)
|
||||
def memBusCanCauseHalt: () => Option[Bool] = halt
|
||||
|
||||
require (isPow2(nMemoryChannels) || nMemoryChannels == 0)
|
||||
require (isPow2(nBanksPerChannel))
|
||||
require (isPow2(memBusBlockBytes))
|
||||
|
||||
private val mask = ~BigInt((nBanks-1) * memBusBlockBytes)
|
||||
val memBuses = Seq.tabulate(nMemoryChannels) { channel =>
|
||||
val mbus = LazyModule(new MemoryBus(mbusParams))
|
||||
for (bank <- 0 until nBanksPerChannel) {
|
||||
val offset = (bank * nMemoryChannels) + channel
|
||||
ForceFanout(a = true) { implicit p => in := sbus.toMemoryBus }
|
||||
mbus.fromCoherenceManager := TLFilter(TLFilter.Mmask(AddressSet(offset * memBusBlockBytes, mask))) := out
|
||||
}
|
||||
mbus
|
||||
}
|
||||
}
|
61
src/main/scala/subsystem/PeripheryBus.scala
Normal file
61
src/main/scala/subsystem/PeripheryBus.scala
Normal file
@ -0,0 +1,61 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.config.{Field, Parameters}
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.tilelink._
|
||||
|
||||
import freechips.rocketchip.config.Field
|
||||
|
||||
case class PeripheryBusParams(
|
||||
beatBytes: Int,
|
||||
blockBytes: Int,
|
||||
masterBuffering: BufferParams = BufferParams.default,
|
||||
slaveBuffering: BufferParams = BufferParams.none,
|
||||
arithmetic: Boolean = true,
|
||||
frequency: BigInt = BigInt(100000000) // 100 MHz as default bus frequency
|
||||
) extends TLBusParams {
|
||||
}
|
||||
|
||||
case object PeripheryBusKey extends Field[PeripheryBusParams]
|
||||
|
||||
class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "PeripheryBus") {
|
||||
|
||||
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))
|
||||
xbar.node :*= TLBuffer(params.masterBuffering) :*= atomics.node
|
||||
}
|
||||
|
||||
def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) {
|
||||
this {
|
||||
LazyScope(s"${busName}ToTile${name.getOrElse("")}") {
|
||||
FlipRendering { implicit p =>
|
||||
gen(p) :*= outwardNode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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(PeripheryBusKey)
|
||||
val pbusBeatBytes = pbusParams.beatBytes
|
||||
|
||||
val pbus = LazyModule(new PeripheryBus(pbusParams))
|
||||
|
||||
// The peripheryBus hangs off of systemBus; here we convert TL-UH -> TL-UL
|
||||
pbus.fromSystemBus :*= sbus.toPeripheryBus()
|
||||
}
|
261
src/main/scala/subsystem/Ports.scala
Normal file
261
src/main/scala/subsystem/Ports.scala
Normal file
@ -0,0 +1,261 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
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: BigInt,
|
||||
size: BigInt,
|
||||
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 = AXI4SlaveNode(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())
|
||||
val trim = LazyModule(new AXI4IdIndexer(params.idBits))
|
||||
val yank = LazyModule(new AXI4UserYanker)
|
||||
val buffer = LazyModule(new AXI4Buffer)
|
||||
|
||||
memBuses.map(_.toDRAMController).foreach { case node =>
|
||||
mem_axi4 := buffer.node := yank.node := trim.node := converter.node := 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) {
|
||||
val mem = LazyModule(new SimAXIMem(nMemoryChannels))
|
||||
Module(mem.module).io.axi4 <> mem_axi4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasMasterAXI4MemPortModuleImp extends LazyModuleImp with HasMasterAXI4MemPortBundle {
|
||||
val outer: HasMasterAXI4MemPort
|
||||
val mem_axi4 = IO(HeterogeneousBag.fromNode(outer.mem_axi4.in))
|
||||
(mem_axi4 zip outer.mem_axi4.in) foreach { case (i, (o, _)) => i <> o }
|
||||
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 = AXI4SlaveNode(Seq(AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = AddressSet.misaligned(params.base, params.size),
|
||||
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()
|
||||
:= 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) {
|
||||
val mmio_mem = LazyModule(new SimAXIMem(1, 4096))
|
||||
Module(mmio_mem.module).io.axi4 <> mmio_axi4
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait HasMasterAXI4MMIOPortModuleImp extends LazyModuleImp with HasMasterAXI4MMIOPortBundle {
|
||||
val outer: HasMasterAXI4MMIOPort
|
||||
val mmio_axi4 = IO(HeterogeneousBag.fromNode(outer.mmio_axi4.in))
|
||||
(mmio_axi4 zip outer.mmio_axi4.in) foreach { case (i, (o, _)) => i <> o }
|
||||
}
|
||||
|
||||
/** 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 = AXI4MasterNode(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 LazyModuleImp with HasSlaveAXI4PortBundle {
|
||||
val outer: HasSlaveAXI4Port
|
||||
val l2_frontend_bus_axi4 = IO(HeterogeneousBag.fromNode(outer.l2FrontendAXI4Node.out).flip)
|
||||
(outer.l2FrontendAXI4Node.out zip l2_frontend_bus_axi4) foreach { case ((i, _), o) => i <> o }
|
||||
}
|
||||
|
||||
/** 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 = TLManagerNode(Seq(TLManagerPortParameters(
|
||||
managers = Seq(TLManagerParameters(
|
||||
address = AddressSet.misaligned(params.base, params.size),
|
||||
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 LazyModuleImp with HasMasterTLMMIOPortBundle {
|
||||
val outer: HasMasterTLMMIOPort
|
||||
val mmio_tl = IO(HeterogeneousBag.fromNode(outer.mmio_tl.in))
|
||||
(mmio_tl zip outer.mmio_tl.in) foreach { case (i, (o, _)) => i <> o }
|
||||
}
|
||||
|
||||
/** 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 = TLClientNode(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 LazyModuleImp with HasSlaveTLPortBundle {
|
||||
val outer: HasSlaveTLPort
|
||||
val l2_frontend_bus_tl = IO(HeterogeneousBag.fromNode(outer.l2FrontendTLNode.out).flip)
|
||||
(outer.l2FrontendTLNode.in zip l2_frontend_bus_tl) foreach { case ((i, _), o) => i <> o }
|
||||
}
|
||||
|
||||
/** 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 config.size
|
||||
val size = totalSize / channels
|
||||
require(totalSize % channels == 0)
|
||||
|
||||
val node = AXI4MasterNode(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 = IO(new Bundle {
|
||||
val axi4 = HeterogeneousBag.fromNode(node.out).flip
|
||||
})
|
||||
(node.out zip io.axi4) foreach { case ((i, _), o) => i <> o }
|
||||
}
|
||||
}
|
24
src/main/scala/subsystem/RTC.scala
Normal file
24
src/main/scala/subsystem/RTC.scala
Normal file
@ -0,0 +1,24 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import freechips.rocketchip.diplomacy.{LazyModuleImp, DTSTimebase}
|
||||
import freechips.rocketchip.devices.tilelink.HasPeripheryCLINT
|
||||
|
||||
trait HasRTCModuleImp extends LazyModuleImp {
|
||||
val outer: HasPeripheryCLINT
|
||||
private val pbusFreq = outer.p(PeripheryBusKey).frequency
|
||||
private val rtcFreq = outer.p(DTSTimebase)
|
||||
private val internalPeriod: BigInt = pbusFreq / rtcFreq
|
||||
|
||||
// check whether pbusFreq >= rtcFreq
|
||||
require(internalPeriod > 0)
|
||||
// check wehther the integer division is within 5% of the real division
|
||||
require((pbusFreq - rtcFreq * internalPeriod) * 100 / pbusFreq <= 5)
|
||||
|
||||
// Use the static period to toggle the RTC
|
||||
val (_, int_rtc_tick) = Counter(true.B, internalPeriod.toInt)
|
||||
|
||||
outer.clint.module.io.rtcTick := int_rtc_tick
|
||||
}
|
11
src/main/scala/subsystem/ResetVector.scala
Normal file
11
src/main/scala/subsystem/ResetVector.scala
Normal file
@ -0,0 +1,11 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
|
||||
/** A single place for all tiles to find out the reset vector */
|
||||
trait HasResetVectorWire {
|
||||
def resetVectorBits: Int
|
||||
val global_reset_vector = Wire(UInt(width = resetVectorBits))
|
||||
}
|
180
src/main/scala/subsystem/RocketSubsystem.scala
Normal file
180
src/main/scala/subsystem/RocketSubsystem.scala
Normal file
@ -0,0 +1,180 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
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.interrupts._
|
||||
import freechips.rocketchip.util._
|
||||
|
||||
// TODO: how specific are these to RocketTiles?
|
||||
case class TileMasterPortParams(
|
||||
addBuffers: Int = 0,
|
||||
cork: Option[Boolean] = None) {
|
||||
|
||||
def adapt(subsystem: HasPeripheryBus)
|
||||
(masterNode: TLOutwardNode)
|
||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = {
|
||||
val tile_master_cork = cork.map(u => (LazyModule(new TLCacheCork(unsafe = u))))
|
||||
val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable))
|
||||
|
||||
(Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers) ++ tile_master_cork.map(_.node))
|
||||
.foldRight(masterNode)(_ :=* _)
|
||||
}
|
||||
}
|
||||
|
||||
case class TileSlavePortParams(
|
||||
addBuffers: Int = 0,
|
||||
blockerCtrlAddr: Option[BigInt] = None) {
|
||||
|
||||
def adapt(subsystem: HasPeripheryBus)
|
||||
(slaveNode: TLInwardNode)
|
||||
(implicit p: Parameters, sourceInfo: SourceInfo): TLInwardNode = {
|
||||
val tile_slave_blocker =
|
||||
blockerCtrlAddr
|
||||
.map(BasicBusBlockerParams(_, subsystem.pbus.beatBytes, subsystem.sbus.beatBytes))
|
||||
.map(bp => LazyModule(new BasicBusBlocker(bp)))
|
||||
|
||||
tile_slave_blocker.foreach { _.controlNode := subsystem.pbus.toVariableWidthSlaves }
|
||||
(Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers))
|
||||
.foldLeft(slaveNode)(_ :*= _)
|
||||
}
|
||||
}
|
||||
|
||||
case class RocketCrossingParams(
|
||||
crossingType: SubsystemClockCrossing = SynchronousCrossing(),
|
||||
master: TileMasterPortParams = TileMasterPortParams(),
|
||||
slave: TileSlavePortParams = TileSlavePortParams()) {
|
||||
def knownRatio: Option[Int] = crossingType match {
|
||||
case RationalCrossing(_) => Some(2)
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
||||
case object RocketTilesKey extends Field[Seq[RocketTileParams]](Nil)
|
||||
case object RocketCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams()))
|
||||
|
||||
trait HasRocketTiles extends HasTiles
|
||||
with HasPeripheryBus
|
||||
with HasPeripheryPLIC
|
||||
with HasPeripheryCLINT
|
||||
with HasPeripheryDebug {
|
||||
val module: HasRocketTilesModuleImp
|
||||
|
||||
protected val rocketTileParams = p(RocketTilesKey)
|
||||
private val NumRocketTiles = rocketTileParams.size
|
||||
private val crossingParams = p(RocketCrossingKey)
|
||||
private val crossings = crossingParams.size match {
|
||||
case 1 => List.fill(NumRocketTiles) { crossingParams.head }
|
||||
case NumRocketTiles => crossingParams
|
||||
case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size")
|
||||
}
|
||||
private val crossingTuples = rocketTileParams.zip(crossings)
|
||||
|
||||
// Make a tile and wire its nodes into the system,
|
||||
// according to the specified type of clock crossing.
|
||||
// Note that we also inject new nodes into the tile itself,
|
||||
// also based on the crossing type.
|
||||
val rocketTiles = crossingTuples.map { case (tp, crossing) =>
|
||||
// For legacy reasons, it is convenient to store some state
|
||||
// in the global Parameters about the specific tile being built now
|
||||
val rocket = LazyModule(new RocketTile(tp, crossing.crossingType)(p.alterPartial {
|
||||
case TileKey => tp
|
||||
case BuildRoCC => tp.rocc
|
||||
case SharedMemoryTLEdge => sharedMemoryTLEdge
|
||||
})
|
||||
).suggestName(tp.name)
|
||||
|
||||
// Connect the master ports of the tile to the system bus
|
||||
|
||||
def tileMasterBuffering: TLOutwardNode = rocket {
|
||||
// The buffers needed to cut feed-through paths are microarchitecture specific, so belong here
|
||||
val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1)))
|
||||
crossing.crossingType match {
|
||||
case _: AsynchronousCrossing => rocket.masterNode
|
||||
case SynchronousCrossing(b) =>
|
||||
require (!tp.boundaryBuffers || (b.depth >= 1 && !b.flow && !b.pipe), "Buffer misconfiguration creates feed-through paths")
|
||||
rocket.masterNode
|
||||
case RationalCrossing(dir) =>
|
||||
require (dir != SlowToFast, "Misconfiguration? Core slower than fabric")
|
||||
if (tp.boundaryBuffers) {
|
||||
masterBuffer.node :=* rocket.masterNode
|
||||
} else {
|
||||
rocket.masterNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(rocket.crossTLOut :=* tileMasterBuffering) }
|
||||
|
||||
// Connect the slave ports of the tile to the periphery bus
|
||||
|
||||
def tileSlaveBuffering: TLInwardNode = rocket {
|
||||
val slaveBuffer = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none))
|
||||
crossing.crossingType match {
|
||||
case RationalCrossing(_) if (tp.boundaryBuffers) => rocket.slaveNode :*= slaveBuffer.node
|
||||
case _ => rocket.slaveNode
|
||||
}
|
||||
}
|
||||
|
||||
pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)( DisableMonitors { implicit p =>
|
||||
tileSlaveBuffering :*= rocket.crossTLIn
|
||||
})}
|
||||
|
||||
// Handle all the different types of interrupts crossing to or from the tile:
|
||||
// 1. Debug interrupt is definitely asynchronous in all cases.
|
||||
// 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock,
|
||||
// so might need to be synchronized depending on the Tile's crossing type.
|
||||
// 3. Local Interrupts are required to already be synchronous to the tile clock.
|
||||
// 4. Interrupts coming out of the tile are sent to the PLIC,
|
||||
// so might need to be synchronized depending on the Tile's crossing type.
|
||||
// NOTE: The order of calls to := matters! They must match how interrupts
|
||||
// are decoded from rocket.intNode inside the tile.
|
||||
|
||||
// 1. always async crossing for debug
|
||||
rocket.intInwardNode := rocket { IntSyncCrossingSink(3) } := debug.intnode
|
||||
|
||||
// 2. clint+plic conditionally crossing
|
||||
val periphIntNode = rocket.intInwardNode :=* rocket.crossIntIn
|
||||
periphIntNode := clint.intnode // msip+mtip
|
||||
periphIntNode := plic.intnode // meip
|
||||
if (tp.core.useVM) periphIntNode := plic.intnode // seip
|
||||
|
||||
// 3. local interrupts never cross
|
||||
// rocket.intInwardNode is wired up externally // lip
|
||||
|
||||
// 4. conditional crossing from core to PLIC
|
||||
FlipRendering { implicit p =>
|
||||
plic.intnode :=* rocket.crossIntOut :=* rocket.intOutwardNode
|
||||
}
|
||||
|
||||
rocket
|
||||
}
|
||||
}
|
||||
|
||||
trait HasRocketTilesModuleImp extends HasTilesModuleImp
|
||||
with HasPeripheryDebugModuleImp {
|
||||
val outer: HasRocketTiles
|
||||
}
|
||||
|
||||
class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem
|
||||
with HasRocketTiles {
|
||||
val tiles = rocketTiles
|
||||
override lazy val module = new RocketSubsystemModule(this)
|
||||
}
|
||||
|
||||
class RocketSubsystemModule[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModule(_outer)
|
||||
with HasRocketTilesModuleImp {
|
||||
tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) =>
|
||||
wire.clock := clock
|
||||
wire.reset := reset
|
||||
wire.hartid := UInt(i)
|
||||
wire.reset_vector := global_reset_vector
|
||||
}
|
||||
}
|
83
src/main/scala/subsystem/SystemBus.scala
Normal file
83
src/main/scala/subsystem/SystemBus.scala
Normal file
@ -0,0 +1,83 @@
|
||||
// See LICENSE.SiFive for license details.
|
||||
|
||||
package freechips.rocketchip.subsystem
|
||||
|
||||
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.default
|
||||
) extends TLBusParams
|
||||
|
||||
case object SystemBusKey extends Field[SystemBusParams]
|
||||
|
||||
class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "SystemBus") {
|
||||
|
||||
private val master_splitter = LazyModule(new TLSplitter) // Allows cycle-free connection to external networks
|
||||
master_splitter.suggestName(s"${busName}_master_TLSplitter")
|
||||
inwardNode :=* master_splitter.node
|
||||
def busView = master_splitter.node.edges.in.head
|
||||
|
||||
protected def inwardSplitNode: TLInwardNode = master_splitter.node
|
||||
protected def outwardSplitNode: TLOutwardNode = master_splitter.node
|
||||
|
||||
|
||||
private val port_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all))
|
||||
port_fixer.suggestName(s"${busName}_port_TLFIFOFixer")
|
||||
master_splitter.node :=* port_fixer.node
|
||||
|
||||
private val pbus_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all))
|
||||
pbus_fixer.suggestName(s"${busName}_pbus_TLFIFOFixer")
|
||||
pbus_fixer.node :*= outwardWWNode
|
||||
|
||||
def toSplitSlaves: TLOutwardNode = outwardSplitNode
|
||||
|
||||
def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = {
|
||||
TLBuffer.chain(addBuffers).foldRight(pbus_fixer.node:TLOutwardNode)(_ :*= _)
|
||||
}
|
||||
|
||||
val toMemoryBus: TLOutwardNode = outwardNode
|
||||
|
||||
val toSlave: TLOutwardNode = outwardBufNode
|
||||
|
||||
def fromCoherentChip: TLInwardNode = inwardNode
|
||||
|
||||
def fromFrontBus: TLInwardNode = master_splitter.node
|
||||
|
||||
def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) {
|
||||
this {
|
||||
LazyScope(s"${busName}FromTile${name.getOrElse("")}") {
|
||||
master_splitter.node :=* gen(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def fromSyncPorts(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
||||
val buffer = LazyModule(new TLBuffer(params))
|
||||
name.foreach { n => buffer.suggestName(s"${busName}_${n}_TLBuffer") }
|
||||
port_fixer.node :=* buffer.node
|
||||
buffer.node
|
||||
}
|
||||
|
||||
def fromSyncFIFOMaster(params: BufferParams = BufferParams.default, name: Option[String] = None): TLInwardNode = {
|
||||
fromSyncPorts(params, name)
|
||||
}
|
||||
}
|
||||
|
||||
/** 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(SystemBusKey)
|
||||
val sbusBeatBytes = sbusParams.beatBytes
|
||||
|
||||
val sbus = LazyModule(new SystemBus(sbusParams))
|
||||
|
||||
def sharedMemoryTLEdge: TLEdge = sbus.busView
|
||||
}
|
Reference in New Issue
Block a user