From a4c19429582e2134721576024a14b318b05b6d76 Mon Sep 17 00:00:00 2001 From: Yunsup Lee Date: Fri, 2 Sep 2016 17:45:08 -0700 Subject: [PATCH] flatten Coreplex module hierarchy --- src/main/scala/coreplex/Coreplex.scala | 263 +++++++++---------------- 1 file changed, 94 insertions(+), 169 deletions(-) diff --git a/src/main/scala/coreplex/Coreplex.scala b/src/main/scala/coreplex/Coreplex.scala index 023b471b..bf741383 100644 --- a/src/main/scala/coreplex/Coreplex.scala +++ b/src/main/scala/coreplex/Coreplex.scala @@ -55,36 +55,96 @@ trait HasCoreplexParameters { lazy val exportMMIO = p(ExportMMIOPort) } -/** Wrapper around everything that isn't a Tile. - * - * Usually this is clocked and/or place-and-routed separately from the Tiles. - */ -class Uncore(implicit val p: Parameters) extends Module +abstract class Coreplex(implicit val p: Parameters) extends Module with HasCoreplexParameters { - - val io = new Bundle { + class CoreplexIO(implicit val p: Parameters) extends Bundle { val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outermostParams)) - val tiles_cached = Vec(nCachedTilePorts, new ClientTileLinkIO).flip - val tiles_uncached = Vec(nUncachedTilePorts, new ClientUncachedTileLinkIO).flip - val tiles_slave = Vec(nTiles, new ClientUncachedTileLinkIO) - val ext_uncached = Vec(nExtClients, new ClientUncachedTileLinkIO()(innerParams)).flip - val prci = Vec(nTiles, new PRCITileIO).asOutput - val mmio = exportMMIO.option(new ClientUncachedTileLinkIO()(outermostMMIOParams)) + val ext_clients = Vec(nExtClients, new ClientUncachedTileLinkIO()(innerParams)).flip + val mmio = p(ExportMMIOPort).option(new ClientUncachedTileLinkIO()(outermostMMIOParams)) val interrupts = Vec(p(NExtInterrupts), Bool()).asInput val debug = new DebugBusIO()(p).flip - val rtcTick = Bool(INPUT) + val rtcTick = new Bool(INPUT) + val extra = p(ExtraCoreplexPorts)(p) + val success: Option[Bool] = hasSuccessFlag.option(Bool(OUTPUT)) } - val outmemsys = if (nCachedTilePorts + nUncachedTilePorts > 0) - Module(new DefaultOuterMemorySystem) // NoC, LLC and SerDes - else Module(new DummyOuterMemorySystem) - outmemsys.io.incoherent foreach (_ := false) - outmemsys.io.tiles_uncached <> io.tiles_uncached - outmemsys.io.tiles_cached <> io.tiles_cached - outmemsys.io.ext_uncached <> io.ext_uncached - io.mem <> outmemsys.io.mem + def hasSuccessFlag: Boolean = false + val io = new CoreplexIO +} - buildMMIONetwork(p.alterPartial({case TLId => "L2toMMIO"})) +class DefaultCoreplex(topParams: Parameters) extends Coreplex()(topParams) { + // Build a set of Tiles + val tileResets = Wire(Vec(nTiles, Bool())) + 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(_ + _) + + printConfigString + buildUncore(p.alterPartial({ + case HastiId => "TL" + case TLId => "L1toL2" + case NCachedTileLinkPorts => nCachedPorts + case NUncachedTileLinkPorts => nUncachedPorts + })) + + def printConfigString(implicit p: Parameters) = { + 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 + println(f"\t$name%s $start%x - $end%x") + } + println("Generated Configuration String") + println(new String(p(ConfigString))) + } + + 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 { + val isMemory = p(GlobalAddrMap).isInRegion("mem", addr << log2Up(p(CacheBlockBytes))) + 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)} + managerEndpoints.foreach { _.incoherent := Vec.fill(nCachedTilePorts)(Bool(false)) } + + 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 + l1tol2net.io.clients_uncached <> tileList.map(_.io.uncached).flatten ++ io.ext_clients + l1tol2net.io.managers <> managerEndpoints.map(_.innerTL) :+ mmioManager.io.inner + + // Create a converter between TileLinkIO and MemIO for each channel + val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, nMemChannels)(outermostParams)) + + 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)) + unwrap.io.in <> ClientTileLinkEnqueuer(bank.outerTL, backendBuffering)(outerTLParams) + TileLinkWidthAdapter(icPort, unwrap.io.out) + } + + io.mem <> mem_ic.io.out + + buildMMIONetwork(ClientUncachedTileLinkEnqueuer(mmioManager.io.outer, 1))( + p.alterPartial({case TLId => "L2toMMIO"})) + } def makeBootROM()(implicit p: Parameters) = { val romdata = Files.readAllBytes(Paths.get(p(BootROMFile))) @@ -104,11 +164,12 @@ class Uncore(implicit val p: Parameters) extends Module rom.array() ++ p(ConfigString).toSeq } - def buildMMIONetwork(implicit p: Parameters) = { + + def buildMMIONetwork(mmio: ClientUncachedTileLinkIO)(implicit p: Parameters) = { val ioAddrMap = p(GlobalAddrMap).subMap("io") val mmioNetwork = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap)) - mmioNetwork.io.in.head <> outmemsys.io.mmio + mmioNetwork.io.in.head <> mmio val plic = Module(new PLIC(p(PLICKey))) plic.io.tl <> mmioNetwork.port("int:plic") @@ -124,168 +185,32 @@ class Uncore(implicit val p: Parameters) extends Module val prci = Module(new PRCI) prci.io.tl <> mmioNetwork.port("int:prci") - io.prci := prci.io.tiles prci.io.rtcTick := io.rtcTick + (prci.io.tiles, tileResets, tileList).zipped.foreach { + case (prci, rst, tile) => + rst := reset + tile.io.prci <> prci + } + for (i <- 0 until nTiles) { prci.io.interrupts(i).meip := plic.io.harts(plic.cfg.context(i, 'M')) if (p(UseVM)) prci.io.interrupts(i).seip := plic.io.harts(plic.cfg.context(i, 'S')) prci.io.interrupts(i).debug := debugModule.io.debugInterrupts(i) - - io.prci(i).reset := reset } val tileSlavePorts = (0 until nTiles) map (i => s"int:dmem$i") filter (ioAddrMap contains _) - for ((t, m) <- io.tiles_slave zip (tileSlavePorts map (mmioNetwork port _))) + for ((t, m) <- (tileList.map(_.io.slave).flatten) zip (tileSlavePorts map (mmioNetwork port _))) t <> ClientUncachedTileLinkEnqueuer(m, 1) val bootROM = Module(new ROMSlave(makeBootROM())) bootROM.io <> mmioNetwork.port("int:bootrom") - io.mmio.map { ext => ext <> mmioNetwork.port("ext") } + io.mmio.foreach { _ <> mmioNetwork.port("ext") } } } -abstract class OuterMemorySystem(implicit val p: Parameters) - extends Module with HasCoreplexParameters { - val io = new Bundle { - val tiles_cached = Vec(nCachedTilePorts, new ClientTileLinkIO).flip - val tiles_uncached = Vec(nUncachedTilePorts, new ClientUncachedTileLinkIO).flip - val ext_uncached = Vec(nExtClients, new ClientUncachedTileLinkIO()(innerParams)).flip - val incoherent = Vec(nCachedTilePorts, Bool()).asInput - val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outermostParams)) - val mmio = new ClientUncachedTileLinkIO()(p.alterPartial({case TLId => "L2toMMIO"})) - } -} - -/** Use in place of OuterMemorySystem if there are no clients to connect. */ -class DummyOuterMemorySystem(implicit p: Parameters) extends OuterMemorySystem()(p) { - require(nCachedTilePorts + nUncachedTilePorts + nExtClients == 0) - - io.mem.foreach { tl => - tl.acquire.valid := Bool(false) - tl.grant.ready := Bool(false) - } - - io.mmio.acquire.valid := Bool(false) - io.mmio.grant.ready := Bool(false) -} - -/** The whole outer memory hierarchy, including a NoC, some kind of coherence - * manager agent, and a converter from TileLink to MemIO. - */ -class DefaultOuterMemorySystem(implicit p: Parameters) extends OuterMemorySystem()(p) { - // 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 { - val isMemory = p(GlobalAddrMap).isInRegion("mem", addr << log2Up(p(CacheBlockBytes))) - 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)} - managerEndpoints.foreach { _.incoherent := io.incoherent } - - val mmioManager = Module(new MMIOTileLinkManager()(p.alterPartial({ - case TLId => "L1toL2" - case InnerTLId => "L1toL2" - case OuterTLId => "L2toMMIO" - }))) - - io.mmio.acquire <> Queue(mmioManager.io.outer.acquire, 1) - mmioManager.io.outer.grant <> Queue(io.mmio.grant, 1) - - // Wire the tiles to the TileLink client ports of the L1toL2 network, - // and coherence manager(s) to the other side - l1tol2net.io.clients_cached <> io.tiles_cached - l1tol2net.io.clients_uncached <> io.tiles_uncached ++ io.ext_uncached - l1tol2net.io.managers <> managerEndpoints.map(_.innerTL) :+ mmioManager.io.inner - - // Create a converter between TileLinkIO and MemIO for each channel - val outerTLParams = p.alterPartial({ case TLId => "L2toMC" }) - val backendBuffering = TileLinkDepths(0,0,0,0,0) - - // TODO: the code to print this stuff should live somewhere else - 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 - println(f"\t$name%s $start%x - $end%x") - } - println("Generated Configuration String") - println(new String(p(ConfigString))) - - val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, nMemChannels)(outermostParams)) - - for ((bank, icPort) <- managerEndpoints zip mem_ic.io.in) { - val unwrap = Module(new ClientTileLinkIOUnwrapper()(outerTLParams)) - unwrap.io.in <> ClientTileLinkEnqueuer(bank.outerTL, backendBuffering)(outerTLParams) - TileLinkWidthAdapter(icPort, unwrap.io.out) - } - - io.mem <> mem_ic.io.out -} - -abstract class Coreplex(implicit val p: Parameters) extends Module - with HasCoreplexParameters { - class CoreplexIO(implicit val p: Parameters) extends Bundle { - val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outermostParams)) - val ext_clients = Vec(nExtClients, new ClientUncachedTileLinkIO()(innerParams)).flip - val mmio = p(ExportMMIOPort).option(new ClientUncachedTileLinkIO()(outermostMMIOParams)) - val interrupts = Vec(p(NExtInterrupts), Bool()).asInput - val debug = new DebugBusIO()(p).flip - val rtcTick = new Bool(INPUT) - val extra = p(ExtraCoreplexPorts)(p) - val success: Option[Bool] = hasSuccessFlag.option(Bool(OUTPUT)) - } - - def hasSuccessFlag: Boolean = false - val io = new CoreplexIO -} - -class DefaultCoreplex(topParams: Parameters) extends Coreplex()(topParams) { - // Build an Uncore and a set of Tiles - val tileResets = Wire(Vec(nTiles, Bool())) - 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(_ + _) - - val innerTLParams = p.alterPartial({ - case HastiId => "TL" - case TLId => "L1toL2" - case NCachedTileLinkPorts => nCachedPorts - case NUncachedTileLinkPorts => nUncachedPorts - }) - - val uncore = Module(new Uncore()(innerTLParams)) - - (uncore.io.prci, tileResets, tileList).zipped.foreach { - case (prci, rst, tile) => - rst := prci.reset - tile.io.prci <> prci - } - - uncore.io.rtcTick := io.rtcTick - - // Connect the uncore to the tile memory ports, HostIO and MemIO - uncore.io.tiles_cached <> tileList.map(_.io.cached).flatten - uncore.io.tiles_uncached <> tileList.map(_.io.uncached).flatten - (tileList.map(_.io.slave).flatten zip uncore.io.tiles_slave) foreach { case (x, y) => x <> y } - uncore.io.interrupts <> io.interrupts - uncore.io.debug <> io.debug - uncore.io.ext_uncached <> io.ext_clients - if (exportMMIO) { io.mmio.get <> uncore.io.mmio.get } - io.mem <> uncore.io.mem -} - class GroundTestCoreplex(topParams: Parameters) extends DefaultCoreplex(topParams) { override def hasSuccessFlag = true io.success.get := tileList.flatMap(_.io.elements get "success").map(_.asInstanceOf[Bool]).reduce(_&&_)