diff --git a/src/main/scala/Configs.scala b/src/main/scala/Configs.scala index 5da49d2b..b55a2a81 100644 --- a/src/main/scala/Configs.scala +++ b/src/main/scala/Configs.scala @@ -34,15 +34,18 @@ class BaseConfig extends Config ( entries += AddrMapEntry("bootrom", MemSize(4096, MemAttr(AddrMapProt.RX))) entries += AddrMapEntry("plic", MemRange(0x40000000, 0x4000000, MemAttr(AddrMapProt.RW))) entries += AddrMapEntry("prci", MemSize(0x4000000, MemAttr(AddrMapProt.RW))) - entries ++= site(ExtraDevices).map(_.addrMapEntry) new AddrMap(entries) } lazy val globalAddrMap = { val memBase = 0x80000000L val memSize = 0x10000000L - val io = new AddrMap(AddrMapEntry("int", internalIOAddrMap) +: site(ExtMMIOPorts).entries) + + val intern = AddrMapEntry("int", internalIOAddrMap) + val extern = AddrMapEntry("ext", MemRange(0x50000000L, 0x30000000L, MemAttr(AddrMapProt.RWX))) + val ioMap = if (site(ExportMMIOPort)) AddrMap(intern, extern) else AddrMap(intern) + val addrMap = AddrMap( - AddrMapEntry("io", io), + AddrMapEntry("io", ioMap), AddrMapEntry("mem", MemRange(memBase, memSize, MemAttr(AddrMapProt.RWX, true)))) Dump("MEM_BASE", addrMap("mem").start) @@ -51,6 +54,7 @@ class BaseConfig extends Config ( } def makeConfigString() = { val addrMap = globalAddrMap + val extAddrMap = site(ExtAddrMap) val plicAddr = addrMap("io:int:plic").start val prciAddr = addrMap("io:int:prci").start val plicInfo = site(PLICKey) @@ -97,7 +101,7 @@ class BaseConfig extends Config ( } for (device <- site(ExtraDevices)) { val deviceName = device.addrMapEntry.name - val deviceRegion = addrMap("io:int:" + deviceName) + val deviceRegion = extAddrMap(deviceName) res.append(device.makeConfigString(deviceRegion)) } res append "};\n" @@ -188,6 +192,7 @@ class BaseConfig extends Config ( } } case BuildRoCC => Nil + case BuildCoreplex => (p: Parameters) => Module(new DefaultCoreplex(p)) case RoccNMemChannels => site(BuildRoCC).map(_.nMemChannels).foldLeft(0)(_ + _) case RoccNPTWPorts => site(BuildRoCC).map(_.nPTWPorts).foldLeft(0)(_ + _) case RoccNCSRs => site(BuildRoCC).map(_.csrs.size).foldLeft(0)(_ + _) @@ -231,17 +236,18 @@ class BaseConfig extends Config ( case AsyncMMIOChannels => false case ExtraDevices => Nil case ExtraTopPorts => (p: Parameters) => new Bundle - case ExtMMIOPorts => AddrMap() -/* - AddrMap( - AddrMapEntry("cfg", MemRange(0x50000000L, 0x04000000L, MemAttr(AddrMapProt.RW))), - AddrMapEntry("ext", MemRange(0x60000000L, 0x20000000L, MemAttr(AddrMapProt.RWX)))) -*/ + case ExtMMIOPorts => Nil + case ExtAddrMap => new AddrMap( + site(ExtraDevices).map(_.addrMapEntry) ++ + site(ExtMMIOPorts), + start = BigInt("50000000", 16)) case NExtMMIOAXIChannels => 0 case NExtMMIOAHBChannels => 0 case NExtMMIOTLChannels => 0 + case ExportMMIOPort => (site(ExtraDevices).size + site(ExtMMIOPorts).size) > 0 case AsyncBusChannels => false case NExtBusAXIChannels => 0 + case ExportBusPort => site(NExtBusAXIChannels) > 0 case PLICKey => PLICConfig(site(NTiles), site(UseVM), site(NExtInterrupts), 0) case DMKey => new DefaultDebugModuleConfig(site(NTiles), site(XLen)) case FDivSqrt => true diff --git a/src/main/scala/Coreplex.scala b/src/main/scala/Coreplex.scala new file mode 100644 index 00000000..41df986c --- /dev/null +++ b/src/main/scala/Coreplex.scala @@ -0,0 +1,255 @@ +package rocketchip + +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._ +import java.nio.{ByteBuffer,ByteOrder} +import java.nio.file.{Files, Paths} + +/** 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]] +/** A string describing on-chip devices, readable by target software */ +case object ConfigString extends Field[Array[Byte]] +/** Number of external interrupt sources */ +case object NExtInterrupts extends Field[Int] +/** Interrupt controller configuration */ +case object PLICKey extends Field[PLICConfig] +/** Number of clock cycles per RTC tick */ +case object RTCPeriod extends Field[Int] +/** The file to read the BootROM contents from */ +case object BootROMFile extends Field[String] +/** Export an external MMIO slave port */ +case object ExportMMIOPort extends Field[Boolean] +/** Expose an additional bus master port */ +case object ExportBusPort extends Field[Boolean] +/** Function for building Coreplex */ +case object BuildCoreplex extends Field[Parameters => Coreplex] + +/** 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 + with HasTopLevelParameters { + + val io = new 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 prci = Vec(nTiles, new PRCITileIO).asOutput + val bus = if (exportBus) Some(new ClientUncachedTileLinkIO().flip) else None + val mmio = if (exportMMIO) Some(new ClientUncachedTileLinkIO()(outermostMMIOParams)) else None + val interrupts = Vec(p(NExtInterrupts), Bool()).asInput + val debug = new DebugBusIO()(p).flip + } + + val outmemsys = if (nCachedTilePorts + nUncachedTilePorts > 0) + Module(new OuterMemorySystem) // 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 + if (exportBus) { outmemsys.io.bus.get <> io.bus.get } + io.mem <> outmemsys.io.mem + + buildMMIONetwork(p.alterPartial({case TLId => "L2toMMIO"})) + + def makeBootROM()(implicit p: Parameters) = { + val romdata = Files.readAllBytes(Paths.get(p(BootROMFile))) + val rom = ByteBuffer.wrap(romdata) + + rom.order(ByteOrder.LITTLE_ENDIAN) + + // for now, have the reset vector jump straight to memory + val resetToMemDist = p(GlobalAddrMap)("mem").start - p(ResetVector) + require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12)) + val configStringAddr = p(ResetVector).toInt + rom.capacity + + require(rom.getInt(12) == 0, + "Config string address position should not be occupied by code") + rom.putInt(12, configStringAddr) + rom.array() ++ p(ConfigString).toSeq + } + + def buildMMIONetwork(implicit p: Parameters) = { + val ioAddrMap = p(GlobalAddrMap).subMap("io") + + val mmioNetwork = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap)) + mmioNetwork.io.in.head <> outmemsys.io.mmio + + val plic = Module(new PLIC(p(PLICKey))) + 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 + + val prci = Module(new PRCI) + prci.io.tl <> mmioNetwork.port("int:prci") + io.prci := prci.io.tiles + prci.io.rtcTick := Counter(p(RTCPeriod)).inc() // placeholder for real RTC + + 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 bootROM = Module(new ROMSlave(makeBootROM())) + bootROM.io <> mmioNetwork.port("int:bootrom") + + io.mmio.map { ext => ext <> mmioNetwork.port("ext") } + } +} + +abstract class AbstractOuterMemorySystem(implicit val p: Parameters) + extends Module with HasTopLevelParameters { + val io = new Bundle { + val tiles_cached = Vec(nCachedTilePorts, new ClientTileLinkIO).flip + val tiles_uncached = Vec(nUncachedTilePorts, new ClientUncachedTileLinkIO).flip + val bus = if (exportBus) Some(new ClientUncachedTileLinkIO().flip) else None + 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 AbstractOuterMemorySystem()(p) { + require(nCachedTilePorts + nUncachedTilePorts == 0) + require(io.bus.isEmpty) + + 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 OuterMemorySystem(implicit p: Parameters) extends AbstractOuterMemorySystem()(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 = { + val isMemory = p(GlobalAddrMap).isInRegion("mem", addr << log2Up(p(CacheBlockBytes))) + Mux(isMemory, + if (nBanks > 1) addr(lsb + log2Up(nBanks) - 1, lsb) else UInt(0), + 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 <> mmioManager.io.outer + + // 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.bus + 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 ((name, region) <- p(GlobalAddrMap).flatten) { + println(f"\t$name%s ${region.start}%x - ${region.start + region.size - 1}%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 HasTopLevelParameters { + val io = new Bundle { + val mem = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outermostParams)) + val bus = if (p(ExportBusPort)) Some(new ClientUncachedTileLinkIO().flip) else None + val mmio = if(p(ExportMMIOPort)) Some(new ClientUncachedTileLinkIO()(outermostMMIOParams)) else None + val interrupts = Vec(p(NExtInterrupts), Bool()).asInput + val debug = new DebugBusIO()(p).flip + } +} + +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 + } + + // 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 + uncore.io.interrupts <> io.interrupts + uncore.io.debug <> io.debug + if (exportBus) { uncore.io.bus.get <> io.bus.get } + if (exportMMIO) { io.mmio.get <> uncore.io.mmio.get } + io.mem <> uncore.io.mem +} diff --git a/src/main/scala/RocketChip.scala b/src/main/scala/RocketChip.scala index 374be473..137f32c9 100644 --- a/src/main/scala/RocketChip.scala +++ b/src/main/scala/RocketChip.scala @@ -6,15 +6,10 @@ 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._ -import java.nio.{ByteBuffer,ByteOrder} -import java.nio.file.{Files, Paths} /** Top-level parameters of RocketChip, values set in e.g. PublicConfigs.scala */ @@ -27,38 +22,25 @@ object BusType { val busTypes = Seq(AXI, AHB, TL) } -/** Number of memory channels */ -case object AsyncMemChannels extends Field[Boolean] -case object NMemoryChannels extends Field[Int] +/** Memory channel controls */ case object TMemoryChannels extends Field[BusType.EnumVal] -/** 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] /** Number of outstanding memory requests */ case object NOutstandingMemReqsPerChannel extends Field[Int] -/** Number of exteral MMIO ports */ -case object AsyncMMIOChannels extends Field[Boolean] -case object ExtMMIOPorts extends Field[AddrMap] +/** External MMIO controls */ case object NExtMMIOAXIChannels extends Field[Int] case object NExtMMIOAHBChannels extends Field[Int] case object NExtMMIOTLChannels extends Field[Int] -case object AsyncBusChannels extends Field[Boolean] +/** External Bus controls */ case object NExtBusAXIChannels 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]] -/** A string describing on-chip devices, readable by target software */ -case object ConfigString extends Field[Array[Byte]] -/** Number of external interrupt sources */ -case object NExtInterrupts extends Field[Int] -/** Interrupt controller configuration */ -case object PLICKey extends Field[PLICConfig] -/** Number of clock cycles per RTC tick */ -case object RTCPeriod extends Field[Int] +/** Async configurations */ +case object AsyncBusChannels extends Field[Boolean] case object AsyncDebugBus extends Field[Boolean] -case object BootROMFile extends Field[String] +case object AsyncMemChannels extends Field[Boolean] +case object AsyncMMIOChannels extends Field[Boolean] + +/** External address map settings */ +case object ExtMMIOPorts extends Field[Seq[AddrMapEntry]] +case object ExtAddrMap extends Field[AddrMap] /** Utility trait for quick access to some relevant parameters */ trait HasTopLevelParameters { @@ -81,6 +63,8 @@ trait HasTopLevelParameters { lazy val xLen = p(XLen) lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" }) lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" }) + lazy val exportBus = p(ExportBusPort) + lazy val exportMMIO = p(ExportMMIOPort) } class MemBackupCtrlIO extends Bundle { @@ -148,34 +132,14 @@ class Top(topParams: Parameters) extends Module with HasTopLevelParameters { implicit val p = topParams val io = new TopIO - // 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 coreplex = p(BuildCoreplex)(p) + val periphery = Module(new Periphery) - val innerTLParams = p.alterPartial({ - case HastiId => "TL" - case TLId => "L1toL2" - case NCachedTileLinkPorts => nCachedPorts - case NUncachedTileLinkPorts => nUncachedPorts - }) + if (exportMMIO) { periphery.io.mmio_in.get <> coreplex.io.mmio.get } + periphery.io.mem_in <> coreplex.io.mem + if (exportBus) { coreplex.io.bus.get <> periphery.io.bus_out.get } - val uncore = Module(new Uncore()(innerTLParams)) - - (uncore.io.prci, tileResets, tileList).zipped.foreach { - case (prci, rst, tile) => - rst := prci.reset - tile.io.prci <> prci - } - - // 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 - uncore.io.interrupts <> io.interrupts - uncore.io.debugBus <> + coreplex.io.debug <> (if (p(AsyncDebugBus)) AsyncDebugBusFrom(io.debug_clk.get, io.debug_rst.get, io.debug) else io.debug) @@ -192,62 +156,49 @@ class Top(topParams: Parameters) extends Module with HasTopLevelParameters { io.mmio_axi <> (if (p(AsyncMMIOChannels)) - asyncAxiTo(io.mmio_clk.get, io.mmio_rst.get, uncore.io.mmio_axi) - else uncore.io.mmio_axi) - io.mmio_ahb <> uncore.io.mmio_ahb - io.mmio_tl <> uncore.io.mmio_tl + asyncAxiTo(io.mmio_clk.get, io.mmio_rst.get, periphery.io.mmio_axi) + else periphery.io.mmio_axi) + io.mmio_ahb <> periphery.io.mmio_ahb + io.mmio_tl <> periphery.io.mmio_tl io.mem_axi <> (if (p(AsyncMemChannels)) - asyncAxiTo(io.mem_clk.get, io.mem_rst.get, uncore.io.mem_axi) - else uncore.io.mem_axi) - io.mem_ahb <> uncore.io.mem_ahb - io.mem_tl <> uncore.io.mem_tl + asyncAxiTo(io.mem_clk.get, io.mem_rst.get, periphery.io.mem_axi) + else periphery.io.mem_axi) + io.mem_ahb <> periphery.io.mem_ahb + io.mem_tl <> periphery.io.mem_tl - uncore.io.bus_axi <> + periphery.io.bus_axi <> (if (p(AsyncBusChannels)) asyncAxiFrom(io.bus_clk.get, io.bus_rst.get, io.bus_axi) else io.bus_axi) - io.extra <> uncore.io.extra + io.extra <> periphery.io.extra } -/** 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 +class Periphery(implicit val p: Parameters) extends Module with HasTopLevelParameters { - val io = new Bundle { + val mem_in = Vec(nMemChannels, new ClientUncachedTileLinkIO()(outermostParams)).flip + val bus_out = if (exportBus) Some(new ClientUncachedTileLinkIO) else None + val mmio_in = if (exportMMIO) Some(new ClientUncachedTileLinkIO()(outermostMMIOParams).flip) else None val mem_axi = Vec(nMemAXIChannels, new NastiIO) val mem_ahb = Vec(nMemAHBChannels, new HastiMasterIO) val mem_tl = Vec(nMemTLChannels, new ClientUncachedTileLinkIO()(outermostParams)) - val tiles_cached = Vec(nCachedTilePorts, new ClientTileLinkIO).flip - val tiles_uncached = Vec(nUncachedTilePorts, new ClientUncachedTileLinkIO).flip - val prci = Vec(nTiles, new PRCITileIO).asOutput val bus_axi = Vec(p(NExtBusAXIChannels), new NastiIO).flip val mmio_axi = Vec(p(NExtMMIOAXIChannels), new NastiIO) val mmio_ahb = Vec(p(NExtMMIOAHBChannels), new HastiMasterIO) val mmio_tl = Vec(p(NExtMMIOTLChannels), new ClientUncachedTileLinkIO()(outermostMMIOParams)) - val interrupts = Vec(p(NExtInterrupts), Bool()).asInput - val debugBus = new DebugBusIO()(p).flip val extra = p(ExtraTopPorts)(p) } - val outmemsys = if (nCachedTilePorts + nUncachedTilePorts > 0) - Module(new OuterMemorySystem) // 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 - - buildMMIONetwork(p.alterPartial({case TLId => "L2toMMIO"})) - - io.mem_axi <> outmemsys.io.mem_axi - io.mem_ahb <> outmemsys.io.mem_ahb - io.mem_tl <> outmemsys.io.mem_tl - outmemsys.io.bus_axi <> io.bus_axi + io.bus_out.map { tl_out => + val conv = Module(new TileLinkIONastiIOConverter) + val arb = Module(new NastiArbiter(p(NExtBusAXIChannels))) + arb.io.master <> io.bus_axi + conv.io.nasti <> conv.io.tl + tl_out <> conv.io.tl + } def connectExternalMMIO(ports: Seq[ClientUncachedTileLinkIO])(implicit p: Parameters) { val mmio_axi_start = 0 @@ -273,189 +224,41 @@ class Uncore(implicit val p: Parameters) extends Module } } - def makeBootROM()(implicit p: Parameters) = { - val romdata = Files.readAllBytes(Paths.get(p(BootROMFile))) - val rom = ByteBuffer.wrap(romdata) - - rom.order(ByteOrder.LITTLE_ENDIAN) - - // for now, have the reset vector jump straight to memory - val resetToMemDist = p(GlobalAddrMap)("mem").start - p(ResetVector) - require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12)) - val configStringAddr = p(ResetVector).toInt + rom.capacity - - require(rom.getInt(12) == 0, - "Config string address position should not be occupied by code") - rom.putInt(12, configStringAddr) - rom.array() ++ p(ConfigString).toSeq - } - def buildMMIONetwork(implicit p: Parameters) = { - val ioAddrMap = p(GlobalAddrMap).subMap("io") + val extAddrMap = p(ExtAddrMap) - val mmioNetwork = Module(new TileLinkRecursiveInterconnect(1, ioAddrMap)) - mmioNetwork.io.in.head <> outmemsys.io.mmio - - val plic = Module(new PLIC(p(PLICKey))) - 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.debugBus - - val prci = Module(new PRCI) - prci.io.tl <> mmioNetwork.port("int:prci") - io.prci := prci.io.tiles - prci.io.rtcTick := Counter(p(RTCPeriod)).inc() // placeholder for real RTC - - 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 bootROM = Module(new ROMSlave(makeBootROM())) - bootROM.io <> mmioNetwork.port("int:bootrom") + val mmioNetwork = Module(new TileLinkRecursiveInterconnect(1, extAddrMap)) + mmioNetwork.io.in.head <> io.mmio_in.get for (device <- p(ExtraDevices)) { - device.builder(mmioNetwork.port("int:" + device.addrMapEntry.name), io.extra, p) + device.builder(mmioNetwork.port(device.addrMapEntry.name), io.extra, p) } - val ext = p(ExtMMIOPorts).entries.map(port => TileLinkWidthAdapter(mmioNetwork.port(port.name), "MMIO_Outermost")) + val ext = p(ExtMMIOPorts).map( + port => TileLinkWidthAdapter(mmioNetwork.port(port.name), "MMIO_Outermost")) connectExternalMMIO(ext)(outermostMMIOParams) } -} -abstract class AbstractOuterMemorySystem(implicit val p: Parameters) - extends Module with HasTopLevelParameters { - val io = new Bundle { - val tiles_cached = Vec(nCachedTilePorts, new ClientTileLinkIO).flip - val tiles_uncached = Vec(nUncachedTilePorts, new ClientUncachedTileLinkIO).flip - val incoherent = Vec(nCachedTilePorts, Bool()).asInput - val mem_axi = Vec(nMemAXIChannels, new NastiIO) - val mem_ahb = Vec(nMemAHBChannels, new HastiMasterIO) - val mem_tl = Vec(nMemTLChannels, new ClientUncachedTileLinkIO()(outermostParams)) - val bus_axi = Vec(p(NExtBusAXIChannels), new NastiIO).flip - 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 AbstractOuterMemorySystem()(p) { - require(nCachedTilePorts + nUncachedTilePorts == 0) - - io.mem_axi.foreach { axi => - axi.ar.valid := Bool(false) - axi.aw.valid := Bool(false) - axi.w.valid := Bool(false) - axi.r.ready := Bool(false) - axi.b.ready := Bool(false) + if (exportMMIO) { + buildMMIONetwork(p.alterPartial({case TLId => "L2toMMIO"})) } - io.mem_ahb.foreach { ahb => - ahb.htrans := UInt(0) - ahb.hmastlock := Bool(false) - ahb.hwrite := Bool(false) - ahb.haddr := UInt(0) - ahb.hburst := UInt(0) - ahb.hsize := UInt(0) - ahb.hprot := UInt(0) - } - - io.mem_tl.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 OuterMemorySystem(implicit p: Parameters) extends AbstractOuterMemorySystem()(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 = { - val isMemory = p(GlobalAddrMap).isInRegion("mem", addr << log2Up(p(CacheBlockBytes))) - Mux(isMemory, - if (nBanks > 1) addr(lsb + log2Up(nBanks) - 1, lsb) else UInt(0), - 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 <> mmioManager.io.outer - - val bus_in = io.bus_axi.map { ext_nasti => - val converter = Module(new TileLinkIONastiIOConverter) - converter.io.nasti <> ext_nasti - converter.io.tl - } - - // 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 ++ bus_in - 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 outermostTLParams = p.alterPartial({case TLId => "Outermost"}) - val backendBuffering = TileLinkDepths(0,0,0,0,0) - - // TODO: the code to print this stuff should live somewhere else - println("Generated Address Map") - for ((name, region) <- p(GlobalAddrMap).flatten) { - println(f"\t$name%s ${region.start}%x - ${region.start + region.size - 1}%x") - } - println("Generated Configuration String") - println(new String(p(ConfigString))) - - val mem_ic = Module(new TileLinkMemoryInterconnect(nBanksPerMemChannel, nMemChannels)(outermostTLParams)) - - 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) - } - - for ((nasti, tl) <- io.mem_axi zip mem_ic.io.out) { - TopUtils.connectTilelinkNasti(nasti, tl)(outermostTLParams) + for ((nasti, tl) <- io.mem_axi zip io.mem_in) { + TopUtils.connectTilelinkNasti(nasti, tl)(outermostParams) // Memory cache type should be normal non-cacheable bufferable // TODO why is this happening here? Would 0000 (device) be OK instead? nasti.ar.bits.cache := UInt("b0011") nasti.aw.bits.cache := UInt("b0011") } - + // Abuse the fact that zip takes the shorter of the two lists - for ((ahb, tl) <- io.mem_ahb zip mem_ic.io.out) { + for ((ahb, tl) <- io.mem_ahb zip io.mem_in) { val bridge = Module(new AHBBridge(false)) // no atomics ahb <> bridge.io.ahb bridge.io.tl <> tl } - for ((mem_tl, tl) <- io.mem_tl zip mem_ic.io.out) { + for ((mem_tl, tl) <- io.mem_tl zip io.mem_in) { TopUtils.connectTilelink(mem_tl, tl) } } diff --git a/src/main/scala/TestConfigs.scala b/src/main/scala/TestConfigs.scala index cecde465..f0256238 100644 --- a/src/main/scala/TestConfigs.scala +++ b/src/main/scala/TestConfigs.scala @@ -69,7 +69,10 @@ class WithComparator extends Config( case BuildGroundTest => (p: Parameters) => Module(new ComparatorCore()(p)) case ComparatorKey => ComparatorParameters( - targets = Seq("mem", "io:int:testram").map(name => site(GlobalAddrMap)(name).start.longValue), + targets = Seq( + site(GlobalAddrMap)("mem"), + site(ExtAddrMap)("testram")) + .map(entry => entry.start.longValue), width = 8, operations = 1000, atomics = site(UseAtomics),