1
0

Merge pull request #424 from ucb-bar/coreplex-cake

Coreplex cake
This commit is contained in:
Wesley W. Terpstra 2016-10-31 16:49:27 -07:00 committed by GitHub
commit 1b016051e8
33 changed files with 1101 additions and 1140 deletions

View File

@ -23,7 +23,7 @@ case object BankIdLSB extends Field[Int]
/** Function for building some kind of coherence manager agent */
case object BuildL2CoherenceManager extends Field[(Int, Parameters) => CoherenceAgent]
/** Function for building some kind of tile connected to a reset signal */
case object BuildTiles extends Field[Seq[(Bool, Parameters) => Tile]]
case object BuildTiles extends Field[Seq[Parameters => LazyTile]]
/** The file to read the BootROM contents from */
case object BootROMFile extends Field[String]
@ -35,50 +35,137 @@ trait HasCoreplexParameters {
lazy val outerMemParams = p.alterPartial({ case TLId => "L2toMC" })
lazy val outerMMIOParams = p.alterPartial({ case TLId => "L2toMMIO" })
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap)
lazy val nTiles = p(uncore.devices.NTiles)
lazy val nSlaves = p(rocketchip.NCoreplexExtClients)
lazy val nMemChannels = p(NMemoryChannels)
lazy val hasSupervisor = p(rocket.UseVM)
}
case class CoreplexConfig(
nTiles: Int,
nExtInterrupts: Int,
nSlaves: Int,
nMemChannels: Int,
hasSupervisor: Boolean)
{
val nInterruptPriorities = if (nExtInterrupts <= 1) 0 else (nExtInterrupts min 7)
val plicKey = PLICConfig(nTiles, hasSupervisor, nExtInterrupts, nInterruptPriorities)
case class CoreplexParameters(implicit val p: Parameters) extends HasCoreplexParameters
abstract class BareCoreplex(implicit val p: Parameters) extends LazyModule
abstract class BareCoreplexBundle[+L <: BareCoreplex](_outer: L) extends Bundle {
val outer = _outer
}
abstract class BareCoreplexModule[+L <: BareCoreplex, +B <: BareCoreplexBundle[L]](_outer: L, _io: () => B) extends LazyModuleImp(_outer) {
val outer = _outer
val io = _io ()
}
abstract class BaseCoreplex(c: CoreplexConfig)(implicit p: Parameters) extends LazyModule
trait CoreplexNetwork extends HasCoreplexParameters {
this: BareCoreplex =>
abstract class BaseCoreplexBundle(val c: CoreplexConfig)(implicit val p: Parameters) extends Bundle with HasCoreplexParameters {
val master = new Bundle {
val mem = Vec(c.nMemChannels, new ClientUncachedTileLinkIO()(outerMemParams))
val mmio = new ClientUncachedTileLinkIO()(outerMMIOParams)
}
val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
val interrupts = Vec(c.nExtInterrupts, Bool()).asInput
val debug = new DebugBusIO()(p).flip
val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput
val resetVector = UInt(INPUT, p(XLen))
val success = Bool(OUTPUT) // used for testing
val l1tol2 = LazyModule(new TLXbar)
val l1tol2_beatBytes = p(TLKey("L2toMMIO")).dataBitsPerBeat/8
val l1tol2_lineBytes = p(CacheBlockBytes)
override def cloneType = this.getClass.getConstructors.head.newInstance(c, p).asInstanceOf[this.type]
val cbus = LazyModule(new TLXbar)
val cbus_beatBytes = p(XLen)/8
val cbus_lineBytes = l1tol2_lineBytes
val mmio = TLOutputNode()
val mmioInt = IntInputNode()
cbus.node :=
TLAtomicAutomata(arithmetic = true)( // disable once TLB uses TL2 metadata
TLWidthWidget(l1tol2_beatBytes)(
TLBuffer()(
l1tol2.node)))
mmio :=
TLBuffer()(
TLWidthWidget(l1tol2_beatBytes)(
l1tol2.node))
}
abstract class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle](
c: CoreplexConfig, l: L, b: => B)(implicit val p: Parameters) extends LazyModuleImp(l) with HasCoreplexParameters {
val outer: L = l
val io: B = b
trait CoreplexNetworkBundle extends HasCoreplexParameters {
this: {
val outer: CoreplexNetwork
} =>
implicit val p = outer.p
val mmio = outer.mmio.bundleOut
val interrupts = outer.mmioInt.bundleIn
}
trait CoreplexNetworkModule extends HasCoreplexParameters {
this: BareCoreplexModule[BareCoreplex, BareCoreplexBundle[BareCoreplex]] =>
implicit val p = outer.p
}
trait CoreplexRISCVPlatform {
this: CoreplexNetwork =>
// Build a set of Tiles
val tiles = p(BuildTiles) map { _(reset, p) }
val lazyTiles = p(BuildTiles) map { _(p) }
val legacy = LazyModule(new TLLegacy()(outerMMIOParams))
val tileIntNodes = lazyTiles.map { _ => IntInternalOutputNode() } // this should be moved into the Tile...
val debug = LazyModule(new TLDebugModule())
val plic = LazyModule(new TLPLIC(hasSupervisor, maxPriorities = 7))
val clint = LazyModule(new CoreplexLocalInterrupter)
// Kill this once we move TL2 into rocket
l1tol2.node :=
TLHintHandler()(
legacy.node)
debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
plic.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
clint.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
plic.intnode := mmioInt
tileIntNodes.foreach { _ := plic.intnode }
}
trait CoreplexRISCVPlatformBundle {
this: CoreplexNetworkBundle {
val outer: CoreplexRISCVPlatform
} =>
val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outerMemParams))
val slave = Vec(nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
val debug = new DebugBusIO().flip
val rtcTick = Bool(INPUT)
val resetVector = UInt(INPUT, p(XLen))
val success = Bool(OUTPUT) // used for testing
}
trait CoreplexRISCVPlatformModule {
this: CoreplexNetworkModule {
val outer: CoreplexNetwork with CoreplexRISCVPlatform
val io: CoreplexRISCVPlatformBundle
} =>
val tiles = outer.lazyTiles.map(_.module)
val uncoreTileIOs = (tiles zipWithIndex) map { case (tile, i) => Wire(tile.io) }
println("\nGenerated Address Map")
for (entry <- p(rocketchip.GlobalAddrMap).flatten) {
val name = entry.name
val start = entry.region.start
val end = entry.region.start + entry.region.size - 1
val prot = entry.region.attr.prot
val protStr = (if ((prot & AddrMapProt.R) > 0) "R" else "") +
(if ((prot & AddrMapProt.W) > 0) "W" else "") +
(if ((prot & AddrMapProt.X) > 0) "X" else "")
val cacheable = if (entry.region.attr.cacheable) " [C]" else ""
println(f"\t$name%s $start%x - $end%x, $protStr$cacheable")
}
// Create and export the ConfigString
val managers = outer.l1tol2.node.edgesIn(0).manager.managers
val configString = rocketchip.GenerateConfigString(p, outer.clint, outer.plic, managers)
// Allow something else to have override the config string
if (!ConfigStringOutput.contents.isDefined) {
ConfigStringOutput.contents = Some(configString)
}
println(s"\nGenerated Configuration String\n${ConfigStringOutput.contents.get}")
val nCachedPorts = tiles.map(tile => tile.io.cached.size).reduce(_ + _)
val nUncachedPorts = tiles.map(tile => tile.io.uncached.size).reduce(_ + _)
val nBanks = c.nMemChannels * nBanksPerMemChannel
val nBanks = nMemChannels * nBanksPerMemChannel
// Build an uncore backing the Tiles
buildUncore(p.alterPartial({
case HastiId => "TL"
case TLId => "L1toL2"
@ -86,7 +173,7 @@ abstract class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle](
case NUncachedTileLinkPorts => nUncachedPorts
}))
def buildUncore(implicit p: Parameters) = {
def buildUncore(implicit p: Parameters) {
// Create a simple L1toL2 NoC between the tiles and the banks of outer memory
// Cached ports are first in client list, making sharerToClientId just an indentity function
// addrToBank is sed to hash physical addresses (of cache blocks) to banks (and thereby memory channels)
@ -112,8 +199,9 @@ abstract class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle](
l1tol2net.io.clients_cached <> uncoreTileIOs.map(_.cached).flatten
l1tol2net.io.clients_uncached <> uncoreTileIOs.map(_.uncached).flatten ++ io.slave
l1tol2net.io.managers <> managerEndpoints.map(_.innerTL) :+ mmioManager.io.inner
outer.legacy.module.io.legacy <> mmioManager.io.outer
val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, c.nMemChannels)(outerMemParams))
val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, nMemChannels)(outerMemParams))
val backendBuffering = TileLinkDepths(0,0,0,0,0)
for ((bank, icPort) <- managerEndpoints zip mem_ic.io.in) {
@ -121,46 +209,36 @@ abstract class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle](
icPort <> TileLinkIOUnwrapper(enqueued)
}
io.master.mem <> mem_ic.io.out
buildMMIONetwork(TileLinkEnqueuer(mmioManager.io.outer, 1))(outerMMIOParams)
io.mem <> mem_ic.io.out
}
def buildMMIONetwork(mmio: ClientUncachedTileLinkIO)(implicit p: Parameters) = {
val ioAddrMap = globalAddrMap.subMap("io")
val cBus = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap))
cBus.io.in.head <> mmio
val plic = Module(new PLIC(c.plicKey))
plic.io.tl <> cBus.port("cbus:plic")
for (i <- 0 until io.interrupts.size) {
val gateway = Module(new LevelGateway)
gateway.io.interrupt := io.interrupts(i)
plic.io.devices(i) <> gateway.io.plic
}
val debugModule = Module(new DebugModule)
debugModule.io.tl <> cBus.port("cbus:debug")
debugModule.io.db <> io.debug
// connect coreplex-internal interrupts to tiles
for ((tile, i) <- (uncoreTileIOs zipWithIndex)) {
tile.interrupts <> io.clint(i)
tile.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
tile.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
tile.interrupts.debug := debugModule.io.debugInterrupts(i)
tile.hartid := UInt(i)
tile.resetVector := io.resetVector
tile.interrupts := outer.clint.module.io.tiles(i)
tile.interrupts.debug := outer.debug.module.io.debugInterrupts(i)
tile.interrupts.meip := outer.tileIntNodes(i).bundleOut(0)(0)
tile.interrupts.seip.foreach(_ := outer.tileIntNodes(i).bundleOut(0)(1))
}
val tileSlavePorts = (0 until c.nTiles) map (i => s"cbus:dmem$i") filter (ioAddrMap contains _)
for ((t, m) <- (uncoreTileIOs.map(_.slave).flatten) zip (tileSlavePorts map (cBus port _)))
t <> m
io.master.mmio <> cBus.port("pbus")
}
outer.debug.module.io.db <> io.debug
outer.clint.module.io.rtcTick := io.rtcTick
// Coreplex doesn't know when to stop running
io.success := Bool(false)
}
class BaseCoreplex(implicit p: Parameters) extends BareCoreplex
with CoreplexNetwork
with CoreplexRISCVPlatform {
override lazy val module = new BaseCoreplexModule(this, () => new BaseCoreplexBundle(this))
}
class BaseCoreplexBundle[+L <: BaseCoreplex](_outer: L) extends BareCoreplexBundle(_outer)
with CoreplexNetworkBundle
with CoreplexRISCVPlatformBundle
class BaseCoreplexModule[+L <: BaseCoreplex, +B <: BaseCoreplexBundle[L]](_outer: L, _io: () => B) extends BareCoreplexModule(_outer, _io)
with CoreplexNetworkModule
with CoreplexRISCVPlatformModule

View File

@ -4,6 +4,7 @@ package coreplex
import Chisel._
import junctions._
import diplomacy._
import uncore.tilelink._
import uncore.coherence._
import uncore.agents._
@ -69,8 +70,8 @@ class BaseCoreplexConfig extends Config (
case NUncachedTileLinkPorts => 1
//Tile Constants
case BuildTiles => {
List.tabulate(site(NTiles)){ i => (r: Bool, p: Parameters) =>
Module(new RocketTile(resetSignal = r)(p.alterPartial({
List.tabulate(site(NTiles)){ i => (p: Parameters) =>
LazyModule(new RocketTile()(p.alterPartial({
case TileId => i
case TLId => "L1toL2"
case NUncachedTileLinkPorts => 1 + site(RoccNMemChannels)

View File

@ -3,14 +3,20 @@ package coreplex
import Chisel._
import cde.{Parameters, Field}
import junctions._
import diplomacy._
import uncore.tilelink._
import uncore.tilelink2._
import uncore.util._
import util._
import rocket._
trait DirectConnection {
val tiles: Seq[Tile]
val uncoreTileIOs: Seq[TileIO]
this: CoreplexNetwork with CoreplexRISCVPlatform =>
lazyTiles.map(_.slave).flatten.foreach { scratch => scratch := cbus.node }
}
trait DirectConnectionModule {
this: CoreplexNetworkModule with CoreplexRISCVPlatformModule =>
val tlBuffering = TileLinkDepths(1,1,2,2,0)
val ultBuffering = UncachedTileLinkDepths(1,2)
@ -18,7 +24,6 @@ trait DirectConnection {
(tiles zip uncoreTileIOs) foreach { case (tile, uncore) =>
(uncore.cached zip tile.io.cached) foreach { case (u, t) => u <> TileLinkEnqueuer(t, tlBuffering) }
(uncore.uncached zip tile.io.uncached) foreach { case (u, t) => u <> TileLinkEnqueuer(t, ultBuffering) }
tile.io.slave.foreach { _ <> TileLinkEnqueuer(uncore.slave.get, 1) }
tile.io.interrupts <> uncore.interrupts
@ -27,30 +32,54 @@ trait DirectConnection {
}
}
class DefaultCoreplex(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplex(c)(p) {
override lazy val module = Module(new DefaultCoreplexModule(c, this, new DefaultCoreplexBundle(c)(p))(p))
class DefaultCoreplex(implicit p: Parameters) extends BaseCoreplex
with DirectConnection {
override lazy val module = new DefaultCoreplexModule(this, () => new DefaultCoreplexBundle(this))
}
class DefaultCoreplexBundle(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplexBundle(c)(p)
class DefaultCoreplexBundle[+L <: DefaultCoreplex](_outer: L) extends BaseCoreplexBundle(_outer)
class DefaultCoreplexModule[+L <: DefaultCoreplex, +B <: DefaultCoreplexBundle](
c: CoreplexConfig, l: L, b: => B)(implicit p: Parameters) extends BaseCoreplexModule(c, l, b)(p)
with DirectConnection
class DefaultCoreplexModule[+L <: DefaultCoreplex, +B <: DefaultCoreplexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io)
with DirectConnectionModule
/////
trait TileClockResetBundle {
val c: CoreplexConfig
val tcrs = Vec(c.nTiles, new Bundle {
trait AsyncConnection {
this: CoreplexNetwork with CoreplexRISCVPlatform =>
val crossings = lazyTiles.map(_.slave).map(_.map { scratch =>
val crossing = LazyModule(new TLAsyncCrossing)
crossing.node := cbus.node
val monitor = (scratch := crossing.node)
(crossing, monitor)
})
}
trait AsyncConnectionBundle {
this: CoreplexNetworkBundle with CoreplexRISCVPlatformBundle =>
val tcrs = Vec(nTiles, new Bundle {
val clock = Clock(INPUT)
val reset = Bool(INPUT)
})
}
trait AsyncConnection {
val io: TileClockResetBundle
val tiles: Seq[Tile]
val uncoreTileIOs: Seq[TileIO]
trait AsyncConnectionModule {
this: Module with CoreplexNetworkModule with CoreplexRISCVPlatformModule {
val outer: AsyncConnection
val io: AsyncConnectionBundle
} =>
(outer.crossings zip io.tcrs) foreach { case (slaves, tcr) =>
slaves.foreach { case (crossing, monitor) =>
crossing.module.io.in_clock := clock
crossing.module.io.in_reset := reset
crossing.module.io.out_clock := tcr.clock
crossing.module.io.out_reset := tcr.reset
monitor.foreach { m =>
m.module.clock := tcr.clock
m.module.reset := tcr.reset
}
}
}
(tiles, uncoreTileIOs, io.tcrs).zipped foreach { case (tile, uncore, tcr) =>
tile.clock := tcr.clock
@ -58,7 +87,6 @@ trait AsyncConnection {
(uncore.cached zip tile.io.cached) foreach { case (u, t) => u <> AsyncTileLinkFrom(tcr.clock, tcr.reset, t) }
(uncore.uncached zip tile.io.uncached) foreach { case (u, t) => u <> AsyncUTileLinkFrom(tcr.clock, tcr.reset, t) }
tile.io.slave.foreach { _ <> AsyncUTileLinkTo(tcr.clock, tcr.reset, uncore.slave.get)}
val ti = tile.io.interrupts
val ui = uncore.interrupts
@ -73,13 +101,13 @@ trait AsyncConnection {
}
}
class MultiClockCoreplex(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplex(c)(p) {
override lazy val module = Module(new MultiClockCoreplexModule(c, this, new MultiClockCoreplexBundle(c)(p))(p))
class MultiClockCoreplex(implicit p: Parameters) extends BaseCoreplex
with AsyncConnection {
override lazy val module = new MultiClockCoreplexModule(this, () => new MultiClockCoreplexBundle(this))
}
class MultiClockCoreplexBundle(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplexBundle(c)(p)
with TileClockResetBundle
class MultiClockCoreplexBundle[+L <: MultiClockCoreplex](_outer: L) extends BaseCoreplexBundle(_outer)
with AsyncConnectionBundle
class MultiClockCoreplexModule[+L <: MultiClockCoreplex, +B <: MultiClockCoreplexBundle](
c: CoreplexConfig, l: L, b: => B)(implicit p: Parameters) extends BaseCoreplexModule(c, l, b)(p)
with AsyncConnection
class MultiClockCoreplexModule[+L <: MultiClockCoreplex, +B <: MultiClockCoreplexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io)
with AsyncConnectionModule

View File

@ -62,7 +62,7 @@ abstract class LazyModule
private def nodesGraphML(buf: StringBuilder, pad: String) {
buf ++= s"""${pad}<node id=\"${index}\">\n"""
buf ++= s"""${pad} <data key=\"n\"><y:ShapeNode><y:NodeLabel modelName=\"sides\" modelPosition=\"w\" fontSize=\"10\" borderDistance=\"1.0\" rotationAngle=\"270.0\">${module.name}</y:NodeLabel></y:ShapeNode></data>\n"""
buf ++= s"""${pad} <data key=\"n\"><y:ShapeNode><y:NodeLabel modelName=\"sides\" modelPosition=\"w\" rotationAngle=\"270.0\">${module.instanceName}</y:NodeLabel></y:ShapeNode></data>\n"""
buf ++= s"""${pad} <graph id=\"${index}::\" edgedefault=\"directed\">\n"""
nodes.filter(!_.omitGraphML).foreach { n =>
buf ++= s"""${pad} <node id=\"${index}::${n.index}\"/>\n"""
@ -72,11 +72,15 @@ abstract class LazyModule
buf ++= s"""${pad}</node>\n"""
}
private def edgesGraphML(buf: StringBuilder, pad: String) {
nodes.filter(!_.omitGraphML) foreach { n => n.outputs.filter(!_.omitGraphML).foreach { o =>
nodes.filter(!_.omitGraphML) foreach { n => n.outputs.filter(!_._1.omitGraphML).foreach { case (o, l) =>
buf ++= pad
buf ++= "<edge"
buf ++= s""" source=\"${index}::${n.index}\""""
buf ++= s""" target=\"${o.lazyModule.index}::${o.index}\"><data key=\"e\"><y:PolyLineEdge><y:Arrows source=\"none\" target=\"standard\"/><y:LineStyle color=\"${o.colour}\" type=\"line\" width=\"1.0\"/></y:PolyLineEdge></data></edge>\n"""
buf ++= s""" target=\"${o.lazyModule.index}::${o.index}\"><data key=\"e\"><y:PolyLineEdge>"""
buf ++= s"""<y:Arrows source=\"none\" target=\"standard\"/>"""
buf ++= s"""<y:LineStyle color=\"${o.colour}\" type=\"line\" width=\"1.0\"/>"""
buf ++= s"""<y:EdgeLabel modelName=\"centered\" rotationAngle=\"270.0\">${l}</y:EdgeLabel>"""
buf ++= s"""</y:PolyLineEdge></data></edge>\n"""
} }
children.filter(!_.omitGraphML).foreach { c => c.edgesGraphML(buf, pad) }
}

View File

@ -20,6 +20,7 @@ trait InwardNodeImp[DI, UI, EI, BI <: Data]
// optional methods to track node graph
def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu // insert node into parameters
def getO(pu: UI): Option[BaseNode] = None // most-outward common node
def labelI(ei: EI) = ""
}
// DO = Downwards flowing Parameters generated by the outer side of the node
@ -34,6 +35,7 @@ trait OutwardNodeImp[DO, UO, EO, BO <: Data]
// optional methods to track node graph
def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd // insert node into parameters
def getI(pd: DO): Option[BaseNode] = None // most-inward common node
def labelO(eo: EO) = ""
}
abstract class NodeImp[D, U, EO, EI, B <: Data]
@ -54,8 +56,8 @@ abstract class BaseNode
protected[diplomacy] def gci: Option[BaseNode] // greatest common inner
protected[diplomacy] def gco: Option[BaseNode] // greatest common outer
protected[diplomacy] def outputs: Seq[BaseNode]
protected[diplomacy] def inputs: Seq[BaseNode]
protected[diplomacy] def outputs: Seq[(BaseNode, String)]
protected[diplomacy] def inputs: Seq[(BaseNode, String)]
protected[diplomacy] def colour: String
}
@ -94,7 +96,7 @@ trait InwardNode[DI, UI, BI <: Data] extends BaseNode with InwardNodeHandle[DI,
protected[diplomacy] lazy val iPorts = { iRealized = true; reqI(); accPI.result() }
protected[diplomacy] val iParams: Seq[UI]
protected[diplomacy] def iConnect: Vec[BI]
val bundleIn: Vec[BI]
}
trait OutwardNodeHandle[DO, UO, BO <: Data]
@ -126,7 +128,7 @@ trait OutwardNode[DO, UO, BO <: Data] extends BaseNode with OutwardNodeHandle[DO
protected[diplomacy] lazy val oPorts = { oRealized = true; reqO(); accPO.result() }
protected[diplomacy] val oParams: Seq[DO]
protected[diplomacy] def oConnect: Vec[BO]
val bundleOut: Vec[BO]
}
class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
@ -140,8 +142,8 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
{
// meta-data for printing the node graph
protected[diplomacy] def colour = inner.colour
protected[diplomacy] def outputs = oPorts.map(_._2)
protected[diplomacy] def inputs = iPorts.map(_._2)
protected[diplomacy] def outputs = oPorts.map(_._2) zip edgesOut.map(e => outer.labelO(e))
protected[diplomacy] def inputs = iPorts.map(_._2) zip edgesIn .map(e => inner.labelI(e))
private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}")
protected[diplomacy] lazy val oParams: Seq[DO] = {
@ -161,11 +163,15 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => outer.edgeO(o, n.iParams(i)) }
lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => inner.edgeI(n.oParams(o), i) }
lazy val bundleOut = outer.bundleO(edgesOut)
lazy val bundleIn = inner.bundleI(edgesIn)
val flip = false // needed for blind nodes
private def flipO(b: Vec[BO]) = if (flip) b.flip else b
private def flipI(b: Vec[BI]) = if (flip) b else b.flip
val wire = false // needed if you want to grab access to from inside a module
private def wireO(b: Vec[BO]) = if (wire) Wire(b) else b
private def wireI(b: Vec[BI]) = if (wire) Wire(b) else b
def oConnect = bundleOut
def iConnect = bundleIn
lazy val bundleOut = wireO(flipO(outer.bundleO(edgesOut)))
lazy val bundleIn = wireI(flipI(inner.bundleI(edgesIn)))
// connects the outward part of a node with the inward part of this node
override def := (h: OutwardNodeHandle[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
@ -177,7 +183,7 @@ class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
val o = y.oPushed
y.oPush(i, x)
x.iPush(o, y)
val (out, binding) = inner.connect(y.oConnect(o), x.iConnect(i), x.edgesIn(i))
val (out, binding) = inner.connect(y.bundleOut(o), x.bundleIn(i), x.edgesIn(i))
LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings
out
}
@ -195,26 +201,54 @@ class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
{
override def oConnect = bundleOut
override def iConnect = bundleOut
override lazy val bundleIn = bundleOut
}
class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
{
override def oConnect = bundleIn
override def iConnect = bundleIn
override lazy val bundleOut = bundleIn
}
class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1)
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0)
{
require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}")
override lazy val bundleIn = { require(false, s"${name} has no bundleIn; try bundleOut?"); bundleOut }
}
class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1)
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num)
{
require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}")
override lazy val bundleOut = { require(false, s"${name} has no bundleOut; try bundleIn?"); bundleIn }
}
class BlindOutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI)
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, 1 to 1)
{
override val flip = true
override lazy val bundleOut = bundleIn
}
class BlindInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO)
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, 1 to 1, 0 to 0)
{
override val flip = true
override lazy val bundleIn = bundleOut
}
class InternalOutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI)
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, 1 to 1)
{
override val wire = true
override lazy val bundleOut = bundleIn
}
class InternalInputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO)
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, 1 to 1, 0 to 0)
{
override val wire = true
override lazy val bundleIn = bundleOut
}
class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])

View File

@ -72,8 +72,6 @@ class Edge32BitMemtestConfig extends Config(
/* Composable Configs to set individual parameters */
class WithGroundTest extends Config(
(pname, site, here) => pname match {
case BuildCoreplex =>
(c: CoreplexConfig, p: Parameters) => LazyModule(new GroundTestCoreplex(c)(p)).module
case TLKey("L1toL2") => {
val useMEI = site(NTiles) <= 1 && site(NCachedTileLinkPorts) <= 1
val dataBeats = (8 * site(CacheBlockBytes)) / site(XLen)
@ -95,8 +93,8 @@ class WithGroundTest extends Config(
case BuildTiles => {
(0 until site(NTiles)).map { i =>
val tileSettings = site(GroundTestKey)(i)
(r: Bool, p: Parameters) => {
Module(new GroundTestTile(resetSignal = r)(p.alterPartial({
(p: Parameters) => {
LazyModule(new GroundTestTile()(p.alterPartial({
case TLId => "L1toL2"
case TileId => i
case NCachedTileLinkPorts => if(tileSettings.cached > 0) 1 else 0
@ -106,7 +104,7 @@ class WithGroundTest extends Config(
}
}
case BuildExampleTop =>
(p: Parameters) => LazyModule(new ExampleTopWithTestRAM(p))
(p: Parameters) => LazyModule(new ExampleTopWithTestRAM(new GroundTestCoreplex()(_))(p))
case FPUKey => None
case UseAtomics => false
case UseCompressed => false
@ -116,12 +114,12 @@ class WithGroundTest extends Config(
class WithComparator extends Config(
(pname, site, here) => pname match {
case GroundTestKey => Seq.fill(site(NTiles)) {
GroundTestTileSettings(uncached = site(ComparatorKey).targets.size)
GroundTestTileSettings(uncached = 2)
}
case BuildGroundTest =>
(p: Parameters) => Module(new ComparatorCore()(p))
case ComparatorKey => ComparatorParameters(
targets = Seq("mem", "io:pbus:TL2:testram").map(name =>
targets = Seq("mem", "TL2:testram").map(name =>
site(GlobalAddrMap)(name).start.longValue),
width = 8,
operations = 1000,

View File

@ -4,13 +4,14 @@ import Chisel._
import cde.{Parameters}
import coreplex._
class GroundTestCoreplex(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplex(c)(p) {
override lazy val module = Module(new GroundTestCoreplexModule(c, this, new GroundTestCoreplexBundle(c)(p))(p))
class GroundTestCoreplex(implicit p: Parameters) extends BaseCoreplex
with DirectConnection {
override lazy val module = new GroundTestCoreplexModule(this, () => new GroundTestCoreplexBundle(this))
}
class GroundTestCoreplexBundle(c: CoreplexConfig)(implicit p: Parameters) extends BaseCoreplexBundle(c)(p)
class GroundTestCoreplexBundle[+L <: GroundTestCoreplex](_outer: L) extends BaseCoreplexBundle(_outer)
class GroundTestCoreplexModule[+L <: GroundTestCoreplex, +B <: GroundTestCoreplexBundle](
c: CoreplexConfig, l: L, b: => B)(implicit p: Parameters) extends BaseCoreplexModule(c, l, b)(p) with DirectConnection {
class GroundTestCoreplexModule[+L <: GroundTestCoreplex, +B <: GroundTestCoreplexBundle[L]](_outer: L, _io: () => B) extends BaseCoreplexModule(_outer, _io)
with DirectConnectionModule {
io.success := tiles.flatMap(_.io.elements get "success").map(_.asInstanceOf[Bool]).reduce(_&&_)
}

View File

@ -5,6 +5,7 @@ package groundtest
object Generator extends util.GeneratorApp {
val longName = names.topModuleProject + "." + names.configs
generateFirrtl
generateGraphML
generateTestSuiteMakefrags // TODO: Needed only for legacy make targets
generateParameterDump // TODO: Needed only for legacy make targets
}

View File

@ -71,7 +71,7 @@ class IOGetAfterPutBlockRegression(implicit p: Parameters) extends Regression()(
io.mem.grant.ready := Bool(true)
io.cache.req.valid := !get_sent && started
io.cache.req.bits.addr := UInt(addrMap("io:pbus:TL2:bootrom").start)
io.cache.req.bits.addr := UInt(addrMap("TL2:bootrom").start)
io.cache.req.bits.typ := MT_WU
io.cache.req.bits.cmd := M_XRD
io.cache.req.bits.tag := UInt(0)

View File

@ -96,12 +96,10 @@ abstract class GroundTest(implicit val p: Parameters) extends Module
val io = new GroundTestIO
}
class GroundTestTile(resetSignal: Bool)
(implicit val p: Parameters)
extends Tile(resetSignal = resetSignal)(p)
with HasGroundTestParameters {
override val io = new TileIO(bc) {
class GroundTestTile(implicit val p: Parameters) extends LazyTile {
val slave = None
lazy val module = new TileImp(this) with HasGroundTestParameters {
val io = new TileIO(bc) {
val success = Bool(OUTPUT)
}
@ -140,4 +138,5 @@ class GroundTestTile(resetSignal: Bool)
}
io.success := test.io.status.finished
}
}

View File

@ -76,12 +76,7 @@ class AddrMap(
var cacheable = true
for (AddrMapEntry(name, r) <- entriesIn) {
require (!mapping.contains(name))
if (r.start != 0) {
base = r.start
} else {
base = (base + r.size - 1) / r.size * r.size
}
r match {
case r: AddrMap =>

View File

@ -4,7 +4,9 @@ package rocket
import Chisel._
import junctions._
import diplomacy._
import uncore.tilelink._
import uncore.tilelink2._
import uncore.agents._
import uncore.coherence._
import uncore.constants._
@ -125,7 +127,7 @@ class DCache(implicit p: Parameters) extends L1HellaCacheModule()(p) {
require(nWays == 1)
metaWriteArb.io.out.ready := true
metaReadArb.io.out.ready := !metaWriteArb.io.out.valid
val inScratchpad = addrMap(s"io:cbus:dmem${tileId}").containsAddress(s1_paddr)
val inScratchpad = addrMap(s"TL2:dmem${tileId}").containsAddress(s1_paddr)
val hitState = Mux(inScratchpad, ClientMetadata.onReset.onHit(M_XWR), ClientMetadata.onReset)
(inScratchpad, hitState, L1Metadata(UInt(0), ClientMetadata.onReset))
} else {
@ -495,60 +497,97 @@ class DCache(implicit p: Parameters) extends L1HellaCacheModule()(p) {
}
}
class ScratchpadSlavePort(implicit p: Parameters) extends CoreModule()(p) {
class ScratchpadSlavePort(implicit val p: Parameters) extends LazyModule with HasCoreParameters {
val node = TLManagerNode(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(AddressSet(0x80000000L, BigInt(p(DataScratchpadSize)-1))),
regionType = RegionType.UNCACHED,
executable = true,
supportsArithmetic = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsLogical = if (p(UseAtomics)) TransferSizes(1, coreDataBytes) else TransferSizes.none,
supportsPutPartial = TransferSizes(1, coreDataBytes),
supportsPutFull = TransferSizes(1, coreDataBytes),
supportsGet = TransferSizes(1, coreDataBytes),
fifoId = Some(0))), // requests handled in FIFO order
beatBytes = coreDataBytes,
minLatency = 1))
// Make sure this ends up with the same name as before
override def name = "dmem0"
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl = new ClientUncachedTileLinkIO().flip
val tl_in = node.bundleIn
val dmem = new HellaCacheIO
}
val tl_in = io.tl_in(0)
val edge = node.edgesIn(0)
require(usingDataScratchpad)
val s_ready :: s_wait :: s_replay :: s_grant :: Nil = Enum(UInt(), 4)
val state = Reg(init = s_ready)
when (io.dmem.resp.valid) { state := s_grant }
when (io.tl.grant.fire()) { state := s_ready }
when (tl_in.d.fire()) { state := s_ready }
when (io.dmem.s2_nack) { state := s_replay }
when (io.dmem.req.fire()) { state := s_wait }
val acq = Reg(io.tl.acquire.bits)
val acq = Reg(tl_in.a.bits)
when (io.dmem.resp.valid) { acq.data := io.dmem.resp.bits.data }
when (io.tl.acquire.fire()) { acq := io.tl.acquire.bits }
when (tl_in.a.fire()) { acq := tl_in.a.bits }
val isRead = acq.isBuiltInType(Acquire.getType)
val isWrite = acq.isBuiltInType(Acquire.putType)
assert(state === s_ready || isRead || isWrite)
require(coreDataBits == acq.tlDataBits)
require(usingDataScratchpad)
val isWrite = acq.opcode === TLMessages.PutFullData || acq.opcode === TLMessages.PutPartialData
val isRead = !edge.hasData(acq)
def formCacheReq(acq: Acquire) = {
def formCacheReq(acq: TLBundleA) = {
val req = Wire(new HellaCacheReq)
req.cmd := MuxLookup(acq.opcode, Wire(M_XRD), Array(
TLMessages.PutFullData -> M_XWR,
TLMessages.PutPartialData -> M_XWR,
TLMessages.ArithmeticData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.MIN -> M_XA_MIN,
TLAtomics.MAX -> M_XA_MAX,
TLAtomics.MINU -> M_XA_MINU,
TLAtomics.MAXU -> M_XA_MAXU,
TLAtomics.ADD -> M_XA_ADD)),
TLMessages.LogicalData -> MuxLookup(acq.param, Wire(M_XRD), Array(
TLAtomics.XOR -> M_XA_XOR,
TLAtomics.OR -> M_XA_OR,
TLAtomics.AND -> M_XA_AND,
TLAtomics.SWAP -> M_XA_SWAP)),
TLMessages.Get -> M_XRD))
// treat all loads as full words, so bytes appear in correct lane
req.typ := Mux(isRead, log2Ceil(acq.tlDataBytes), acq.op_size())
req.cmd := acq.op_code()
req.addr := Mux(isRead, ~(~acq.full_addr() | (acq.tlDataBytes-1)), acq.full_addr())
req.typ := Mux(isRead, log2Ceil(coreDataBytes), acq.size)
req.addr := Mux(isRead, ~(~acq.address | (coreDataBytes-1)), acq.address)
req.tag := UInt(0)
req
}
val ready = state === s_ready || io.tl.grant.fire()
io.dmem.req.valid := (io.tl.acquire.valid && ready) || state === s_replay
io.tl.acquire.ready := io.dmem.req.ready && ready
io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, io.tl.acquire.bits))
// this blows. the TL data is already in the correct byte lane, but the D$
val ready = state === s_ready || tl_in.d.fire()
io.dmem.req.valid := (tl_in.a.valid && ready) || state === s_replay
tl_in.a.ready := io.dmem.req.ready && ready
io.dmem.req.bits := formCacheReq(Mux(state === s_replay, acq, tl_in.a.bits))
// the TL data is already in the correct byte lane, but the D$
// expects right-justified store data, so that it can steer the bytes.
io.dmem.s1_data := new LoadGen(acq.op_size(), Bool(false), acq.addr_byte(), acq.data, Bool(false), acq.tlDataBytes).data
io.dmem.s1_data := new LoadGen(acq.size, Bool(false), acq.address(log2Ceil(coreDataBytes)-1,0), acq.data, Bool(false), coreDataBytes).data
io.dmem.s1_kill := false
io.dmem.invalidate_lr := false
// place AMO data in correct word lane
val minAMOBytes = 4
val grantData = Mux(io.dmem.resp.valid, io.dmem.resp.bits.data, acq.data)
val alignedGrantData = Mux(acq.op_size() <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData)
val alignedGrantData = Mux(acq.size <= log2Ceil(minAMOBytes), Fill(coreDataBytes/minAMOBytes, grantData(8*minAMOBytes-1, 0)), grantData)
io.tl.grant.valid := io.dmem.resp.valid || state === s_grant
io.tl.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = acq.getBuiltInGrantType(),
client_xact_id = acq.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = acq.addr_beat,
data = alignedGrantData)
tl_in.d.valid := io.dmem.resp.valid || state === s_grant
tl_in.d.bits := Mux(isWrite,
edge.AccessAck(acq, UInt(0)),
edge.AccessAck(acq, UInt(0), UInt(0)))
tl_in.d.bits.data := alignedGrantData
// Tie off unused channels
tl_in.b.valid := Bool(false)
tl_in.c.ready := Bool(true)
tl_in.e.ready := Bool(true)
}
}

View File

@ -3,7 +3,9 @@
package rocket
import Chisel._
import diplomacy._
import uncore.tilelink._
import uncore.tilelink2._
import uncore.agents._
import uncore.converters._
import uncore.devices._
@ -25,36 +27,44 @@ case class RoccParameters(
case class TileBundleConfig(
nCachedTileLinkPorts: Int,
nUncachedTileLinkPorts: Int,
xLen: Int,
hasSlavePort: Boolean)
xLen: Int)
class TileIO(c: TileBundleConfig)(implicit p: Parameters) extends Bundle {
class TileIO(c: TileBundleConfig, node: Option[TLInwardNode] = None)(implicit p: Parameters) extends Bundle {
val cached = Vec(c.nCachedTileLinkPorts, new ClientTileLinkIO)
val uncached = Vec(c.nUncachedTileLinkPorts, new ClientUncachedTileLinkIO)
val hartid = UInt(INPUT, c.xLen)
val interrupts = new TileInterrupts().asInput
val slave = c.hasSlavePort.option(new ClientUncachedTileLinkIO().flip)
val slave = node.map(_.inward.bundleIn)
val resetVector = UInt(INPUT, c.xLen)
override def cloneType = new TileIO(c).asInstanceOf[this.type]
}
abstract class Tile(clockSignal: Clock = null, resetSignal: Bool = null)
(implicit p: Parameters) extends Module(Option(clockSignal), Option(resetSignal)) {
abstract class TileImp(l: LazyTile)(implicit val p: Parameters) extends LazyModuleImp(l) {
val io: TileIO
}
abstract class LazyTile(implicit p: Parameters) extends LazyModule {
val nCachedTileLinkPorts = p(NCachedTileLinkPorts)
val nUncachedTileLinkPorts = p(NUncachedTileLinkPorts)
val dcacheParams = p.alterPartial({ case CacheName => "L1D" })
val bc = TileBundleConfig(
nCachedTileLinkPorts = nCachedTileLinkPorts,
nUncachedTileLinkPorts = nUncachedTileLinkPorts,
xLen = p(XLen),
hasSlavePort = p(DataScratchpadSize) > 0)
xLen = p(XLen))
val io = new TileIO(bc)
val module: TileImp
val slave: Option[TLInputNode]
}
class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
(implicit p: Parameters) extends Tile(clockSignal, resetSignal)(p) {
class RocketTile(implicit p: Parameters) extends LazyTile {
val slave = if (p(DataScratchpadSize) == 0) None else Some(TLInputNode())
val scratch = if (p(DataScratchpadSize) == 0) None else Some(LazyModule(new ScratchpadSlavePort()(dcacheParams)))
(slave zip scratch) foreach { case (node, lm) => lm.node := TLFragmenter(p(XLen)/8, p(CacheBlockBytes))(node) }
lazy val module = new TileImp(this) {
val io = new TileIO(bc, slave)
val buildRocc = p(BuildRoCC)
val usingRocc = !buildRocc.isEmpty
val nRocc = buildRocc.size
@ -140,11 +150,7 @@ class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
core.io.ptw <> ptw.io.dpath
}
io.slave foreach { case slavePort =>
val adapter = Module(new ScratchpadSlavePort()(dcacheParams))
adapter.io.tl <> TileLinkFragmenter(slavePort)
adapter.io.dmem +=: dcPorts
}
scratch.foreach { lm => lm.module.io.dmem +=: dcPorts }
require(dcPorts.size == core.dcacheArbPorts)
val dcArb = Module(new HellaCacheArbiter(dcPorts.size)(dcacheParams))
@ -157,4 +163,5 @@ class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
fpu.io.cp_resp.ready := Bool(false)
}
}
}
}

View File

@ -15,103 +15,97 @@ import coreplex._
// the following parameters will be refactored properly with TL2
case object GlobalAddrMap extends Field[AddrMap]
case object ConfigString extends Field[String]
case object NCoreplexExtClients extends Field[Int]
/** Enable or disable monitoring of Diplomatic buses */
case object TLEmitMonitors extends Field[Bool]
/** Function for building Coreplex */
case object BuildCoreplex extends Field[(CoreplexConfig, Parameters) => BaseCoreplexModule[BaseCoreplex, BaseCoreplexBundle]]
/** Base Top with no Periphery */
abstract class BaseTop(q: Parameters) extends LazyModule {
// the following variables will be refactored properly with TL2
val pInterrupts = new RangeManager
abstract class BareTop[+C <: BaseCoreplex](_coreplex: Parameters => C)(implicit val q: Parameters) extends LazyModule {
// Fill in the TL1 legacy parameters; remove these once rocket/groundtest/unittest are TL2
val pBusMasters = new RangeManager
val pDevices = new ResourceManager[AddrMapEntry]
TLImp.emitMonitors = q(TLEmitMonitors)
// Add a SoC and peripheral bus
val socBus = LazyModule(new TLXbar)
val peripheryBus = LazyModule(new TLXbar)
lazy val peripheryManagers = socBus.node.edgesIn(0).manager.managers
lazy val c = CoreplexConfig(
nTiles = q(NTiles),
nExtInterrupts = pInterrupts.sum,
nSlaves = pBusMasters.sum,
nMemChannels = q(NMemoryChannels),
hasSupervisor = q(UseVM)
)
lazy val genGlobalAddrMap = GenerateGlobalAddrMap(q, pDevices.get, peripheryManagers)
private val qWithMap = q.alterPartial({case GlobalAddrMap => genGlobalAddrMap})
lazy val genConfigString = GenerateConfigString(qWithMap, c, pDevices.get, peripheryManagers)
implicit val p = qWithMap.alterPartial({
case ConfigString => genConfigString
case NCoreplexExtClients => pBusMasters.sum})
val legacy = LazyModule(new TLLegacy()(p.alterPartial({ case TLId => "L2toMMIO" })))
peripheryBus.node :=
TLWidthWidget(p(SOCBusKey).beatBytes)(
TLBuffer()(
TLAtomicAutomata(arithmetic = p(PeripheryBusKey).arithAMO)(
socBus.node)))
socBus.node :=
TLWidthWidget(legacy.tlDataBytes)(
TLHintHandler()(
legacy.node))
lazy val legacyAddrMap = GenerateGlobalAddrMap(q, coreplex.l1tol2.node.edgesIn(0).manager.managers)
val coreplex : C = LazyModule(_coreplex(q.alterPartial {
case NCoreplexExtClients => pBusMasters.sum
case GlobalAddrMap => legacyAddrMap
}))
TopModule.contents = Some(this)
}
abstract class BaseTopBundle(val p: Parameters) extends Bundle {
abstract class BareTopBundle[+L <: BareTop[BaseCoreplex]](_outer: L) extends Bundle {
val outer = _outer
}
abstract class BareTopModule[+L <: BareTop[BaseCoreplex], +B <: BareTopBundle[L]](_outer: L, _io: () => B) extends LazyModuleImp(_outer) {
val outer = _outer
val io = _io ()
}
/** Base Top with no Periphery */
trait TopNetwork extends HasPeripheryParameters {
this: BareTop[BaseCoreplex] =>
implicit val p = q
TLImp.emitMonitors = p(TLEmitMonitors)
// Add a SoC and peripheral bus
val socBus = LazyModule(new TLXbar)
val peripheryBus = LazyModule(new TLXbar)
val intBus = LazyModule(new IntXbar)
peripheryBus.node :=
TLWidthWidget(p(SOCBusKey).beatBytes)(
TLAtomicAutomata(arithmetic = p(PeripheryBusKey).arithAMO)(
socBus.node))
}
trait TopNetworkBundle extends HasPeripheryParameters {
this: BareTopBundle[BareTop[BaseCoreplex]] =>
implicit val p = outer.q
val success = Bool(OUTPUT)
}
abstract class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](
val p: Parameters, l: L, b: => B) extends LazyModuleImp(l) {
val outer: L = l
val io: B = b
trait TopNetworkModule extends HasPeripheryParameters {
this: {
val outer: BareTop[BaseCoreplex] with TopNetwork
val io: TopNetworkBundle
} =>
implicit val p = outer.p
val coreplex = p(BuildCoreplex)(outer.c, p)
val coreplexIO = Wire(coreplex.io)
val coreplexMem : Vec[ClientUncachedTileLinkIO] = Wire(outer.coreplex.module.io.mem)
val coreplexSlave: Vec[ClientUncachedTileLinkIO] = Wire(outer.coreplex.module.io.slave)
val coreplexDebug: DebugBusIO = Wire(outer.coreplex.module.io.debug)
val coreplexRtc : Bool = Wire(outer.coreplex.module.io.rtcTick)
val pBus =
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).subMap("io:pbus"))(
p.alterPartial({ case TLId => "L2toMMIO" })))
pBus.io.in.head <> coreplexIO.master.mmio
outer.legacy.module.io.legacy <> pBus.port("TL2")
io.success := outer.coreplex.module.io.success
println("Generated Address Map")
for (entry <- p(GlobalAddrMap).flatten) {
val name = entry.name
val start = entry.region.start
val end = entry.region.start + entry.region.size - 1
val prot = entry.region.attr.prot
val protStr = (if ((prot & AddrMapProt.R) > 0) "R" else "") +
(if ((prot & AddrMapProt.W) > 0) "W" else "") +
(if ((prot & AddrMapProt.X) > 0) "X" else "")
val cacheable = if (entry.region.attr.cacheable) " [C]" else ""
println(f"\t$name%s $start%x - $end%x, $protStr$cacheable")
}
println("\nGenerated Interrupt Vector")
outer.pInterrupts.print
println("\nGenerated Configuration String")
println(p(ConfigString))
ConfigStringOutput.contents = Some(p(ConfigString))
io.success := coreplexIO.success
outer.coreplex.module.io.rtcTick := coreplexRtc
coreplexRtc := Counter(p(rocketchip.RTCPeriod)).inc()
}
/** Base Top with no Periphery */
class BaseTop[+C <: BaseCoreplex](_coreplex: Parameters => C)(implicit p: Parameters) extends BareTop(_coreplex)
with TopNetwork {
override lazy val module = new BaseTopModule(this, () => new BaseTopBundle(this))
}
class BaseTopBundle[+L <: BaseTop[BaseCoreplex]](_outer: L) extends BareTopBundle(_outer)
with TopNetworkBundle
class BaseTopModule[+L <: BaseTop[BaseCoreplex], +B <: BaseTopBundle[L]](_outer: L, _io: () => B) extends BareTopModule(_outer, _io)
with TopNetworkModule
trait DirectConnection {
val coreplexIO: BaseCoreplexBundle
val coreplex: BaseCoreplexModule[BaseCoreplex, BaseCoreplexBundle]
this: BareTop[BaseCoreplex] with TopNetwork =>
coreplexIO <> coreplex.io
socBus.node := coreplex.mmio
coreplex.mmioInt := intBus.intnode
}
trait DirectConnectionModule {
this: TopNetworkModule {
val outer: BaseTop[BaseCoreplex]
} =>
coreplexMem <> outer.coreplex.module.io.mem
outer.coreplex.module.io.slave <> coreplexSlave
outer.coreplex.module.io.debug <> coreplexDebug
}

View File

@ -40,19 +40,12 @@ class BasePlatformConfig extends Config(
site(TLKey("L2toMC")).copy(dataBeats = edgeDataBeats)
case TLKey("MMIOtoEdge") =>
site(TLKey("L2toMMIO")).copy(dataBeats = edgeDataBeats)
case BuildCoreplex =>
(c: CoreplexConfig, p: Parameters) => LazyModule(new DefaultCoreplex(c)(p)).module
case NExtTopInterrupts => 2
case SOCBusKey => SOCBusConfig(beatBytes = site(TLKey("L2toMMIO")).dataBitsPerBeat/8)
case PeripheryBusKey => PeripheryBusConfig(arithAMO = true, beatBytes = 4)
// Note that PLIC asserts that this is > 0.
case AsyncDebugBus => false
case IncludeJtagDTM => false
case AsyncMMIOChannels => false
case ExtMMIOPorts => Nil
case NExtMMIOAXIChannels => 0
case NExtMMIOAHBChannels => 0
case NExtMMIOTLChannels => 0
case AsyncBusChannels => false
case NExtBusAXIChannels => 0
case HastiId => "Ext"
@ -70,7 +63,7 @@ class BasePlatformConfig extends Config(
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
case BuildExampleTop =>
(p: Parameters) => LazyModule(new ExampleTop(p))
(p: Parameters) => LazyModule(new ExampleTop(new DefaultCoreplex()(_))(p))
case SimMemLatency => 0
case _ => throw new CDEMatchError
}
@ -110,17 +103,6 @@ class WithExtMemSize(n: Long) extends Config(
case _ => throw new CDEMatchError
}
)
class WithAHB extends Config(
(pname, site, here) => pname match {
case TMemoryChannels => BusType.AHB
case NExtMMIOAHBChannels => 1
})
class WithTL extends Config(
(pname, site, here) => pname match {
case TMemoryChannels => BusType.TL
case NExtMMIOTLChannels => 1
})
class WithScratchpads extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))

View File

@ -9,45 +9,43 @@ import coreplex._
import rocketchip._
/** Example Top with Periphery */
class ExampleTop(q: Parameters) extends BaseTop(q)
class ExampleTop[+C <: BaseCoreplex](_coreplex: Parameters => C)(implicit p: Parameters) extends BaseTop(_coreplex)
with PeripheryBootROM
with PeripheryDebug
with PeripheryExtInterrupts
with PeripheryCoreplexLocalInterrupter
with PeripheryMasterMem
with PeripheryMasterMMIO
with PeripherySlave {
override lazy val module = Module(new ExampleTopModule(p, this, new ExampleTopBundle(p)))
with PeripheryMasterAXI4MMIO
with PeripherySlave
with DirectConnection {
override lazy val module = new ExampleTopModule(this, () => new ExampleTopBundle(this))
}
class ExampleTopBundle(p: Parameters) extends BaseTopBundle(p)
class ExampleTopBundle[+L <: ExampleTop[BaseCoreplex]](_outer: L) extends BaseTopBundle(_outer)
with PeripheryBootROMBundle
with PeripheryDebugBundle
with PeripheryExtInterruptsBundle
with PeripheryCoreplexLocalInterrupterBundle
with PeripheryMasterMemBundle
with PeripheryMasterMMIOBundle
with PeripheryMasterAXI4MMIOBundle
with PeripherySlaveBundle
class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters, l: L, b: => B) extends BaseTopModule(p, l, b)
class ExampleTopModule[+L <: ExampleTop[BaseCoreplex], +B <: ExampleTopBundle[L]](_outer: L, _io: () => B) extends BaseTopModule(_outer, _io)
with PeripheryBootROMModule
with PeripheryDebugModule
with PeripheryExtInterruptsModule
with PeripheryCoreplexLocalInterrupterModule
with PeripheryMasterMemModule
with PeripheryMasterMMIOModule
with PeripheryMasterAXI4MMIOModule
with PeripherySlaveModule
with HardwiredResetVector
with DirectConnection
with DirectConnectionModule
/** Example Top with TestRAM */
class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q)
class ExampleTopWithTestRAM[+C <: BaseCoreplex](_coreplex: Parameters => C)(implicit p: Parameters) extends ExampleTop(_coreplex)
with PeripheryTestRAM {
override lazy val module = Module(new ExampleTopWithTestRAMModule(p, this, new ExampleTopWithTestRAMBundle(p)))
override lazy val module = new ExampleTopWithTestRAMModule(this, () => new ExampleTopWithTestRAMBundle(this))
}
class ExampleTopWithTestRAMBundle(p: Parameters) extends ExampleTopBundle(p)
class ExampleTopWithTestRAMBundle[+L <: ExampleTopWithTestRAM[BaseCoreplex]](_outer: L) extends ExampleTopBundle(_outer)
with PeripheryTestRAMBundle
class ExampleTopWithTestRAMModule[+L <: ExampleTopWithTestRAM, +B <: ExampleTopWithTestRAMBundle](p: Parameters, l: L, b: => B) extends ExampleTopModule(p, l, b)
class ExampleTopWithTestRAMModule[+L <: ExampleTopWithTestRAM[BaseCoreplex], +B <: ExampleTopWithTestRAMBundle[L]](_outer: L, _io: () => B) extends ExampleTopModule(_outer, _io)
with PeripheryTestRAMModule

View File

@ -9,6 +9,7 @@ import junctions.NastiConstants._
import diplomacy._
import uncore.tilelink._
import uncore.tilelink2._
import uncore.axi4._
import uncore.converters._
import uncore.devices._
import uncore.agents._
@ -29,19 +30,12 @@ object BusType {
/** Memory channel controls */
case object TMemoryChannels extends Field[BusType.EnumVal]
/** External MMIO controls */
case object NExtMMIOAXIChannels extends Field[Int]
case object NExtMMIOAHBChannels extends Field[Int]
case object NExtMMIOTLChannels extends Field[Int]
/** External Bus controls */
case object NExtBusAXIChannels extends Field[Int]
/** Async configurations */
case object AsyncBusChannels extends Field[Boolean]
case object AsyncDebugBus extends Field[Boolean]
case object AsyncMemChannels extends Field[Boolean]
case object AsyncMMIOChannels extends Field[Boolean]
/** External address map settings */
case object ExtMMIOPorts extends Field[Seq[AddrMapEntry]]
/** Specifies the size of external memory */
case object ExtMemSize extends Field[Long]
/** Specifies the number of external interrupts */
@ -89,10 +83,8 @@ trait HasPeripheryParameters {
lazy val nMemAXIChannels = if (tMemChannels == BusType.AXI) nMemChannels else 0
lazy val nMemAHBChannels = if (tMemChannels == BusType.AHB) nMemChannels else 0
lazy val nMemTLChannels = if (tMemChannels == BusType.TL) nMemChannels else 0
lazy val outerMMIOParams = p.alterPartial({ case TLId => "L2toMMIO" })
lazy val edgeSlaveParams = p.alterPartial({ case TLId => "EdgetoSlave" })
lazy val edgeMemParams = p.alterPartial({ case TLId => "MCtoEdge" })
lazy val edgeMMIOParams = p.alterPartial({ case TLId => "MMIOtoEdge" })
lazy val peripheryBusConfig = p(PeripheryBusKey)
lazy val socBusConfig = p(SOCBusKey)
lazy val cacheBlockBytes = p(CacheBlockBytes)
@ -100,12 +92,14 @@ trait HasPeripheryParameters {
/////
trait PeripheryDebug extends LazyModule {
implicit val p: Parameters
trait PeripheryDebug {
this: TopNetwork =>
}
trait PeripheryDebugBundle {
implicit val p: Parameters
this: TopNetworkBundle {
val outer: PeripheryDebug
} =>
val debug_clk = (p(AsyncDebugBus) && !p(IncludeJtagDTM)).option(Clock(INPUT))
val debug_rst = (p(AsyncDebugBus) && !p(IncludeJtagDTM)).option(Bool(INPUT))
val debug = (!p(IncludeJtagDTM)).option(new DebugBusIO()(p).flip)
@ -113,19 +107,19 @@ trait PeripheryDebugBundle {
}
trait PeripheryDebugModule {
implicit val p: Parameters
this: TopNetworkModule {
val outer: PeripheryDebug
val io: PeripheryDebugBundle
val coreplexIO: BaseCoreplexBundle
} =>
if (p(IncludeJtagDTM)) {
// JtagDTMWithSync is a wrapper which
// handles the synchronization as well.
val dtm = Module (new JtagDTMWithSync()(p))
dtm.io.jtag <> io.jtag.get
coreplexIO.debug <> dtm.io.debug
coreplexDebug <> dtm.io.debug
} else {
coreplexIO.debug <>
coreplexDebug <>
(if (p(AsyncDebugBus)) AsyncDebugBusFrom(io.debug_clk.get, io.debug_rst.get, io.debug.get)
else io.debug.get)
}
@ -133,40 +127,40 @@ trait PeripheryDebugModule {
/////
trait PeripheryExtInterrupts extends LazyModule {
implicit val p: Parameters
val pInterrupts: RangeManager
trait PeripheryExtInterrupts {
this: TopNetwork =>
pInterrupts.add("ext", p(NExtTopInterrupts))
val extInterrupts = IntBlindInputNode(p(NExtTopInterrupts))
val extInterruptXing = LazyModule(new IntXing)
intBus.intnode := extInterruptXing.intnode
extInterruptXing.intnode := extInterrupts
}
trait PeripheryExtInterruptsBundle {
implicit val p: Parameters
val interrupts = Vec(p(NExtTopInterrupts), Bool()).asInput
this: TopNetworkBundle {
val outer: PeripheryExtInterrupts
} =>
val interrupts = outer.extInterrupts.bundleIn
}
trait PeripheryExtInterruptsModule {
implicit val p: Parameters
this: TopNetworkModule {
val outer: PeripheryExtInterrupts
val io: PeripheryExtInterruptsBundle
val coreplexIO: BaseCoreplexBundle
{
val r = outer.pInterrupts.range("ext")
((r._1 until r._2) zipWithIndex) foreach { case (c, i) =>
coreplexIO.interrupts(c) := io.interrupts(i)
}
}
} =>
}
/////
trait PeripheryMasterMem extends LazyModule {
implicit val p: Parameters
trait PeripheryMasterMem {
this: TopNetwork =>
}
trait PeripheryMasterMemBundle extends HasPeripheryParameters {
implicit val p: Parameters
trait PeripheryMasterMemBundle {
this: TopNetworkBundle {
val outer: PeripheryMasterMem
} =>
val mem_clk = p(AsyncMemChannels).option(Vec(nMemChannels, Clock(INPUT)))
val mem_rst = p(AsyncMemChannels).option(Vec(nMemChannels, Bool (INPUT)))
val mem_axi = Vec(nMemAXIChannels, new NastiIO)
@ -174,13 +168,13 @@ trait PeripheryMasterMemBundle extends HasPeripheryParameters {
val mem_tl = Vec(nMemTLChannels, new ClientUncachedTileLinkIO()(edgeMemParams))
}
trait PeripheryMasterMemModule extends HasPeripheryParameters {
implicit val p: Parameters
trait PeripheryMasterMemModule {
this: TopNetworkModule {
val outer: PeripheryMasterMem
val io: PeripheryMasterMemBundle
val coreplexIO: BaseCoreplexBundle
} =>
val edgeMem = coreplexIO.master.mem.map(TileLinkWidthAdapter(_, edgeMemParams))
val edgeMem = coreplexMem.map(TileLinkWidthAdapter(_, edgeMemParams))
// Abuse the fact that zip takes the shorter of the two lists
((io.mem_axi zip edgeMem) zipWithIndex) foreach { case ((axi, mem), idx) =>
@ -204,78 +198,65 @@ trait PeripheryMasterMemModule extends HasPeripheryParameters {
/////
trait PeripheryMasterMMIO extends LazyModule {
implicit val p: Parameters
// PeripheryMasterAXI4MMIO is an example, make your own cake pattern like this one.
trait PeripheryMasterAXI4MMIO {
this: TopNetwork =>
val mmio_axi4 = AXI4BlindOutputNode(AXI4SlavePortParameters(
slaves = Seq(AXI4SlaveParameters(
address = List(AddressSet(0x60000000L, 0x1fffffffL)),
executable = true, // Can we run programs on this memory?
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
supportsRead = TransferSizes(1, 256),
interleavedId = Some(0))), // slave does not interleave read responses
beatBytes = 8)) // 64-bit AXI interface
mmio_axi4 :=
// AXI4Fragmenter(lite=false, maxInFlight = 20)( // beef device up to support awlen = 0xff
TLToAXI4(idBits = 4)( // use idBits = 0 for AXI4-Lite
TLWidthWidget(socBusConfig.beatBytes)( // convert width before attaching to socBus
socBus.node))
}
trait PeripheryMasterMMIOBundle extends HasPeripheryParameters {
implicit val p: Parameters
val mmio_clk = p(AsyncMMIOChannels).option(Vec(p(NExtMMIOAXIChannels), Clock(INPUT)))
val mmio_rst = p(AsyncMMIOChannels).option(Vec(p(NExtMMIOAXIChannels), Bool (INPUT)))
val mmio_axi = Vec(p(NExtMMIOAXIChannels), new NastiIO)
val mmio_ahb = Vec(p(NExtMMIOAHBChannels), new HastiMasterIO)
val mmio_tl = Vec(p(NExtMMIOTLChannels), new ClientUncachedTileLinkIO()(edgeMMIOParams))
trait PeripheryMasterAXI4MMIOBundle {
this: TopNetworkBundle {
val outer: PeripheryMasterAXI4MMIO
} =>
val mmio_axi = outer.mmio_axi4.bundleOut
}
trait PeripheryMasterMMIOModule extends HasPeripheryParameters {
implicit val p: Parameters
val outer: PeripheryMasterMMIO
val io: PeripheryMasterMMIOBundle
val pBus: TileLinkRecursiveInterconnect
val mmio_ports = p(ExtMMIOPorts) map { port =>
TileLinkWidthAdapter(pBus.port(port.name), edgeMMIOParams)
}
val mmio_axi_start = 0
val mmio_axi_end = mmio_axi_start + p(NExtMMIOAXIChannels)
val mmio_ahb_start = mmio_axi_end
val mmio_ahb_end = mmio_ahb_start + p(NExtMMIOAHBChannels)
val mmio_tl_start = mmio_ahb_end
val mmio_tl_end = mmio_tl_start + p(NExtMMIOTLChannels)
require (mmio_tl_end == mmio_ports.size)
for (i <- 0 until mmio_ports.size) {
if (mmio_axi_start <= i && i < mmio_axi_end) {
val idx = i-mmio_axi_start
val axi_sync = PeripheryUtils.convertTLtoAXI(mmio_ports(i))
io.mmio_axi(idx) <> (
if (!p(AsyncMMIOChannels)) axi_sync
else AsyncNastiTo(io.mmio_clk.get(idx), io.mmio_rst.get(idx), axi_sync)
)
} else if (mmio_ahb_start <= i && i < mmio_ahb_end) {
val idx = i-mmio_ahb_start
io.mmio_ahb(idx) <> PeripheryUtils.convertTLtoAHB(mmio_ports(i), atomics = true)
} else if (mmio_tl_start <= i && i < mmio_tl_end) {
val idx = i-mmio_tl_start
io.mmio_tl(idx) <> TileLinkEnqueuer(mmio_ports(i), 2)
} else {
require(false, "Unconnected external MMIO port")
}
}
trait PeripheryMasterAXI4MMIOModule {
this: TopNetworkModule {
val outer: PeripheryMasterAXI4MMIO
val io: PeripheryMasterAXI4MMIOBundle
} =>
// nothing to do
}
/////
trait PeripherySlave extends LazyModule {
implicit val p: Parameters
trait PeripherySlave {
this: TopNetwork {
val pBusMasters: RangeManager
} =>
if (p(NExtBusAXIChannels) > 0) pBusMasters.add("ext", 1) // NExtBusAXIChannels are arbitrated into one TL port
}
trait PeripherySlaveBundle extends HasPeripheryParameters {
implicit val p: Parameters
trait PeripherySlaveBundle {
this: TopNetworkBundle {
val outer: PeripherySlave
} =>
val bus_clk = p(AsyncBusChannels).option(Vec(p(NExtBusAXIChannels), Clock(INPUT)))
val bus_rst = p(AsyncBusChannels).option(Vec(p(NExtBusAXIChannels), Bool (INPUT)))
val bus_axi = Vec(p(NExtBusAXIChannels), new NastiIO).flip
}
trait PeripherySlaveModule extends HasPeripheryParameters {
implicit val p: Parameters
val outer: PeripherySlave
trait PeripherySlaveModule {
this: TopNetworkModule {
val outer: PeripherySlave { val pBusMasters: RangeManager }
val io: PeripherySlaveBundle
val coreplexIO: BaseCoreplexBundle
} =>
if (p(NExtBusAXIChannels) > 0) {
val arb = Module(new NastiArbiter(p(NExtBusAXIChannels)))
@ -290,105 +271,82 @@ trait PeripherySlaveModule extends HasPeripheryParameters {
val (r_start, r_end) = outer.pBusMasters.range("ext")
require(r_end - r_start == 1, "RangeManager should return 1 slot")
TileLinkWidthAdapter(coreplexIO.slave(r_start), conv.io.tl)
TileLinkWidthAdapter(coreplexSlave(r_start), conv.io.tl)
}
}
/////
trait PeripheryCoreplexLocalInterrupter extends LazyModule with HasPeripheryParameters {
implicit val p: Parameters
val peripheryBus: TLXbar
trait PeripheryBootROM {
this: TopNetwork =>
// CoreplexLocalInterrupter must be at least 64b if XLen >= 64
val beatBytes = max((outerMMIOParams(XLen) min 64) / 8, peripheryBusConfig.beatBytes)
val clintConfig = CoreplexLocalInterrupterConfig(beatBytes)
val clint = LazyModule(new CoreplexLocalInterrupter(clintConfig)(outerMMIOParams))
// The periphery bus is 32-bit, so we may need to adapt its width to XLen
clint.node := TLFragmenter(beatBytes, cacheBlockBytes)(TLWidthWidget(peripheryBusConfig.beatBytes)(peripheryBus.node))
}
trait PeripheryCoreplexLocalInterrupterBundle {
implicit val p: Parameters
}
trait PeripheryCoreplexLocalInterrupterModule extends HasPeripheryParameters {
implicit val p: Parameters
val outer: PeripheryCoreplexLocalInterrupter
val io: PeripheryCoreplexLocalInterrupterBundle
val coreplexIO: BaseCoreplexBundle
outer.clint.module.io.rtcTick := Counter(p(RTCPeriod)).inc()
coreplexIO.clint <> outer.clint.module.io.tiles
}
/////
trait PeripheryBootROM extends LazyModule with HasPeripheryParameters {
implicit val p: Parameters
val peripheryBus: TLXbar
val address = 0x1000
val size = 0x1000
val bootrom = LazyModule(new TLROM(address, size, GenerateBootROM(p, address), true, peripheryBusConfig.beatBytes))
val bootrom_address = 0x1000
val bootrom_size = 0x1000
val bootrom = LazyModule(new TLROM(bootrom_address, bootrom_size, GenerateBootROM(p, bootrom_address), true, peripheryBusConfig.beatBytes))
bootrom.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
}
trait PeripheryBootROMBundle {
implicit val p: Parameters
this: TopNetworkBundle {
val outer: PeripheryBootROM
} =>
}
trait PeripheryBootROMModule extends HasPeripheryParameters {
implicit val p: Parameters
trait PeripheryBootROMModule {
this: TopNetworkModule {
val outer: PeripheryBootROM
val io: PeripheryBootROMBundle
} =>
}
/////
trait PeripheryTestRAM extends LazyModule with HasPeripheryParameters {
implicit val p: Parameters
val peripheryBus: TLXbar
trait PeripheryTestRAM {
this: TopNetwork =>
val ramBase = 0x52000000
val ramSize = 0x1000
val sram = LazyModule(new TLRAM(AddressSet(ramBase, ramSize-1), true, peripheryBusConfig.beatBytes)
{ override def name = "testram" })
sram.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
val testram = LazyModule(new TLRAM(AddressSet(0x52000000, 0xfff), true, peripheryBusConfig.beatBytes))
testram.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
}
trait PeripheryTestRAMBundle {
implicit val p: Parameters
this: TopNetworkBundle {
val outer: PeripheryTestRAM
} =>
}
trait PeripheryTestRAMModule extends HasPeripheryParameters {
implicit val p: Parameters
trait PeripheryTestRAMModule {
this: TopNetworkModule {
val outer: PeripheryTestRAM
val io: PeripheryTestRAMBundle
} =>
}
/////
trait PeripheryTestBusMaster extends LazyModule {
implicit val p: Parameters
val peripheryBus: TLXbar
trait PeripheryTestBusMaster {
this: TopNetwork =>
val fuzzer = LazyModule(new TLFuzzer(5000))
peripheryBus.node := fuzzer.node
}
trait PeripheryTestBusMasterBundle {
implicit val p: Parameters
this: TopNetworkBundle {
val outer: PeripheryTestBusMaster
} =>
}
trait PeripheryTestBusMasterModule {
implicit val p: Parameters
this: TopNetworkModule {
val outer: PeripheryTestBusMaster
val io: PeripheryTestBusMasterBundle
} =>
}
/////
trait HardwiredResetVector {
val coreplexIO: BaseCoreplexBundle
coreplexIO.resetVector := UInt(0x1000) // boot ROM
this: TopNetworkModule {
val outer: BaseTop[BaseCoreplex]
} =>
outer.coreplex.module.io.resetVector := UInt(0x1000) // boot ROM
}

View File

@ -8,14 +8,14 @@ import junctions._
import junctions.NastiConstants._
import util.LatencyPipe
case object BuildExampleTop extends Field[Parameters => ExampleTop]
case object BuildExampleTop extends Field[Parameters => ExampleTop[coreplex.BaseCoreplex]]
case object SimMemLatency extends Field[Int]
class TestHarness(q: Parameters) extends Module {
val io = new Bundle {
val success = Bool(OUTPUT)
}
val dut = q(BuildExampleTop)(q).module
val dut = Module(q(BuildExampleTop)(q).module)
implicit val p = dut.p
// This test harness isn't especially flexible yet
@ -25,16 +25,12 @@ class TestHarness(q: Parameters) extends Module {
require(dut.io.mem_tl.isEmpty)
require(dut.io.bus_clk.isEmpty)
require(dut.io.bus_rst.isEmpty)
require(dut.io.mmio_clk.isEmpty)
require(dut.io.mmio_rst.isEmpty)
require(dut.io.mmio_ahb.isEmpty)
require(dut.io.mmio_tl.isEmpty)
for (int <- dut.io.interrupts)
for (int <- dut.io.interrupts(0))
int := Bool(false)
if (dut.io.mem_axi.nonEmpty) {
val memSize = p(GlobalAddrMap)("mem").size
val memSize = p(ExtMemSize)
require(memSize % dut.io.mem_axi.size == 0)
for (axi <- dut.io.mem_axi) {
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))

View File

@ -53,20 +53,8 @@ class GlobalVariable[T] {
}
object GenerateGlobalAddrMap {
def apply(p: Parameters, pDevicesEntries: Seq[AddrMapEntry], peripheryManagers: Seq[TLManagerParameters]) = {
lazy val cBusIOAddrMap: AddrMap = {
val entries = collection.mutable.ArrayBuffer[AddrMapEntry]()
entries += AddrMapEntry("debug", MemSize(4096, MemAttr(AddrMapProt.RWX)))
entries += AddrMapEntry("plic", MemRange(0x0C000000, 0x4000000, MemAttr(AddrMapProt.RW)))
if (p(DataScratchpadSize) > 0) { // TODO heterogeneous tiles
require(p(NTiles) == 1) // TODO relax this
require(p(NMemoryChannels) == 0) // TODO allow both scratchpad & DRAM
entries += AddrMapEntry("dmem0", MemRange(0x80000000L, BigInt(p(DataScratchpadSize)), MemAttr(AddrMapProt.RWX)))
}
new AddrMap(entries)
}
lazy val tl2Devices = peripheryManagers.map { manager =>
def apply(p: Parameters, peripheryManagers: Seq[TLManagerParameters]) = {
val tl2Devices = peripheryManagers.map { manager =>
val cacheable = manager.regionType match {
case RegionType.CACHED => true
case RegionType.TRACKED => true
@ -84,41 +72,28 @@ object GenerateGlobalAddrMap {
}
}.flatten
lazy val uniquelyNamedTL2Devices =
val uniquelyNamedTL2Devices =
tl2Devices.groupBy(_.name).values.map(_.zipWithIndex.map {
case (e, i) => if (i == 0) e else e.copy(name = e.name + "_" + i)
}).flatten.toList
lazy val tl2AddrMap = new AddrMap(uniquelyNamedTL2Devices, collapse = true)
lazy val pBusIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: (p(ExtMMIOPorts) ++ pDevicesEntries), collapse = true)
val memBase = 0x80000000L
val memSize = p(ExtMemSize)
Dump("MEM_BASE", memBase)
val cBus = AddrMapEntry("cbus", cBusIOAddrMap)
val pBus = AddrMapEntry("pbus", pBusIOAddrMap)
val io = AddrMapEntry("io", AddrMap((cBus +: (!pBusIOAddrMap.isEmpty).option(pBus).toSeq):_*))
val tl2 = AddrMapEntry("TL2", new AddrMap(uniquelyNamedTL2Devices, collapse = true))
val mem = AddrMapEntry("mem", MemRange(memBase, memSize, MemAttr(AddrMapProt.RWX, true)))
AddrMap((io +: (p(NMemoryChannels) > 0).option(mem).toSeq):_*)
AddrMap((tl2 +: (p(NMemoryChannels) > 0).option(mem).toSeq):_*)
}
}
object GenerateConfigString {
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry], peripheryManagers: Seq[TLManagerParameters]) = {
def apply(p: Parameters, clint: CoreplexLocalInterrupter, plic: TLPLIC, peripheryManagers: Seq[TLManagerParameters]) = {
val c = CoreplexParameters()(p)
val addrMap = p(GlobalAddrMap)
val plicAddr = addrMap("io:cbus:plic").start
val clint = CoreplexLocalInterrupterConfig(0, addrMap("io:pbus:TL2:clint").start)
val xLen = p(XLen)
val res = new StringBuilder
res append "plic {\n"
res append s" priority 0x${plicAddr.toString(16)};\n"
res append s" pending 0x${(plicAddr + c.plicKey.pendingBase).toString(16)};\n"
res append s" ndevs ${c.plicKey.nDevices};\n"
res append "};\n"
res append "rtc {\n"
res append s" addr 0x${clint.timeAddress.toString(16)};\n"
res append "};\n"
res append plic.module.globalConfigString
res append clint.module.globalConfigString
if (addrMap contains "mem") {
res append "ram {\n"
res append " 0 {\n"
@ -140,33 +115,12 @@ object GenerateConfigString {
res append s" $i {\n"
res append " 0 {\n"
res append s" isa $isa;\n"
res append s" timecmp 0x${clint.timecmpAddress(i).toString(16)};\n"
res append s" ipi 0x${clint.msipAddress(i).toString(16)};\n"
res append s" plic {\n"
res append s" m {\n"
res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\n"
res append s" thresh 0x${(plicAddr + c.plicKey.threshAddr(i, 'M')).toString(16)};\n"
res append s" claim 0x${(plicAddr + c.plicKey.claimAddr(i, 'M')).toString(16)};\n"
res append s" };\n"
if (c.hasSupervisor) {
res append s" s {\n"
res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'S')).toString(16)};\n"
res append s" thresh 0x${(plicAddr + c.plicKey.threshAddr(i, 'S')).toString(16)};\n"
res append s" claim 0x${(plicAddr + c.plicKey.claimAddr(i, 'S')).toString(16)};\n"
res append s" };\n"
}
res append " };\n"
res append clint.module.hartConfigStrings(i)
res append plic.module.hartConfigStrings(i)
res append " };\n"
res append " };\n"
}
res append "};\n"
pDevicesEntries foreach { entry =>
val region = addrMap("io:pbus:" + entry.name)
res append s"${entry.name} {\n"
res append s" addr 0x${region.start.toString(16)};\n"
res append s" size 0x${region.size.toString(16)}; \n"
res append "}\n"
}
peripheryManagers.foreach { manager => res append manager.dts }
res append '\u0000'
res.toString
@ -185,6 +139,6 @@ object GenerateBootROM {
require(rom.getInt(12) == 0,
"Config string address position should not be occupied by code")
rom.putInt(12, configStringAddr)
rom.array() ++ (p(ConfigString).getBytes.toSeq)
rom.array() ++ (ConfigStringOutput.contents.get.getBytes.toSeq)
}
}

View File

@ -10,7 +10,7 @@ import scala.math.{min,max}
import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH}
// lite: masters all use only one ID => reads will not be interleaved
class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational: Boolean = true) extends LazyModule
class AXI4Fragmenter(lite: Boolean = false, maxInFlight: => Int = 32, combinational: Boolean = true) extends LazyModule
{
val maxBeats = 1 << AXI4Parameters.lenBits
def expandTransfer(x: TransferSizes, beatBytes: Int, alignment: BigInt) =
@ -287,7 +287,7 @@ class AXI4FragmenterSideband(maxInFlight: Int, flow: Boolean = false) extends Mo
object AXI4Fragmenter
{
// applied to the AXI4 source node; y.node := AXI4Fragmenter()(x.node)
def apply(lite: Boolean = false, maxInFlight: Int = 32, combinational: Boolean = true)(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): AXI4OutwardNode = {
def apply(lite: Boolean = false, maxInFlight: => Int = 32, combinational: Boolean = true)(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): AXI4OutwardNode = {
val fragmenter = LazyModule(new AXI4Fragmenter(lite, maxInFlight, combinational))
fragmenter.node := x
fragmenter.node

View File

@ -16,10 +16,13 @@ object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters
}
def bundleI(ei: Seq[AXI4EdgeParameters]): Vec[AXI4Bundle] = {
require (!ei.isEmpty)
Vec(ei.size, AXI4Bundle(ei.map(_.bundle).reduce(_.union(_)))).flip
Vec(ei.size, AXI4Bundle(ei.map(_.bundle).reduce(_.union(_))))
}
def colour = "#00ccff" // bluish
override def labelI(ei: AXI4EdgeParameters) = (ei.slave.beatBytes * 8).toString
override def labelO(eo: AXI4EdgeParameters) = (eo.slave.beatBytes * 8).toString
def connect(bo: => AXI4Bundle, bi: => AXI4Bundle, ei: => AXI4EdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
(None, () => { bi <> bo })
}
@ -30,18 +33,23 @@ object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters
pu.copy(slaves = pu.slaves.map { m => m.copy (nodePath = node +: m.nodePath) })
}
// Nodes implemented inside modules
case class AXI4IdentityNode() extends IdentityNode(AXI4Imp)
case class AXI4OutputNode() extends OutputNode(AXI4Imp)
case class AXI4InputNode() extends InputNode(AXI4Imp)
case class AXI4MasterNode(portParams: AXI4MasterPortParameters, numPorts: Range.Inclusive = 1 to 1)
extends SourceNode(AXI4Imp)(portParams, numPorts)
case class AXI4SlaveNode(portParams: AXI4SlavePortParameters, numPorts: Range.Inclusive = 1 to 1)
extends SinkNode(AXI4Imp)(portParams, numPorts)
case class AXI4AdapterNode(
masterFn: Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters,
slaveFn: Seq[AXI4SlavePortParameters] => AXI4SlavePortParameters,
numMasterPorts: Range.Inclusive = 1 to 1,
numSlavePorts: Range.Inclusive = 1 to 1)
extends InteriorNode(AXI4Imp)(masterFn, slaveFn, numMasterPorts, numSlavePorts)
// Nodes passed from an inner module
case class AXI4OutputNode() extends OutputNode(AXI4Imp)
case class AXI4InputNode() extends InputNode(AXI4Imp)
// Nodes used for external ports
case class AXI4BlindOutputNode(portParams: AXI4SlavePortParameters) extends BlindOutputNode(AXI4Imp)(portParams)
case class AXI4BlindInputNode(portParams: AXI4MasterPortParameters) extends BlindInputNode(AXI4Imp)(portParams)

View File

@ -7,10 +7,11 @@ import diplomacy._
import regmapper._
import scala.math.{min,max}
class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true)
class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
extends AXI4SlaveNode(AXI4SlavePortParameters(
Seq(AXI4SlaveParameters(
address = Seq(address),
executable = executable,
supportsWrite = TransferSizes(1, beatBytes),
supportsRead = TransferSizes(1, beatBytes),
interleavedId = Some(0))),
@ -69,16 +70,16 @@ class AXI4RegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int
object AXI4RegisterNode
{
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true) =
new AXI4RegisterNode(address, concurrency, beatBytes, undefZero)
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false) =
new AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
}
// These convenience methods below combine to make it possible to create a AXI4
// register mapped device from a totally abstract register mapped device.
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean) extends LazyModule
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean) extends LazyModule
{
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero)
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
val intnode = uncore.tilelink2.IntSourceNode(interrupts)
}
@ -101,10 +102,10 @@ class AXI4RegModule[P, B <: AXI4RegBundleBase](val params: P, bundleBuilder: =>
}
class AXI4RegisterRouter[B <: AXI4RegBundleBase, M <: LazyModuleImp]
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true)
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
(bundleBuilder: AXI4RegBundleArg => B)
(moduleBuilder: (=> B, AXI4RegisterRouterBase) => M)
extends AXI4RegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero)
extends AXI4RegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero, executable)
{
require (isPow2(size))
// require (size >= 4096) ... not absolutely required, but highly recommended

View File

@ -4,8 +4,9 @@ package uncore.devices
import Chisel._
import junctions._
import uncore.tilelink._
import util._
import regmapper._
import uncore.tilelink2._
import cde.{Parameters, Config, Field}
// *****************************************
@ -15,6 +16,7 @@ import cde.{Parameters, Config, Field}
object DbRegAddrs{
def DMRAMBASE = UInt(0x0)
def DMCONTROL = UInt(0x10)
def DMINFO = UInt(0x11)
@ -69,7 +71,7 @@ object DsbBusConsts {
// See $RISCV/riscv-tools/riscv-isa-sim/debug_rom/debug_rom.h/S
// The code assumes 64 bytes of Debug RAM.
def defaultRomContents : Array[Byte] = Array(
def xlenAnyRomContents : Array[Byte] = Array(
0x6f, 0x00, 0xc0, 0x04, 0x6f, 0x00, 0xc0, 0x00, 0x13, 0x04, 0xf0, 0xff,
0x6f, 0x00, 0x80, 0x00, 0x13, 0x04, 0x00, 0x00, 0x0f, 0x00, 0xf0, 0x0f,
0xf3, 0x24, 0x00, 0xf1, 0x63, 0xc6, 0x04, 0x00, 0x83, 0x24, 0xc0, 0x43,
@ -121,10 +123,10 @@ object DsbBusConsts {
object DsbRegAddrs{
def CLEARDEBINT = UInt(0x100)
def SETHALTNOT = UInt(0x10C)
def SERINFO = UInt(0x110)
def SERBASE = UInt(0x114)
def CLEARDEBINT = 0x100
def SETHALTNOT = 0x10C
def SERINFO = 0x110
def SERBASE = 0x114
// For each serial, there are
// 3 registers starting here:
// SERSEND0
@ -132,9 +134,11 @@ object DsbRegAddrs{
// SERSTATUS0
// ...
// SERSTATUS7
def SERTX_OFFSET = UInt(0)
def SERRX_OFFSET = UInt(4)
def SERSTAT_OFFSET = UInt(8)
def SERTX_OFFSET = 0
def SERRX_OFFSET = 4
def SERSTAT_OFFSET = 8
def RAMBASE = 0x400
def ROMBASE = 0x800
}
@ -302,6 +306,24 @@ class DebugBusIO(implicit val p: cde.Parameters) extends ParameterizedBundle()(p
val resp = new DecoupledIO(new DebugBusResp).flip()
}
trait HasDebugModuleParameters {
val params : Parameters
implicit val p = params
val cfg = p(DMKey)
}
/** Debug Module I/O, with the exclusion of the RegisterRouter
* Access interface.
*/
trait DebugModuleBundle extends Bundle with HasDebugModuleParameters {
val db = new DebugBusIO()(p).flip()
val debugInterrupts = Vec(cfg.nComponents, Bool()).asOutput
val ndreset = Bool(OUTPUT)
val fullreset = Bool(OUTPUT)
}
// *****************************************
// The Module
//
@ -313,7 +335,7 @@ class DebugBusIO(implicit val p: cde.Parameters) extends ParameterizedBundle()(p
* DebugModule is a slave to two masters:
* The Debug Bus -- implemented as a generic Decoupled IO with request
* and response channels
* The System Bus -- implemented as Uncached Tile Link.
* The System Bus -- implemented as generic RegisterRouter
*
* DebugModule is responsible for holding registers, RAM, and ROM
* to support debug interactions, as well as driving interrupts
@ -321,10 +343,9 @@ class DebugBusIO(implicit val p: cde.Parameters) extends ParameterizedBundle()(p
* It is also responsible for some reset lines.
*/
class DebugModule ()(implicit val p:cde.Parameters)
extends Module
with HasTileLinkParameters {
val cfg = p(DMKey)
trait DebugModule extends Module with HasDebugModuleParameters with HasRegMap {
val io: DebugModuleBundle
//--------------------------------------------------------------
// Import constants for shorter variable names
@ -344,6 +365,7 @@ class DebugModule ()(implicit val p:cde.Parameters)
require (cfg.hasBusMaster == false)
require (cfg.nDebugRamBytes <= 64)
require (cfg.authType == DebugModuleAuthType.None)
require((DbBusConsts.dbRamWordBits % 8) == 0)
//--------------------------------------------------------------
// Private Classes (Register Fields)
@ -403,17 +425,6 @@ class DebugModule ()(implicit val p:cde.Parameters)
}
//--------------------------------------------------------------
// Module I/O
//--------------------------------------------------------------
val io = new Bundle {
val db = new DebugBusIO()(p).flip()
val debugInterrupts = Vec(cfg.nComponents, Bool()).asOutput
val tl = new ClientUncachedTileLinkIO().flip
val ndreset = Bool(OUTPUT)
val fullreset = Bool(OUTPUT)
}
//--------------------------------------------------------------
// Register & Wire Declarations
@ -455,46 +466,23 @@ class DebugModule ()(implicit val p:cde.Parameters)
// --- Debug RAM
// Since the access size from Debug Bus and System Bus may not be consistent,
// use the maximum to build the RAM, and then select as needed for the smaller
// size.
val ramDataWidth = DbBusConsts.dbRamWordBits
val ramDataBytes = ramDataWidth / 8;
val ramAddrWidth = log2Up(cfg.nDebugRamBytes / ramDataBytes)
val dbRamDataWidth = DbBusConsts.dbRamWordBits
val sbRamDataWidth = tlDataBits
val dbRamAddrWidth = log2Up((cfg.nDebugRamBytes * 8) / dbRamDataWidth)
val sbRamAddrWidth = log2Up((cfg.nDebugRamBytes * 8) / sbRamDataWidth)
val sbRamAddrOffset = log2Up(tlDataBits/8)
val ramMem = Reg(init = Vec.fill(cfg.nDebugRamBytes){UInt(0, width = 8)})
val ramDataWidth = dbRamDataWidth max sbRamDataWidth
val ramAddrWidth = dbRamAddrWidth min sbRamAddrWidth
val ramMem = Mem(1 << ramAddrWidth , UInt(width=ramDataWidth))
val ramAddr = Wire(UInt(width=ramAddrWidth))
val ramRdData = Wire(UInt(width=ramDataWidth))
val ramWrData = Wire(UInt(width=ramDataWidth))
val ramWrMask = Wire(UInt(width=ramDataWidth))
val ramWrEn = Wire(Bool())
val dbRamAddr = Wire(UInt(width=dbRamAddrWidth))
val dbRamAddr = Wire(UInt(width=ramAddrWidth))
val dbRamAddrValid = Wire(Bool())
val dbRamRdData = Wire (UInt(width=dbRamDataWidth))
val dbRamWrData = Wire(UInt(width=dbRamDataWidth))
val dbRamRdData = Wire (UInt(width=ramDataWidth))
val dbRamWrData = Wire(UInt(width=ramDataWidth))
val dbRamWrEn = Wire(Bool())
val dbRamRdEn = Wire(Bool())
val dbRamWrEnFinal = Wire(Bool())
val dbRamRdEnFinal = Wire(Bool())
require((cfg.nDebugRamBytes % ramDataBytes) == 0)
val dbRamDataOffset = log2Up(ramDataBytes)
val sbRamAddr = Wire(UInt(width=sbRamAddrWidth))
val sbRamAddrValid = Wire(Bool())
val sbRamRdData = Wire (UInt(width=sbRamDataWidth))
val sbRamWrData = Wire(UInt(width=sbRamDataWidth))
val sbRamWrEn = Wire(Bool())
val sbRamRdEn = Wire(Bool())
val sbRamWrEnFinal = Wire(Bool())
val sbRamRdEnFinal = Wire(Bool())
val sbRomRdData = Wire(UInt(width=tlDataBits))
val sbRomAddrOffset = log2Up(tlDataBits/8)
// --- Debug Bus Accesses
@ -513,16 +501,6 @@ class DebugModule ()(implicit val p:cde.Parameters)
val rdCondWrFailure = Wire(Bool())
val dbWrNeeded = Wire(Bool())
// --- System Bus Access
val sbAddr = Wire(UInt(width=sbAddrWidth))
val sbRdData = Wire(UInt(width=tlDataBits))
val sbWrData = Wire(UInt(width=tlDataBits))
val sbWrMask = Wire(UInt(width=tlDataBits))
val sbWrEn = Wire(Bool())
val sbRdEn = Wire(Bool())
val stallFromDb = Wire(Bool())
val stallFromSb = Wire(Bool())
//--------------------------------------------------------------
// Interrupt Registers
//--------------------------------------------------------------
@ -622,64 +600,30 @@ class DebugModule ()(implicit val p:cde.Parameters)
HALTSUMRdData.acks := haltnotSummary
//--------------------------------------------------------------
// Debug RAM Access (Debug Bus & System Bus)
// Debug RAM Access (Debug Bus ... System Bus can override)
//--------------------------------------------------------------
dbReq := io.db.req.bits
// Debug Bus RAM Access
// From Specification: Debug RAM is 0x00 - 0x0F
// 0x40 - 0x6F Not Implemented
dbRamAddr := dbReq.addr( dbRamAddrWidth-1 , 0)
dbRamAddr := dbReq.addr( ramAddrWidth-1 , 0)
dbRamWrData := dbReq.data
dbRamAddrValid := Bool(true)
if (dbRamAddrWidth < 4){
dbRamAddrValid := (dbReq.addr(3, dbRamAddrWidth) === UInt(0))
dbRamAddrValid := (dbReq.addr(3,0) <= UInt((cfg.nDebugRamBytes/ramDataBytes)))
val dbRamRdDataFields = List.tabulate(cfg.nDebugRamBytes / ramDataBytes) { ii =>
val slice = ramMem.slice(ii * ramDataBytes, (ii+1)*ramDataBytes)
slice.reduce[UInt]{ case (x: UInt, y: UInt) => Cat(y, x)}
}
sbRamAddr := sbAddr(sbRamAddrWidth + sbRamAddrOffset - 1, sbRamAddrOffset)
sbRamWrData := sbWrData
sbRamAddrValid := Bool(true)
// From Specification: Debug RAM is 0x400 - 0x4FF
if ((sbRamAddrWidth + sbRamAddrOffset) < 8){
sbRamAddrValid := (sbAddr(7, sbRamAddrWidth + sbRamAddrOffset) === UInt(0))
dbRamRdData := dbRamRdDataFields(dbRamAddr)
when (dbRamWrEnFinal) {
for (ii <- 0 until ramDataBytes) {
ramMem((dbRamAddr << UInt(dbRamDataOffset)) + UInt(ii)) := dbRamWrData((8*(ii+1)-1), (8*ii))
}
require (dbRamAddrWidth >= ramAddrWidth) // SB accesses less than 32 bits Not Implemented.
val dbRamWrMask = Wire(init=Vec.fill(1 << (dbRamAddrWidth - ramAddrWidth)){Fill(dbRamDataWidth, UInt(1, width=1))})
if (dbRamDataWidth < ramDataWidth){
val dbRamSel = dbRamAddr(dbRamAddrWidth - ramAddrWidth - 1 , 0)
val rdDataWords = Vec.tabulate(1 << (dbRamAddrWidth - ramAddrWidth)){ ii =>
ramRdData((ii+1)*dbRamDataWidth - 1 , ii*dbRamDataWidth)}
dbRamWrMask := Vec.fill(1 << (dbRamAddrWidth - ramAddrWidth)){UInt(0, width = dbRamDataWidth)}
dbRamWrMask(dbRamSel) := Fill(dbRamDataWidth, UInt(1, width=1))
dbRamRdData := rdDataWords(dbRamSel)
} else {
dbRamRdData := ramRdData
}
sbRamRdData := ramRdData
ramWrMask := Mux(sbRamWrEn, sbWrMask, dbRamWrMask.asUInt)
assert (!((dbRamWrEn | dbRamRdEn) & (sbRamRdEn | sbRamWrEn)), "Stall logic should have prevented concurrent SB/DB RAM Access")
// Make copies of DB RAM data before writing.
val dbRamWrDataVec = Fill(1 << (dbRamAddrWidth - ramAddrWidth), dbRamWrData)
ramWrData := Mux(sbRamWrEn,
(ramWrMask & sbRamWrData ) | (~ramWrMask & ramRdData),
(ramWrMask & dbRamWrDataVec) | (~ramWrMask & ramRdData))
ramAddr := Mux(sbRamWrEn | sbRamRdEn, sbRamAddr,
dbRamAddr >> (dbRamAddrWidth - ramAddrWidth))
ramRdData := ramMem(ramAddr)
when (ramWrEn) { ramMem(ramAddr) := ramWrData }
ramWrEn := sbRamWrEnFinal | dbRamWrEnFinal
//--------------------------------------------------------------
// Debug Bus Access
//--------------------------------------------------------------
@ -813,8 +757,8 @@ class DebugModule ()(implicit val p:cde.Parameters)
// -----------------------------------------
// DB Access State Machine Decode (Combo)
io.db.req.ready := !stallFromSb && ((dbStateReg === s_DB_READY) ||
(dbStateReg === s_DB_RESP && io.db.resp.fire()))
io.db.req.ready := (dbStateReg === s_DB_READY) ||
(dbStateReg === s_DB_RESP && io.db.resp.fire())
io.db.resp.valid := (dbStateReg === s_DB_RESP)
io.db.resp.bits := dbRespReg
@ -844,172 +788,28 @@ class DebugModule ()(implicit val p:cde.Parameters)
// Debug ROM
//--------------------------------------------------------------
sbRomRdData := UInt(0)
if (cfg.hasDebugRom) {
// Inspired by ROMSlave
val romContents = cfg.debugRomContents.get
val romByteWidth = tlDataBits / 8
val romRows = (romContents.size + romByteWidth - 1)/romByteWidth
val romMem = Vec.tabulate(romRows) { ii =>
val slice = romContents.slice(ii*romByteWidth, (ii+1)*romByteWidth)
UInt(slice.foldRight(BigInt(0)) { case (x,y) => ((y << 8) + (x.toInt & 0xFF))}, width = romByteWidth*8)
}
val sbRomRdAddr = Wire(UInt())
if (romRows == 1) {
sbRomRdAddr := UInt(0)
val romRegFields = if (cfg.hasDebugRom) {
cfg.debugRomContents.get.map( x => RegField.r(8, UInt(x.toInt & 0xFF)))
} else {
sbRomRdAddr := sbAddr(log2Up(romRows) + sbRomAddrOffset - 1, sbRomAddrOffset)
}
sbRomRdData := romMem (sbRomRdAddr)
Seq(RegField(8))
}
//--------------------------------------------------------------
// System Bus Access
//--------------------------------------------------------------
// -----------------------------------------
// SB Access Write Decoder
sbRamWrEn := Bool(false)
sbRamWrEnFinal := Bool(false)
SETHALTNOTWrEn := Bool(false)
CLEARDEBINTWrEn := Bool(false)
if (tlDataBits == 32) {
SETHALTNOTWrData := sbWrData
CLEARDEBINTWrData := sbWrData
when (sbAddr(11, 8) === UInt(4)){ // 0x400-0x4ff is Debug RAM
sbRamWrEn := sbWrEn
sbRamRdEn := sbRdEn
when (sbRamAddrValid) {
sbRamWrEnFinal := sbWrEn
sbRamRdEnFinal := sbRdEn
}
}.elsewhen (sbAddr === SETHALTNOT){
SETHALTNOTWrEn := sbWrEn
}.elsewhen (sbAddr === CLEARDEBINT){
CLEARDEBINTWrEn := sbWrEn
}.otherwise {
//Other registers/RAM are Not Implemented.
}
} else {
// Pick out the correct word based on the address.
val sbWrDataWords = Vec.tabulate (tlDataBits / 32) {ii => sbWrData((ii+1)*32 - 1, ii*32)}
val sbWrMaskWords = Vec.tabulate (tlDataBits / 32) {ii => sbWrMask ((ii+1)*32 -1, ii*32)}
val sbWrSelTop = log2Up(tlDataBits/8) - 1
val sbWrSelBottom = 2
SETHALTNOTWrData := sbWrDataWords(SETHALTNOT(sbWrSelTop, sbWrSelBottom))
CLEARDEBINTWrData := sbWrDataWords(CLEARDEBINT(sbWrSelTop, sbWrSelBottom))
when (sbAddr(11,8) === UInt(4)){ //0x400-0x4ff is Debug RAM
sbRamWrEn := sbWrEn
sbRamRdEn := sbRdEn
when (sbRamAddrValid){
sbRamWrEnFinal := sbWrEn
sbRamRdEnFinal := sbRdEn
}
// Local reg mapper function : Notify when written, but give the value.
def wValue (n: Int, value: UInt, set: Bool) : RegField = {
RegField(n, value, RegWriteFn((valid, data) => {set := valid ; value := data; Bool(true)}))
}
SETHALTNOTWrEn := sbAddr(sbAddrWidth - 1, sbWrSelTop + 1) === SETHALTNOT(sbAddrWidth-1, sbWrSelTop + 1) &&
(sbWrMaskWords(SETHALTNOT(sbWrSelTop, sbWrSelBottom))).orR &&
sbWrEn
CLEARDEBINTWrEn := sbAddr(sbAddrWidth - 1, sbWrSelTop + 1) === CLEARDEBINT(sbAddrWidth-1, sbWrSelTop + 1) &&
(sbWrMaskWords(CLEARDEBINT(sbWrSelTop, sbWrSelBottom))).orR &&
sbWrEn
}
// -----------------------------------------
// SB Access Read Mux
sbRdData := UInt(0)
sbRamRdEn := Bool(false)
sbRamRdEnFinal := Bool(false)
when (sbAddr(11, 8) === UInt(4)) { //0x400-0x4FF Debug RAM
sbRamRdEn := sbRdEn
when (sbRamAddrValid) {
sbRdData := sbRamRdData
sbRamRdEnFinal := sbRdEn
}
}.elsewhen (sbAddr(11,8).isOneOf(UInt(8), UInt(9))){ //0x800-0x9FF Debug ROM
if (cfg.hasDebugRom) {
sbRdData := sbRomRdData
} else {
sbRdData := UInt(0)
}
}. otherwise {
// All readable registers are Not Implemented.
sbRdData := UInt(0)
}
// -----------------------------------------
// SB Access State Machine -- based on BRAM Slave
val sbAcqReg = Reg(io.tl.acquire.bits)
val sbAcqValidReg = Reg(init = Bool(false))
val (sbReg_get :: sbReg_getblk :: sbReg_put :: sbReg_putblk :: Nil) = Seq(
Acquire.getType, Acquire.getBlockType, Acquire.putType, Acquire.putBlockType
).map(sbAcqReg.isBuiltInType _)
val sbMultibeat = sbReg_getblk & sbAcqValidReg;
val sbBeatInc1 = sbAcqReg.addr_beat + UInt(1)
val sbLast = (sbAcqReg.addr_beat === UInt(tlDataBeats - 1))
sbAddr := sbAcqReg.full_addr()
sbRdEn := (sbAcqValidReg && (sbReg_get || sbReg_getblk))
sbWrEn := (sbAcqValidReg && (sbReg_put || sbReg_putblk))
sbWrData := sbAcqReg.data
sbWrMask := sbAcqReg.full_wmask()
// -----------------------------------------
// SB Access State Machine Update (Seq)
when (io.tl.acquire.fire()){
sbAcqReg := io.tl.acquire.bits
sbAcqValidReg := Bool(true)
} .elsewhen (io.tl.grant.fire()) {
when (sbMultibeat){
sbAcqReg.addr_beat := sbBeatInc1
when (sbLast) {
sbAcqValidReg := Bool(false)
}
} . otherwise {
sbAcqValidReg := Bool(false)
}
}
io.tl.grant.valid := sbAcqValidReg
io.tl.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = sbAcqReg.getBuiltInGrantType(),
client_xact_id = sbAcqReg.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = sbAcqReg.addr_beat,
data = sbRdData
regmap(
CLEARDEBINT -> Seq(wValue(sbIdWidth, CLEARDEBINTWrData, CLEARDEBINTWrEn)),
SETHALTNOT -> Seq(wValue(sbIdWidth, SETHALTNOTWrData, SETHALTNOTWrEn)),
RAMBASE -> ramMem.map(x => RegField(8, x)),
ROMBASE -> romRegFields
)
stallFromDb := Bool(false) // SB always wins, and DB latches its read data so it is not necessary for SB to wait
stallFromSb := sbRamRdEn || sbRamWrEn // pessimistically assume that DB/SB are going to conflict on the RAM,
// and SB doesn't latch its read data to it is necessary for DB hold
// off while SB is accessing the RAM and waiting to send its result.
val sbStall = (sbMultibeat & !sbLast) || (io.tl.grant.valid && !io.tl.grant.ready) || stallFromDb
io.tl.acquire.ready := !sbStall
//--------------------------------------------------------------
// Misc. Outputs
//--------------------------------------------------------------
@ -1019,6 +819,21 @@ class DebugModule ()(implicit val p:cde.Parameters)
}
/** Create a concrete TL2 Slave for the DebugModule RegMapper interface.
*
*/
class TLDebugModule(address: BigInt = 0)(implicit p: Parameters)
extends TLRegisterRouter(address, beatBytes=p(rocket.XLen)/8, executable=true)(
new TLRegBundle(p, _ ) with DebugModuleBundle)(
new TLRegModule(p, _, _) with DebugModule)
/** Synchronizers for DebugBus
*
*/
object AsyncDebugBusCrossing {
// takes from_source from the 'from' clock domain to the 'to' clock domain
def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, to_clock: Clock, to_reset: Bool, depth: Int = 1, sync: Int = 3) = {
@ -1029,6 +844,7 @@ object AsyncDebugBusCrossing {
}
}
object AsyncDebugBusFrom { // OutsideClockDomain
// takes from_source from the 'from' clock domain and puts it into your clock domain
def apply(from_clock: Clock, from_reset: Bool, from_source: DebugBusIO, depth: Int = 1, sync: Int = 3): DebugBusIO = {

View File

@ -6,8 +6,11 @@ import Chisel._
import Chisel.ImplicitConversions._
import junctions._
import uncore.tilelink._
import diplomacy._
import regmapper._
import uncore.tilelink2._
import cde.Parameters
import scala.math.min
class GatewayPLICIO extends Bundle {
val valid = Bool(OUTPUT)
@ -27,55 +30,123 @@ class LevelGateway extends Module {
io.plic.valid := io.interrupt && !inFlight
}
case class PLICConfig(nHartsIn: Int, supervisor: Boolean, nDevices: Int, nPriorities: Int) {
def contextsPerHart = if (supervisor) 2 else 1
def nHarts = contextsPerHart * nHartsIn
object PLICConsts
{
def maxDevices = 1023
def maxHarts = 15872
def priorityBase = 0x0
def pendingBase = 0x1000
def enableBase = 0x2000
def hartBase = 0x200000
def claimOffset = 4
def priorityBytes = 4
def enableOffset(i: Int) = i * ((maxDevices+7)/8)
def hartOffset(i: Int) = i * 0x1000
def enableBase(i: Int):Int = enableOffset(i) + enableBase
def hartBase(i: Int):Int = hartOffset(i) + hartBase
def size = hartBase(maxHarts)
require(hartBase >= enableBase(maxHarts))
}
/** Platform-Level Interrupt Controller */
class TLPLIC(supervisor: Boolean, maxPriorities: Int, address: BigInt = 0xC000000)(implicit val p: Parameters) extends LazyModule
{
val contextsPerHart = if (supervisor) 2 else 1
require (maxPriorities >= 0)
val node = TLRegisterNode(
address = AddressSet(address, PLICConsts.size-1),
beatBytes = p(rocket.XLen)/8,
undefZero = false)
val intnode = IntAdapterNode(
numSourcePorts = 0 to 1024,
numSinkPorts = 0 to 1024,
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(contextsPerHart))) },
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val tl_in = node.bundleIn
val devices = intnode.bundleIn
val harts = intnode.bundleOut
}
// Assign all the devices unique ranges
val sources = intnode.edgesIn.map(_.source)
val flatSources = (sources zip sources.map(_.num).scanLeft(0)(_+_).init).map {
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
}.flatten
// Compact the interrupt vector the same way
val interrupts = (intnode.edgesIn zip io.devices).map { case (e, i) => i.take(e.source.num) }.flatten
// This flattens the harts into an MSMSMSMSMS... or MMMMM.... sequence
val harts = io.harts.flatten
println("\nInterrupt map:")
flatSources.foreach { s =>
// +1 because 0 is reserved, +1-1 because the range is half-open
println(s" [${s.range.start+1}, ${s.range.end}] => ${s.name}")
}
val nDevices = interrupts.size
val nPriorities = min(maxPriorities, nDevices)
val nHarts = harts.size
require(nDevices <= PLICConsts.maxDevices)
require(nHarts > 0 && nHarts <= PLICConsts.maxHarts)
def context(i: Int, mode: Char) = mode match {
case 'M' => i * contextsPerHart
case 'S' => require(supervisor); i * contextsPerHart + 1
}
def claimAddr(i: Int, mode: Char) = hartBase + hartOffset(context(i, mode)) + claimOffset
def threshAddr(i: Int, mode: Char) = hartBase + hartOffset(context(i, mode))
def enableAddr(i: Int, mode: Char) = enableBase + enableOffset(context(i, mode))
def size = hartBase + hartOffset(maxHarts)
def claimAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode)) + PLICConsts.claimOffset
def threshAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode))
def enableAddr(i: Int, mode: Char) = address + PLICConsts.enableBase(context(i, mode))
def maxDevices = 1023
def maxHarts = 15872
def pendingBase = 0x1000
def enableBase = 0x2000
def hartBase = 0x200000
require(hartBase >= enableBase + enableOffset(maxHarts))
// Create the global PLIC config string
val globalConfigString = Seq(
s"plic {\n",
s" priority 0x${address.toString(16)};\n",
s" pending 0x${(address + PLICConsts.pendingBase).toString(16)};\n",
s" ndevs ${nDevices};\n",
s"};\n").mkString
def enableOffset(i: Int) = i * ((maxDevices+7)/8)
def hartOffset(i: Int) = i * 0x1000
def claimOffset = 4
def priorityBytes = 4
require(nDevices <= maxDevices)
require(nHarts > 0 && nHarts <= maxHarts)
require(nPriorities >= 0 && nPriorities <= nDevices)
}
/** Platform-Level Interrupt Controller */
class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
with HasTileLinkParameters
with HasAddrMapParameters {
val io = new Bundle {
val devices = Vec(cfg.nDevices, new GatewayPLICIO).flip
val harts = Vec(cfg.nHarts, Bool()).asOutput
val tl = new ClientUncachedTileLinkIO().flip
// Create the per-Hart config string
val hartConfigStrings = io.harts.zipWithIndex.map { case (_, i) => (Seq(
s" plic {\n",
s" m {\n",
s" ie 0x${enableAddr(i, 'M').toString(16)};\n",
s" thresh 0x${threshAddr(i, 'M').toString(16)};\n",
s" claim 0x${claimAddr(i, 'M').toString(16)};\n",
s" };\n") ++ (if (!supervisor) Seq() else Seq(
s" s {\n",
s" ie 0x${enableAddr(i, 'S').toString(16)};\n",
s" thresh 0x${threshAddr(i, 'S').toString(16)};\n",
s" claim 0x${claimAddr(i, 'S').toString(16)};\n",
s" };\n")) ++ Seq(
s" };\n")).mkString
}
val priority =
if (cfg.nPriorities > 0) Reg(Vec(cfg.nDevices+1, UInt(width=log2Up(cfg.nPriorities+1))))
else Wire(init=Vec.fill(cfg.nDevices+1)(UInt(1)))
val threshold =
if (cfg.nPriorities > 0) Reg(Vec(cfg.nHarts, UInt(width = log2Up(cfg.nPriorities+1))))
else Wire(init=Vec.fill(cfg.nHarts)(UInt(0)))
val pending = Reg(init=Vec.fill(cfg.nDevices+1){Bool(false)})
val enables = Reg(Vec(cfg.nHarts, Vec(cfg.nDevices+1, Bool())))
// For now, use LevelGateways for all TL2 interrupts
val gateways = Vec(interrupts.map { case i =>
val gateway = Module(new LevelGateway)
gateway.io.interrupt := i
gateway.io.plic
})
for ((p, g) <- pending.tail zip io.devices) {
val priority =
if (nPriorities > 0) Reg(Vec(nDevices+1, UInt(width=log2Up(nPriorities+1))))
else Wire(init=Vec.fill(nDevices+1)(UInt(1)))
val threshold =
if (nPriorities > 0) Reg(Vec(nHarts, UInt(width = log2Up(nPriorities+1))))
else Wire(init=Vec.fill(nHarts)(UInt(0)))
val pending = Reg(init=Vec.fill(nDevices+1){Bool(false)})
val enables = Reg(Vec(nHarts, Vec(nDevices+1, Bool())))
for ((p, g) <- pending.tail zip gateways) {
g.ready := !p
g.complete := false
when (g.valid) { p := true }
@ -87,101 +158,55 @@ class PLIC(val cfg: PLICConfig)(implicit val p: Parameters) extends Module
val lMax = findMax(x take half)
val rMax = findMax(x drop half)
val useLeft = lMax._1 >= rMax._1
(Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) + rMax._2))
(Mux(useLeft, lMax._1, rMax._1), Mux(useLeft, lMax._2, UInt(half) | rMax._2))
} else (x.head, UInt(0))
}
val maxDevs = Wire(Vec(cfg.nHarts, UInt(width = log2Up(pending.size))))
for (hart <- 0 until cfg.nHarts) {
val maxDevs = Reg(Vec(nHarts, UInt(width = log2Up(pending.size))))
for (hart <- 0 until nHarts) {
val effectivePriority =
for (((p, en), pri) <- (pending zip enables(hart) zip priority).tail)
yield Cat(p && en, pri)
val (maxPri, maxDev) = findMax((UInt(1) << priority(0).getWidth) +: effectivePriority)
maxDevs(hart) := Reg(next = maxDev)
io.harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
maxDevs(hart) := maxDev
harts(hart) := Reg(next = maxPri) > Cat(UInt(1), threshold(hart))
}
val acq = Queue(io.tl.acquire, 1)
val read = acq.fire() && acq.bits.isBuiltInType(Acquire.getType)
val write = acq.fire() && acq.bits.isBuiltInType(Acquire.putType)
assert(!acq.fire() || read || write, "unsupported PLIC operation")
val addr = acq.bits.full_addr()(log2Up(cfg.size)-1,0)
def priorityRegField(x: UInt) = if (nPriorities > 0) RegField(32, x) else RegField.r(32, x)
val priorityRegFields = Seq(PLICConsts.priorityBase -> priority.map(p => priorityRegField(p)))
val pendingRegFields = Seq(PLICConsts.pendingBase -> pending .map(b => RegField.r(1, b)))
val claimant =
if (cfg.nHarts == 1) UInt(0)
else (addr - cfg.hartBase)(log2Up(cfg.hartOffset(cfg.nHarts))-1,log2Up(cfg.hartOffset(1)))
val hart = Wire(init = claimant)
val myMaxDev = maxDevs(claimant)
val myEnables = enables(hart)
val rdata = Wire(init = UInt(0, tlDataBits))
val masked_wdata = (acq.bits.data & acq.bits.full_wmask()) | (rdata & ~acq.bits.full_wmask())
val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
PLICConsts.enableBase(i) -> e.map(b => RegField(1, b))
}
if (cfg.nDevices > 0) when (addr >= cfg.hartBase) {
val word =
if (tlDataBytes > cfg.claimOffset) UInt(0)
else addr(log2Up(cfg.claimOffset),log2Up(tlDataBytes))
rdata := Cat(myMaxDev, UInt(0, 8*cfg.priorityBytes-threshold(0).getWidth), threshold(claimant)) >> (word * tlDataBits)
val hartRegFields = Seq.tabulate(nHarts) { i =>
PLICConsts.hartBase(i) -> Seq(
priorityRegField(threshold(i)),
RegField(32,
RegReadFn { valid =>
when (valid) {
pending(maxDevs(i)) := Bool(false)
maxDevs(i) := UInt(0) // flush pipeline
}
(Bool(true), maxDevs(i))
},
RegWriteFn { (valid, data) =>
when (valid && enables(i)(data)) {
gateways(data - UInt(1)).complete := Bool(true)
}
Bool(true)
}
)
)
}
when (read && addr(log2Ceil(cfg.claimOffset))) {
pending(myMaxDev) := false
}
when (write) {
when (if (tlDataBytes > cfg.claimOffset) acq.bits.wmask()(cfg.claimOffset) else addr(log2Ceil(cfg.claimOffset))) {
val dev = (acq.bits.data >> ((8 * cfg.claimOffset) % tlDataBits))(log2Up(pending.size)-1,0)
when (myEnables(dev)) { io.devices(dev-1).complete := true }
}.otherwise {
if (cfg.nPriorities > 0) threshold(claimant) := acq.bits.data
}
}
}.elsewhen (addr >= cfg.enableBase) {
val enableHart =
if (cfg.nHarts > 1) (addr - cfg.enableBase)(log2Up(cfg.enableOffset(cfg.nHarts))-1,log2Up(cfg.enableOffset(1)))
else UInt(0)
hart := enableHart
val word =
if (tlDataBits >= myEnables.size) UInt(0)
else addr(log2Ceil((myEnables.size-1)/tlDataBits+1) + tlByteAddrBits - 1, tlByteAddrBits)
for (i <- 0 until myEnables.size by tlDataBits) {
when (word === i/tlDataBits) {
rdata := Cat(myEnables.slice(i, i + tlDataBits).reverse)
for (j <- 0 until (tlDataBits min (myEnables.size - i))) {
when (write) { enables(enableHart)(i+j) := masked_wdata(j) }
}
}
}
}.elsewhen (addr >= cfg.pendingBase) {
val word =
if (tlDataBytes >= pending.size) UInt(0)
else addr(log2Up(pending.size)-1,log2Up(tlDataBytes))
rdata := pending.asUInt >> (word * tlDataBits)
}.otherwise {
val regsPerBeat = tlDataBytes >> log2Up(cfg.priorityBytes)
val word =
if (regsPerBeat >= priority.size) UInt(0)
else addr(log2Up(priority.size*cfg.priorityBytes)-1,log2Up(tlDataBytes))
for (i <- 0 until priority.size by regsPerBeat) {
when (word === i/regsPerBeat) {
rdata := Cat(priority.slice(i, i + regsPerBeat).map(p => Cat(UInt(0, 8*cfg.priorityBytes-p.getWidth), p)).reverse)
for (j <- 0 until (regsPerBeat min (priority.size - i))) {
if (cfg.nPriorities > 0) when (write) { priority(i+j) := masked_wdata >> (j * 8 * cfg.priorityBytes) }
}
}
}
}
node.regmap((priorityRegFields ++ pendingRegFields ++ enableRegFields ++ hartRegFields):_*)
priority(0) := 0
pending(0) := false
for (e <- enables)
e(0) := false
io.tl.grant.valid := acq.valid
acq.ready := io.tl.grant.ready
io.tl.grant.bits := Grant(
is_builtin_type = Bool(true),
g_type = acq.bits.getBuiltInGrantType(),
client_xact_id = acq.bits.client_xact_id,
manager_xact_id = UInt(0),
addr_beat = UInt(0),
data = rdata)
}
}

View File

@ -6,6 +6,7 @@ import Chisel._
import junctions._
import junctions.NastiConstants._
import regmapper._
import diplomacy._
import uncore.tilelink2._
import uncore.util._
import util._
@ -20,22 +21,19 @@ class CoreplexLocalInterrupts extends Bundle {
val msip = Bool()
}
case class CoreplexLocalInterrupterConfig(beatBytes: Int, address: BigInt = 0x02000000) {
object ClintConsts
{
def msipOffset(hart: Int) = hart * msipBytes
def msipAddress(hart: Int) = address + msipOffset(hart)
def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
def timecmpAddress(hart: Int) = address + timecmpOffset(hart)
def timeOffset = 0xbff8
def timeAddress = address + timeOffset
def msipBytes = 4
def timecmpBytes = 8
def size = 0x10000
}
trait MixCoreplexLocalInterrupterParameters {
val params: (CoreplexLocalInterrupterConfig, Parameters)
val c = params._1
implicit val p = params._2
val params: Parameters
implicit val p = params
}
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
@ -45,11 +43,10 @@ trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterru
trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters {
val io: CoreplexLocalInterrupterBundle
val address: AddressSet
val timeWidth = 64
val regWidth = 32
// demand atomic accesses for RV64
require(c.beatBytes >= (p(rocket.XLen) min timeWidth)/8)
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
when (io.rtcTick) {
@ -66,6 +63,15 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
tile.mtip := time.asUInt >= timecmp(i).asUInt
}
val globalConfigString = Seq(
s"rtc {\n",
s" addr 0x${(address.base + ClintConsts.timeOffset).toString(16)};\n",
s"};\n").mkString
val hartConfigStrings = (0 until p(NTiles)).map { i => Seq(
s" timecmp 0x${(address.base + ClintConsts.timecmpOffset(i)).toString(16)};\n",
s" ipi 0x${(address.base + ClintConsts.msipOffset(i)).toString(16)};\n").mkString
}
/* 0000 msip hart 0
* 0004 msip hart 1
* 4000 mtimecmp hart 0 lo
@ -78,15 +84,15 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
regmap(
0 -> makeRegFields(ipi),
c.timecmpOffset(0) -> makeRegFields(timecmp.flatten),
c.timeOffset -> makeRegFields(time))
ClintConsts.timecmpOffset(0) -> makeRegFields(timecmp.flatten),
ClintConsts.timeOffset -> makeRegFields(time))
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
}
/** Power, Reset, Clock, Interrupt */
// Magic TL2 Incantation to create a TL2 Slave
class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p: Parameters)
extends TLRegisterRouter(c.address, 0, c.size, 0, c.beatBytes, false)(
new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)(
new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule)
class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit val p: Parameters)
extends TLRegisterRouter(address, size = ClintConsts.size, beatBytes = p(rocket.XLen)/8, undefZero = false)(
new TLRegBundle(p, _) with CoreplexLocalInterrupterBundle)(
new TLRegModule(p, _, _) with CoreplexLocalInterrupterModule)

View File

@ -94,7 +94,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
val cam_free = cam_s.map(_.state === FREE)
val cam_amo = cam_s.map(_.state === AMO)
val cam_abusy = cam_s.map(e => e.state === GET || e.state === AMO) // A is blocked
val cam_dmatch = cam_s.map(e => e.state === GET || e.state === ACK) // D should inspect these entries
val cam_dmatch = cam_s.map(e => e.state =/= FREE) // D should inspect these entries
// Can the manager already handle this message?
val a_size = edgeIn.size(in.a.bits)
@ -211,7 +211,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
val d_cam_sel_match = (d_cam_sel_raw zip cam_dmatch) map { case (a,b) => a&&b }
val d_cam_data = Mux1H(d_cam_sel_match, cam_d.map(_.data))
val d_cam_sel_bypass = if (edgeOut.manager.minLatency > 0) Bool(false) else
out.d.bits.source === in.a.bits.source && in.a.valid && out.d.valid && !a_isSupported
out.d.bits.source === in.a.bits.source && in.a.valid && !a_isSupported
val d_cam_sel = (a_cam_sel_free zip d_cam_sel_match) map { case (a,d) => Mux(d_cam_sel_bypass, a, d) }
val d_cam_sel_any = d_cam_sel_bypass || d_cam_sel_match.reduce(_ || _)
val d_ackd = out.d.bits.opcode === TLMessages.AccessAckData

View File

@ -2,6 +2,7 @@
package uncore.tilelink2
import scala.math.min
import Chisel._
import chisel3.internal.sourceinfo.SourceInfo
import diplomacy._
@ -9,10 +10,9 @@ import diplomacy._
// Acks Hints for managers that don't support them or Acks all Hints if !passthrough
class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule
{
// HintAcks can come back combinationally => minLatency=0
val node = TLAdapterNode(
clientFn = { case Seq(c) => if (!supportClients) c else c.copy(minLatency = 0, clients = c.clients .map(_.copy(supportsHint = TransferSizes(1, c.maxTransfer)))) },
managerFn = { case Seq(m) => if (!supportManagers) m else m.copy(minLatency = 0, managers = m.managers.map(_.copy(supportsHint = TransferSizes(1, m.maxTransfer)))) })
clientFn = { case Seq(c) => if (!supportClients) c else c.copy(minLatency = min(1, c.minLatency), clients = c.clients .map(_.copy(supportsHint = TransferSizes(1, c.maxTransfer)))) },
managerFn = { case Seq(m) => if (!supportManagers) m else m.copy(minLatency = min(1, m.minLatency), managers = m.managers.map(_.copy(supportsHint = TransferSizes(1, m.maxTransfer)))) })
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
@ -46,7 +46,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
hint.bits := edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address))
out.a.bits := in.a.bits
TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats1(out.d.bits), out.d), (UInt(0), hint))
TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats1(out.d.bits), out.d), (UInt(0), Queue(hint, 1)))
} else {
out.a.valid := in.a.valid
in.a.ready := out.a.ready
@ -69,7 +69,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
hint.bits := edgeOut.HintAck(out.b.bits)
in.b.bits := out.b.bits
TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats1(in.c.bits), in.c), (UInt(0), hint))
TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats1(in.c.bits), in.c), (UInt(0), Queue(hint, 1)))
} else if (bce) {
in.b.valid := out.b.valid
out.b.ready := in.b.ready

View File

@ -58,10 +58,13 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
}
def bundleI(ei: Seq[IntEdge]): Vec[Vec[Bool]] = {
require (!ei.isEmpty)
Vec(ei.size, Vec(ei.map(_.source.num).max, Bool())).flip
Vec(ei.size, Vec(ei.map(_.source.num).max, Bool()))
}
def colour = "#0000ff" // blue
override def labelI(ei: IntEdge) = ei.source.sources.map(_.range.size).sum.toString
override def labelO(eo: IntEdge) = eo.source.sources.map(_.range.size).sum.toString
def connect(bo: => Vec[Bool], bi: => Vec[Bool], ei: => IntEdge)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
(None, () => {
// Cannot use bulk connect, because the widths could differ
@ -76,9 +79,6 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
}
case class IntIdentityNode() extends IdentityNode(IntImp)
case class IntOutputNode() extends OutputNode(IntImp)
case class IntInputNode() extends InputNode(IntImp)
case class IntSourceNode(num: Int) extends SourceNode(IntImp)(
IntSourcePortParameters(Seq(IntSourceParameters(num))), (if (num == 0) 0 else 1) to 1)
case class IntSinkNode() extends SinkNode(IntImp)(
@ -91,11 +91,20 @@ case class IntAdapterNode(
numSinkPorts: Range.Inclusive = 1 to 1)
extends InteriorNode(IntImp)(sourceFn, sinkFn, numSourcePorts, numSinkPorts)
case class IntOutputNode() extends OutputNode(IntImp)
case class IntInputNode() extends InputNode(IntImp)
case class IntBlindOutputNode() extends BlindOutputNode(IntImp)(IntSinkPortParameters(Seq(IntSinkParameters())))
case class IntBlindInputNode(num: Int) extends BlindInputNode(IntImp)(IntSourcePortParameters(Seq(IntSourceParameters(num))))
case class IntInternalOutputNode() extends InternalOutputNode(IntImp)(IntSinkPortParameters(Seq(IntSinkParameters())))
case class IntInternalInputNode(num: Int) extends InternalInputNode(IntImp)(IntSourcePortParameters(Seq(IntSourceParameters(num))))
class IntXbar extends LazyModule
{
val intnode = IntAdapterNode(
numSourcePorts = 1 to 1, // does it make sense to have more than one interrupt sink?
numSinkPorts = 1 to 128,
numSinkPorts = 0 to 128,
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
sourceFn = { seq =>
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
@ -113,3 +122,17 @@ class IntXbar extends LazyModule
io.out.foreach { _ := cat }
}
}
class IntXing extends LazyModule
{
val intnode = IntIdentityNode()
lazy val module = new LazyModuleImp(this) {
val io = new Bundle {
val in = intnode.bundleIn
val out = intnode.bundleOut
}
io.out := RegNext(RegNext(RegNext(io.in)))
}
}

View File

@ -38,11 +38,9 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa
require (m.supportsPutPartial.contains(TransferSizes(1, tlDataBytes)))
require (m.supportsPutPartial.contains(TransferSizes(tlDataBeats * tlDataBytes)))
}
// Any atomic support => must support 32-bit up to beat size of all types
if (m.supportsArithmetic || m.supportsLogical) {
require (m.supportsArithmetic.contains(TransferSizes(4, tlDataBytes)))
require (m.supportsLogical .contains(TransferSizes(4, tlDataBytes)))
}
// Any atomic support => must support 32-bit size
if (m.supportsArithmetic) { require (m.supportsArithmetic.contains(TransferSizes(4))) }
if (m.supportsLogical) { require (m.supportsLogical .contains(TransferSizes(4))) }
// We straight-up require hints
require (edge.manager.allSupportHint)
}

View File

@ -17,7 +17,7 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL
}
def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = {
require (!ei.isEmpty)
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_))))
}
var emitMonitors = true
@ -25,6 +25,9 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL
var combinationalCheck = false
def colour = "#000000" // black
override def labelI(ei: TLEdgeIn) = (ei.manager.beatBytes * 8).toString
override def labelO(eo: TLEdgeOut) = (eo.manager.beatBytes * 8).toString
def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
val monitor = if (emitMonitors) {
Some(LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => ei, sourceInfo)))
@ -89,10 +92,8 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL
}
}
// Nodes implemented inside modules
case class TLIdentityNode() extends IdentityNode(TLImp)
case class TLOutputNode() extends OutputNode(TLImp)
case class TLInputNode() extends InputNode(TLImp)
case class TLClientNode(portParams: TLClientPortParameters, numPorts: Range.Inclusive = 1 to 1)
extends SourceNode(TLImp)(portParams, numPorts)
case class TLManagerNode(portParams: TLManagerPortParameters, numPorts: Range.Inclusive = 1 to 1)
@ -117,6 +118,14 @@ case class TLAdapterNode(
numManagerPorts: Range.Inclusive = 1 to 1)
extends InteriorNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
// Nodes passed from an inner module
case class TLOutputNode() extends OutputNode(TLImp)
case class TLInputNode() extends InputNode(TLImp)
// Nodes used for external ports
case class TLBlindOutputNode(portParams: TLManagerPortParameters) extends BlindOutputNode(TLImp)(portParams)
case class TLBlindInputNode(portParams: TLClientPortParameters) extends BlindInputNode(TLImp)(portParams)
/** Synthesizeable unit tests */
import unittest._
@ -149,10 +158,13 @@ object TLAsyncImp extends NodeImp[TLAsyncClientPortParameters, TLAsyncManagerPor
}
def bundleI(ei: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
require (ei.size == 1)
Vec(ei.size, new TLAsyncBundle(ei(0).bundle)).flip
Vec(ei.size, new TLAsyncBundle(ei(0).bundle))
}
def colour = "#ff0000" // red
override def labelI(ei: TLAsyncEdgeParameters) = ei.manager.depth.toString
override def labelO(eo: TLAsyncEdgeParameters) = eo.manager.depth.toString
def connect(bo: => TLAsyncBundle, bi: => TLAsyncBundle, ei: => TLAsyncEdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
(None, () => { bi <> bo })
}

View File

@ -7,10 +7,11 @@ import diplomacy._
import regmapper._
import scala.math.{min,max}
class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true)
class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
extends TLManagerNode(TLManagerPortParameters(
Seq(TLManagerParameters(
address = Seq(address),
executable = executable,
supportsGet = TransferSizes(1, beatBytes),
supportsPutPartial = TransferSizes(1, beatBytes),
supportsPutFull = TransferSizes(1, beatBytes),
@ -70,17 +71,17 @@ class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int =
object TLRegisterNode
{
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true) =
new TLRegisterNode(address, concurrency, beatBytes, undefZero)
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false) =
new TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
}
// These convenience methods below combine to make it possible to create a TL2
// register mapped device from a totally abstract register mapped device.
// See GPIO.scala in this directory for an example
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean) extends LazyModule
abstract class TLRegisterRouterBase(val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean) extends LazyModule
{
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero)
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
val intnode = IntSourceNode(interrupts)
}
@ -99,14 +100,15 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
{
val io = bundleBuilder
val interrupts = if (io.interrupts.isEmpty) Vec(0, Bool()) else io.interrupts(0)
val address = router.address
def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*)
}
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true)
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
(bundleBuilder: TLRegBundleArg => B)
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero)
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero, executable)
{
require (isPow2(size))
// require (size >= 4096) ... not absolutely required, but highly recommended

View File

@ -5,9 +5,11 @@ import diplomacy._
package object tilelink2
{
type TLInwardNode = InwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle]
type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]
type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]]
def OH1ToOH(x: UInt) = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x)
def OH1ToUInt(x: UInt) = OHToUInt(OH1ToOH(x))
def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)

View File

@ -5,6 +5,7 @@ package unittest
object Generator extends util.GeneratorApp {
val longName = names.topModuleProject + "." + names.configs
generateFirrtl
generateGraphML
generateTestSuiteMakefrags // TODO: Needed only for legacy make targets
generateParameterDump // TODO: Needed only for legacy make targets
}