2016-08-11 02:20:00 +02:00
|
|
|
package coreplex
|
2016-08-10 03:26:52 +02:00
|
|
|
|
|
|
|
import Chisel._
|
|
|
|
import cde.{Parameters, Field}
|
|
|
|
import junctions._
|
|
|
|
import uncore.tilelink._
|
|
|
|
import uncore.coherence._
|
|
|
|
import uncore.agents._
|
|
|
|
import uncore.devices._
|
|
|
|
import uncore.util._
|
|
|
|
import uncore.converters._
|
|
|
|
import rocket._
|
|
|
|
import rocket.Util._
|
|
|
|
|
|
|
|
/** Number of memory channels */
|
|
|
|
case object NMemoryChannels extends Field[Int]
|
|
|
|
/** Number of banks per memory channel */
|
|
|
|
case object NBanksPerMemoryChannel extends Field[Int]
|
|
|
|
/** Least significant bit of address used for bank partitioning */
|
|
|
|
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]]
|
|
|
|
/** The file to read the BootROM contents from */
|
|
|
|
case object BootROMFile extends Field[String]
|
|
|
|
|
2016-08-10 18:49:56 +02:00
|
|
|
trait HasCoreplexParameters {
|
|
|
|
implicit val p: Parameters
|
|
|
|
lazy val nBanksPerMemChannel = p(NBanksPerMemoryChannel)
|
|
|
|
lazy val lsb = p(BankIdLSB)
|
2016-08-15 21:45:24 +02:00
|
|
|
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
2016-08-10 18:49:56 +02:00
|
|
|
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
|
|
|
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" })
|
2016-09-15 09:38:46 +02:00
|
|
|
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap)
|
2016-08-10 18:49:56 +02:00
|
|
|
}
|
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
case class CoreplexConfig(
|
|
|
|
nTiles: Int,
|
|
|
|
nExtInterrupts: Int,
|
|
|
|
nSlaves: Int,
|
2016-09-12 21:40:10 +02:00
|
|
|
nMemChannels: Int,
|
2016-09-11 08:39:29 +02:00
|
|
|
hasSupervisor: Boolean,
|
|
|
|
hasExtMMIOPort: Boolean)
|
|
|
|
{
|
|
|
|
val plicKey = PLICConfig(nTiles, hasSupervisor, nExtInterrupts, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract class Coreplex(implicit val p: Parameters, implicit val c: CoreplexConfig) extends Module
|
2016-08-10 18:49:56 +02:00
|
|
|
with HasCoreplexParameters {
|
2016-09-11 08:39:29 +02:00
|
|
|
class CoreplexIO(implicit val p: Parameters, implicit val c: CoreplexConfig) extends Bundle {
|
|
|
|
val master = new Bundle {
|
2016-09-12 21:40:10 +02:00
|
|
|
val mem = Vec(c.nMemChannels, new ClientUncachedTileLinkIO()(outermostParams))
|
2016-09-11 08:39:29 +02:00
|
|
|
val mmio = c.hasExtMMIOPort.option(new ClientUncachedTileLinkIO()(outermostMMIOParams))
|
|
|
|
}
|
|
|
|
val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
|
|
|
|
val interrupts = Vec(c.nExtInterrupts, Bool()).asInput
|
2016-08-10 03:26:52 +02:00
|
|
|
val debug = new DebugBusIO()(p).flip
|
2016-09-16 23:26:34 +02:00
|
|
|
val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput
|
2016-09-15 21:19:22 +02:00
|
|
|
val success = Bool(OUTPUT)
|
Allow reset vector to be set dynamically
A chip's power-up sequence, or awake-from-sleep sequence, may wish to
set the reset PC based upon dynamic properties, e.g., the settings of
external pins. Support this by passing the reset vector to the Coreplex.
ExampleTop simply hard-wires the reset vector, as was the case before.
Additionally, allow MTVEC to *not* be reset. In most cases, including
riscv-tests, pk, and bbl, overriding MTVEC is one of the first things
that the boot sequence does. So the reset value is superfluous.
2016-09-20 01:45:57 +02:00
|
|
|
val resetVector = UInt(INPUT, p(XLen))
|
2016-09-03 02:45:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
val io = new CoreplexIO
|
|
|
|
}
|
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
class DefaultCoreplex(tp: Parameters, tc: CoreplexConfig) extends Coreplex()(tp, tc) {
|
2016-09-15 21:19:22 +02:00
|
|
|
// Coreplex doesn't know when to stop running
|
|
|
|
io.success := Bool(false)
|
|
|
|
|
2016-09-03 02:45:08 +02:00
|
|
|
// Build a set of Tiles
|
2016-09-11 08:39:29 +02:00
|
|
|
val tileResets = Wire(Vec(tc.nTiles, Bool()))
|
2016-09-03 02:45:08 +02:00
|
|
|
val tileList = p(BuildTiles).zip(tileResets).map {
|
|
|
|
case (tile, rst) => tile(rst, p)
|
|
|
|
}
|
|
|
|
val nCachedPorts = tileList.map(tile => tile.io.cached.size).reduce(_ + _)
|
|
|
|
val nUncachedPorts = tileList.map(tile => tile.io.uncached.size).reduce(_ + _)
|
2016-09-12 21:40:10 +02:00
|
|
|
val nBanks = tc.nMemChannels * nBanksPerMemChannel
|
2016-09-03 02:45:08 +02:00
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
// Build an uncore backing the Tiles
|
2016-09-03 02:45:08 +02:00
|
|
|
buildUncore(p.alterPartial({
|
2016-09-04 06:55:09 +02:00
|
|
|
case HastiId => "TL"
|
|
|
|
case TLId => "L1toL2"
|
|
|
|
case NCachedTileLinkPorts => nCachedPorts
|
|
|
|
case NUncachedTileLinkPorts => nUncachedPorts
|
|
|
|
}))
|
2016-09-03 02:45:08 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
def sharerToClientId(sharerId: UInt) = sharerId
|
|
|
|
def addrToBank(addr: UInt): UInt = if (nBanks == 0) UInt(0) else {
|
2016-09-11 08:39:29 +02:00
|
|
|
val isMemory = globalAddrMap.isInRegion("mem", addr << log2Up(p(CacheBlockBytes)))
|
2016-09-03 02:45:08 +02:00
|
|
|
Mux(isMemory, addr.extract(lsb + log2Ceil(nBanks) - 1, lsb), UInt(nBanks))
|
|
|
|
}
|
|
|
|
val preBuffering = TileLinkDepths(1,1,2,2,0)
|
|
|
|
val l1tol2net = Module(new PortedTileLinkCrossbar(addrToBank, sharerToClientId, preBuffering))
|
|
|
|
|
|
|
|
// Create point(s) of coherence serialization
|
|
|
|
val managerEndpoints = List.tabulate(nBanks){id => p(BuildL2CoherenceManager)(id, p)}
|
2016-09-04 06:55:09 +02:00
|
|
|
managerEndpoints.flatMap(_.incoherent).foreach(_ := Bool(false))
|
2016-09-03 02:45:08 +02:00
|
|
|
|
|
|
|
val mmioManager = Module(new MMIOTileLinkManager()(p.alterPartial({
|
|
|
|
case TLId => "L1toL2"
|
|
|
|
case InnerTLId => "L1toL2"
|
|
|
|
case OuterTLId => "L2toMMIO"
|
|
|
|
})))
|
|
|
|
|
|
|
|
// Wire the tiles to the TileLink client ports of the L1toL2 network,
|
|
|
|
// and coherence manager(s) to the other side
|
|
|
|
l1tol2net.io.clients_cached <> tileList.map(_.io.cached).flatten
|
2016-09-11 08:39:29 +02:00
|
|
|
l1tol2net.io.clients_uncached <> tileList.map(_.io.uncached).flatten ++ io.slave
|
2016-09-03 02:45:08 +02:00
|
|
|
l1tol2net.io.managers <> managerEndpoints.map(_.innerTL) :+ mmioManager.io.inner
|
|
|
|
|
|
|
|
// Create a converter between TileLinkIO and MemIO for each channel
|
2016-09-12 21:40:10 +02:00
|
|
|
val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, tc.nMemChannels)(outermostParams))
|
2016-09-03 02:45:08 +02:00
|
|
|
|
|
|
|
val outerTLParams = p.alterPartial({ case TLId => "L2toMC" })
|
|
|
|
val backendBuffering = TileLinkDepths(0,0,0,0,0)
|
|
|
|
for ((bank, icPort) <- managerEndpoints zip mem_ic.io.in) {
|
|
|
|
val unwrap = Module(new ClientTileLinkIOUnwrapper()(outerTLParams))
|
2016-09-13 20:24:05 +02:00
|
|
|
unwrap.io.in <> TileLinkEnqueuer(bank.outerTL, backendBuffering)(outerTLParams)
|
2016-09-03 02:45:08 +02:00
|
|
|
TileLinkWidthAdapter(icPort, unwrap.io.out)
|
|
|
|
}
|
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
io.master.mem <> mem_ic.io.out
|
2016-08-10 03:26:52 +02:00
|
|
|
|
2016-09-13 20:24:05 +02:00
|
|
|
buildMMIONetwork(TileLinkEnqueuer(mmioManager.io.outer, 1))(
|
2016-09-03 02:45:08 +02:00
|
|
|
p.alterPartial({case TLId => "L2toMMIO"}))
|
|
|
|
}
|
2016-08-10 03:26:52 +02:00
|
|
|
|
2016-09-03 02:45:08 +02:00
|
|
|
def buildMMIONetwork(mmio: ClientUncachedTileLinkIO)(implicit p: Parameters) = {
|
2016-09-11 08:39:29 +02:00
|
|
|
val ioAddrMap = globalAddrMap.subMap("io")
|
2016-08-10 03:26:52 +02:00
|
|
|
|
|
|
|
val mmioNetwork = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap))
|
2016-09-03 02:45:08 +02:00
|
|
|
mmioNetwork.io.in.head <> mmio
|
2016-08-10 03:26:52 +02:00
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
val plic = Module(new PLIC(c.plicKey))
|
2016-08-10 03:26:52 +02:00
|
|
|
plic.io.tl <> mmioNetwork.port("int: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 <> mmioNetwork.port("int:debug")
|
|
|
|
debugModule.io.db <> io.debug
|
|
|
|
|
2016-09-14 01:25:31 +02:00
|
|
|
// connect coreplex-internal interrupts to tiles
|
|
|
|
for (((tile, tileReset), i) <- (tileList zip tileResets) zipWithIndex) {
|
2016-09-16 23:26:34 +02:00
|
|
|
tileReset := reset // TODO should tiles be reset separately from coreplex?
|
|
|
|
tile.io.interrupts := io.clint(i)
|
2016-09-14 01:25:31 +02:00
|
|
|
tile.io.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
|
|
|
|
tile.io.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
|
|
|
|
tile.io.interrupts.debug := debugModule.io.debugInterrupts(i)
|
|
|
|
tile.io.hartid := i
|
Allow reset vector to be set dynamically
A chip's power-up sequence, or awake-from-sleep sequence, may wish to
set the reset PC based upon dynamic properties, e.g., the settings of
external pins. Support this by passing the reset vector to the Coreplex.
ExampleTop simply hard-wires the reset vector, as was the case before.
Additionally, allow MTVEC to *not* be reset. In most cases, including
riscv-tests, pk, and bbl, overriding MTVEC is one of the first things
that the boot sequence does. So the reset value is superfluous.
2016-09-20 01:45:57 +02:00
|
|
|
tile.io.resetVector := io.resetVector
|
2016-08-10 03:26:52 +02:00
|
|
|
}
|
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
val tileSlavePorts = (0 until tc.nTiles) map (i => s"int:dmem$i") filter (ioAddrMap contains _)
|
2016-09-03 02:45:08 +02:00
|
|
|
for ((t, m) <- (tileList.map(_.io.slave).flatten) zip (tileSlavePorts map (mmioNetwork port _)))
|
2016-09-13 20:24:05 +02:00
|
|
|
t <> TileLinkEnqueuer(m, 1)
|
2016-09-03 00:59:16 +02:00
|
|
|
|
2016-09-11 08:39:29 +02:00
|
|
|
io.master.mmio.foreach { _ <> mmioNetwork.port("ext") }
|
2016-08-10 03:26:52 +02:00
|
|
|
}
|
|
|
|
}
|