refactor top-level into coreplex and platform
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										255
									
								
								src/main/scala/Coreplex.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								src/main/scala/Coreplex.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user