coreplex => subsystem
This commit is contained in:
		
							
								
								
									
										107
									
								
								src/main/scala/subsystem/BaseSubsystem.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/main/scala/subsystem/BaseSubsystem.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| /** BareSubsystem is the root class for creating a subsystem */ | ||||
| abstract class BareSubsystem(implicit p: Parameters) extends LazyModule with BindingScope { | ||||
|   lazy val dts = DTS(bindingTree) | ||||
|   lazy val dtb = DTB(dts) | ||||
|   lazy val json = JSON(bindingTree) | ||||
| } | ||||
|  | ||||
| abstract class BareSubsystemModule[+L <: BareSubsystem](_outer: L) extends LazyModuleImp(_outer) { | ||||
|   val outer = _outer | ||||
|   ElaborationArtefacts.add("graphml", outer.graphML) | ||||
|   ElaborationArtefacts.add("dts", outer.dts) | ||||
|   ElaborationArtefacts.add("json", outer.json) | ||||
|   ElaborationArtefacts.add("plusArgs", PlusArgArtefacts.serialize_cHeader) | ||||
|   println(outer.dts) | ||||
| } | ||||
|  | ||||
| /** Base Subsystem class with no peripheral devices or ports added */ | ||||
| abstract class BaseSubsystem(implicit p: Parameters) extends BareSubsystem | ||||
|     with HasInterruptBus | ||||
|     with HasSystemBus | ||||
|     with HasPeripheryBus | ||||
|     with HasMemoryBus { | ||||
|   override val module: BaseSubsystemModule[BaseSubsystem] | ||||
|  | ||||
|   // Make topManagers an Option[] so as to avoid LM name reflection evaluating it... | ||||
|   lazy val topManagers = Some(ManagerUnification(sharedMemoryTLEdge.manager.managers)) | ||||
|   ResourceBinding { | ||||
|     val managers = topManagers.get | ||||
|     val max = managers.flatMap(_.address).map(_.max).max | ||||
|     val width = ResourceInt((log2Ceil(max)+31) / 32) | ||||
|     val model = p(DTSModel) | ||||
|     val compat = p(DTSCompat) | ||||
|     val devCompat = (model +: compat).map(s => ResourceString(s + "-dev")) | ||||
|     val socCompat = (model +: compat).map(s => ResourceString(s + "-soc")) | ||||
|     devCompat.foreach { Resource(ResourceAnchors.root, "compat").bind(_) } | ||||
|     socCompat.foreach { Resource(ResourceAnchors.soc,  "compat").bind(_) } | ||||
|     Resource(ResourceAnchors.root, "model").bind(ResourceString(model)) | ||||
|     Resource(ResourceAnchors.root, "width").bind(width) | ||||
|     Resource(ResourceAnchors.soc,  "width").bind(width) | ||||
|     Resource(ResourceAnchors.cpus, "width").bind(ResourceInt(1)) | ||||
|  | ||||
|     managers.foreach { case manager => | ||||
|       val value = manager.toResource | ||||
|       manager.resources.foreach { case resource => | ||||
|         resource.bind(value) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| abstract class BaseSubsystemModule[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModule(_outer) { | ||||
|   println("Generated Address Map") | ||||
|   private val aw = (outer.sharedMemoryTLEdge.bundle.addressBits-1)/4 + 1 | ||||
|   private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s" | ||||
|  | ||||
|   private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = { | ||||
|     value match { | ||||
|       case r: ResourceAddress => List((path(1), r)) | ||||
|       case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions))) | ||||
|       case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) } | ||||
|       case _ => Nil | ||||
|     } | ||||
|   } | ||||
|   private val ranges = collect(Nil, outer.bindingTree).groupBy(_._2).toList.flatMap { case (key, seq) => | ||||
|     AddressRange.fromSets(key.address).map { r => (r, key.permissions, seq.map(_._1)) } | ||||
|   }.sortBy(_._1) | ||||
|   private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c, a), names) => | ||||
|     println(fmt.format( | ||||
|       range.base, | ||||
|       range.base+range.size, | ||||
|       if (a) 'A' else ' ', | ||||
|       if (r) 'R' else ' ', | ||||
|       if (w) 'W' else ' ', | ||||
|       if (x) 'X' else ' ', | ||||
|       if (c) 'C' else ' ', | ||||
|       names.mkString(", "))) | ||||
|     s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],"names":[${names.map('"'+_+'"').mkString(",")}]}""" | ||||
|   } | ||||
|   println("") | ||||
|   ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${json.mkString(",")}]}""") | ||||
|  | ||||
|   // Confirm that all of memory was described by DTS | ||||
|   private val dtsRanges = AddressRange.unify(ranges.map(_._1)) | ||||
|   private val allRanges = AddressRange.unify(outer.topManagers.get.flatMap { m => AddressRange.fromSets(m.address) }) | ||||
|  | ||||
|   if (dtsRanges != allRanges) { | ||||
|     println("Address map described by DTS differs from physical implementation:") | ||||
|     AddressRange.subtract(allRanges, dtsRanges).foreach { case r => | ||||
|       println(s"\texists, but undescribed by DTS: ${r}") | ||||
|     } | ||||
|     AddressRange.subtract(dtsRanges, allRanges).foreach { case r => | ||||
|       println(s"\tdoes not exist, but described by DTS: ${r}") | ||||
|     } | ||||
|     println("") | ||||
|   } | ||||
| } | ||||
							
								
								
									
										304
									
								
								src/main/scala/subsystem/Configs.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								src/main/scala/subsystem/Configs.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
| // See LICENSE.Berkeley for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.devices.debug._ | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.rocket._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| class BaseSubsystemConfig extends Config ((site, here, up) => { | ||||
|   // Tile parameters | ||||
|   case PgLevels => if (site(XLen) == 64) 3 /* Sv39 */ else 2 /* Sv32 */ | ||||
|   case XLen => 64 // Applies to all cores | ||||
|   case MaxHartIdBits => log2Up(site(RocketTilesKey).size) | ||||
|   case BuildCore => (p: Parameters) => new Rocket()(p) | ||||
|   // Interconnect parameters | ||||
|   case SystemBusKey => SystemBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes)) | ||||
|   case PeripheryBusKey => PeripheryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes)) | ||||
|   case MemoryBusKey => MemoryBusParams(beatBytes = site(XLen)/8, blockBytes = site(CacheBlockBytes)) | ||||
|   // Additional device Parameters | ||||
|   case ErrorParams => ErrorParams(Seq(AddressSet(0x3000, 0xfff)), maxAtomic=site(XLen)/8, maxTransfer=4096) | ||||
|   case BootROMParams => BootROMParams(contentFileName = "./bootrom/bootrom.img") | ||||
|   case DebugModuleParams => DefaultDebugModuleParams(site(XLen)) | ||||
| }) | ||||
|  | ||||
| /* Composable partial function Configs to set individual parameters */ | ||||
|  | ||||
| class WithNBigCores(n: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => { | ||||
|     val big = RocketTileParams( | ||||
|       core   = RocketCoreParams(mulDiv = Some(MulDivParams( | ||||
|         mulUnroll = 8, | ||||
|         mulEarlyOut = true, | ||||
|         divEarlyOut = true))), | ||||
|       dcache = Some(DCacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         nMSHRs = 0, | ||||
|         blockBytes = site(CacheBlockBytes))), | ||||
|       icache = Some(ICacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         blockBytes = site(CacheBlockBytes)))) | ||||
|     List.tabulate(n)(i => big.copy(hartId = i)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithNSmallCores(n: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => { | ||||
|     val small = RocketTileParams( | ||||
|       core = RocketCoreParams(useVM = false, fpu = None), | ||||
|       btb = None, | ||||
|       dcache = Some(DCacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         nSets = 64, | ||||
|         nWays = 1, | ||||
|         nTLBEntries = 4, | ||||
|         nMSHRs = 0, | ||||
|         blockBytes = site(CacheBlockBytes))), | ||||
|       icache = Some(ICacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         nSets = 64, | ||||
|         nWays = 1, | ||||
|         nTLBEntries = 4, | ||||
|         blockBytes = site(CacheBlockBytes)))) | ||||
|     List.tabulate(n)(i => small.copy(hartId = i)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class With1TinyCore extends Config((site, here, up) => { | ||||
|   case XLen => 32 | ||||
|   case RocketTilesKey => List(RocketTileParams( | ||||
|       core = RocketCoreParams( | ||||
|         useVM = false, | ||||
|         fpu = None, | ||||
|         mulDiv = Some(MulDivParams(mulUnroll = 8))), | ||||
|       btb = None, | ||||
|       dcache = Some(DCacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         nSets = 256, // 16Kb scratchpad | ||||
|         nWays = 1, | ||||
|         nTLBEntries = 4, | ||||
|         nMSHRs = 0, | ||||
|         blockBytes = site(CacheBlockBytes), | ||||
|         scratch = Some(0x80000000L))), | ||||
|       icache = Some(ICacheParams( | ||||
|         rowBits = site(SystemBusKey).beatBits, | ||||
|         nSets = 64, | ||||
|         nWays = 1, | ||||
|         nTLBEntries = 4, | ||||
|         blockBytes = site(CacheBlockBytes))))) | ||||
|   case RocketCrossingKey => List(RocketCrossingParams( | ||||
|     crossingType = SynchronousCrossing(), | ||||
|     master = TileMasterPortParams(cork = Some(true)) | ||||
|   )) | ||||
| }) | ||||
|  | ||||
| class WithNBanksPerMemChannel(n: Int) extends Config((site, here, up) => { | ||||
|   case BankedL2Key => up(BankedL2Key, site).copy(nBanksPerChannel = n) | ||||
| }) | ||||
|  | ||||
| class WithNTrackersPerBank(n: Int) extends Config((site, here, up) => { | ||||
|   case BroadcastKey => up(BroadcastKey, site).copy(nTrackers = n) | ||||
| }) | ||||
|  | ||||
| // This is the number of icache sets for all Rocket tiles | ||||
| class WithL1ICacheSets(sets: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(icache = r.icache.map(_.copy(nSets = sets))) } | ||||
| }) | ||||
|  | ||||
| // This is the number of icache sets for all Rocket tiles | ||||
| class WithL1DCacheSets(sets: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(dcache = r.dcache.map(_.copy(nSets = sets))) } | ||||
| }) | ||||
|  | ||||
| class WithL1ICacheWays(ways: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(icache = r.icache.map(_.copy(nWays = ways))) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithL1DCacheWays(ways: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(dcache = r.dcache.map(_.copy(nWays = ways))) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithCacheBlockBytes(linesize: Int) extends Config((site, here, up) => { | ||||
|   case CacheBlockBytes => linesize | ||||
| }) | ||||
|  | ||||
| class WithBufferlessBroadcastHub extends Config((site, here, up) => { | ||||
|   case BroadcastKey => up(BroadcastKey, site).copy(bufferless = true) | ||||
| }) | ||||
|  | ||||
| /** | ||||
|  * WARNING!!! IGNORE AT YOUR OWN PERIL!!! | ||||
|  * | ||||
|  * There is a very restrictive set of conditions under which the stateless | ||||
|  * bridge will function properly. There can only be a single tile. This tile | ||||
|  * MUST use the blocking data cache (L1D_MSHRS == 0) and MUST NOT have an | ||||
|  * uncached channel capable of writes (i.e. a RoCC accelerator). | ||||
|  * | ||||
|  * This is because the stateless bridge CANNOT generate probes, so if your | ||||
|  * system depends on coherence between channels in any way, | ||||
|  * DO NOT use this configuration. | ||||
|  */ | ||||
| class WithIncoherentTiles extends Config((site, here, up) => { | ||||
|   case RocketCrossingKey => up(RocketCrossingKey, site) map { r => | ||||
|     r.copy(master = r.master.copy(cork = Some(true))) | ||||
|   } | ||||
|   case BankedL2Key => up(BankedL2Key, site).copy(coherenceManager = { subsystem => | ||||
|     val ww = LazyModule(new TLWidthWidget(subsystem.sbusBeatBytes)(subsystem.p)) | ||||
|     (ww.node, ww.node, () => None) | ||||
|   }) | ||||
| }) | ||||
|  | ||||
| class WithRV32 extends Config((site, here, up) => { | ||||
|   case XLen => 32 | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy( | ||||
|       fpu = r.core.fpu.map(_.copy(fLen = 32)), | ||||
|       mulDiv = Some(MulDivParams(mulUnroll = 8)))) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithNonblockingL1(nMSHRs: Int) extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(dcache = r.dcache.map(_.copy(nMSHRs = nMSHRs))) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithNBreakpoints(hwbp: Int) extends Config ((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy(nBreakpoints = hwbp)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithRoccExample extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(rocc = | ||||
|       Seq( | ||||
|         RoCCParams( | ||||
|           opcodes = OpcodeSet.custom0, | ||||
|           generator = (p: Parameters) => { | ||||
|             val accumulator = LazyModule(new AccumulatorExample()(p)) | ||||
|             accumulator}), | ||||
|         RoCCParams( | ||||
|           opcodes = OpcodeSet.custom1, | ||||
|           generator = (p: Parameters) => { | ||||
|             val translator = LazyModule(new TranslatorExample()(p)) | ||||
|             translator}, | ||||
|           nPTWPorts = 1), | ||||
|         RoCCParams( | ||||
|           opcodes = OpcodeSet.custom2, | ||||
|           generator = (p: Parameters) => { | ||||
|             val counter = LazyModule(new CharacterCountExample()(p)) | ||||
|             counter | ||||
|           }) | ||||
|         )) | ||||
|     } | ||||
| }) | ||||
|  | ||||
| class WithDefaultBtb extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(btb = Some(BTBParams())) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithFastMulDiv extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy(mulDiv = Some( | ||||
|       MulDivParams(mulUnroll = 8, mulEarlyOut = (site(XLen) > 32), divEarlyOut = true) | ||||
|   )))} | ||||
| }) | ||||
|  | ||||
| class WithoutMulDiv extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy(mulDiv = None)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithoutFPU extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy(fpu = None)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithFPUWithoutDivSqrt extends Config((site, here, up) => { | ||||
|   case RocketTilesKey => up(RocketTilesKey, site) map { r => | ||||
|     r.copy(core = r.core.copy(fpu = r.core.fpu.map(_.copy(divSqrt = false)))) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithBootROMFile(bootROMFile: String) extends Config((site, here, up) => { | ||||
|   case BootROMParams => up(BootROMParams, site).copy(contentFileName = bootROMFile) | ||||
| }) | ||||
|  | ||||
| class WithSynchronousRocketTiles extends Config((site, here, up) => { | ||||
|   case RocketCrossingKey => up(RocketCrossingKey, site) map { r => | ||||
|     r.copy(crossingType = SynchronousCrossing()) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithAsynchronousRocketTiles(depth: Int, sync: Int) extends Config((site, here, up) => { | ||||
|   case RocketCrossingKey => up(RocketCrossingKey, site) map { r => | ||||
|     r.copy(crossingType = AsynchronousCrossing(depth, sync)) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithRationalRocketTiles extends Config((site, here, up) => { | ||||
|   case RocketCrossingKey => up(RocketCrossingKey, site) map { r => | ||||
|     r.copy(crossingType = RationalCrossing()) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| class WithEdgeDataBits(dataBits: Int) extends Config((site, here, up) => { | ||||
|   case MemoryBusKey => up(MemoryBusKey, site).copy(beatBytes = dataBits/8) | ||||
|   case ExtIn => up(ExtIn, site).copy(beatBytes = dataBits/8) | ||||
|    | ||||
| }) | ||||
|  | ||||
| class WithJtagDTM extends Config ((site, here, up) => { | ||||
|   case IncludeJtagDTM => true | ||||
| }) | ||||
|  | ||||
| class WithNoPeripheryArithAMO extends Config ((site, here, up) => { | ||||
|   case PeripheryBusKey => up(PeripheryBusKey, site).copy(arithmetic = false) | ||||
| }) | ||||
|  | ||||
| class WithNBitPeripheryBus(nBits: Int) extends Config ((site, here, up) => { | ||||
|   case PeripheryBusKey => up(PeripheryBusKey, site).copy(beatBytes = nBits/8) | ||||
| }) | ||||
|  | ||||
| class WithoutTLMonitors extends Config ((site, here, up) => { | ||||
|   case MonitorsEnabled => false | ||||
| }) | ||||
|  | ||||
| class WithNExtTopInterrupts(nExtInts: Int) extends Config((site, here, up) => { | ||||
|   case NExtTopInterrupts => nExtInts | ||||
| }) | ||||
|  | ||||
| class WithNMemoryChannels(n: Int) extends Config((site, here, up) => { | ||||
|   case BankedL2Key => up(BankedL2Key, site).copy(nMemoryChannels = n) | ||||
| }) | ||||
|  | ||||
| class WithExtMemSize(n: Long) extends Config((site, here, up) => { | ||||
|   case ExtMem => up(ExtMem, site).copy(size = n) | ||||
| }) | ||||
|  | ||||
| class WithDTS(model: String, compat: Seq[String]) extends Config((site, here, up) => { | ||||
|   case DTSModel => model | ||||
|   case DTSCompat => compat | ||||
| }) | ||||
|  | ||||
| class WithTimebase(hertz: BigInt) extends Config((site, here, up) => { | ||||
|   case DTSTimebase => hertz | ||||
| }) | ||||
							
								
								
									
										198
									
								
								src/main/scala/subsystem/CrossingWrapper.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/main/scala/subsystem/CrossingWrapper.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.amba.axi4._ | ||||
| import freechips.rocketchip.interrupts._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| /** Enumerates the three types of clock crossing between tiles and system bus */ | ||||
| sealed trait SubsystemClockCrossing | ||||
| { | ||||
|   def sameClock = this match { | ||||
|     case _: SynchronousCrossing => true | ||||
|     case _ => false | ||||
|   } | ||||
| } | ||||
| case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends SubsystemClockCrossing | ||||
| case class RationalCrossing(direction: RationalDirection = FastToSlow) extends SubsystemClockCrossing | ||||
| case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends SubsystemClockCrossing | ||||
|  | ||||
| private case class CrossingCheck(out: Boolean, source: BaseNode, sink: BaseNode) | ||||
|  | ||||
| trait HasCrossingMethods extends LazyModule with LazyScope | ||||
| { | ||||
|   // Detect incorrect crossing connectivity | ||||
|  | ||||
|   private var checks: List[CrossingCheck] = Nil | ||||
|   private def inside(node: BaseNode) = node.parents.exists(_ eq this) | ||||
|   override def instantiate() { | ||||
|     super.instantiate() | ||||
|     checks.foreach { case CrossingCheck(out, source, sink) => | ||||
|       source.inputs.foreach { case (syncSource, _) => | ||||
|         require (inside(syncSource) == out, s"${syncSource.name} must ${if(out)""else"not "}be inside ${name} (wrong .cross direction?)") | ||||
|       } | ||||
|       sink.outputs.foreach { case (syncSink, _) => | ||||
|         require (inside(syncSink) != out, s"${syncSink.name} must ${if(out)"not "else""}be inside ${name} (wrong .cross direction?)") | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // TileLink | ||||
|  | ||||
|   def crossTLSyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = { | ||||
|     val node = this { LazyModule(new TLBuffer(params)).node } | ||||
|     checks = CrossingCheck(out, node, node) :: checks | ||||
|     node | ||||
|   } | ||||
|  | ||||
|   def crossTLAsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = { | ||||
|     lazy val asource = LazyModule(new TLAsyncCrossingSource(sync)) | ||||
|     lazy val asink = LazyModule(new TLAsyncCrossingSink(depth, sync)) | ||||
|     val source = if (out) this { asource } else asource | ||||
|     val sink = if (out) asink else this { asink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossTLRationalInOut(out: Boolean)(direction: RationalDirection)(implicit p: Parameters): TLNode = { | ||||
|     lazy val rsource = LazyModule(new TLRationalCrossingSource) | ||||
|     lazy val rsink = LazyModule(new TLRationalCrossingSink(if (out) direction else direction.flip)) | ||||
|     val source = if (out) this { rsource } else rsource | ||||
|     val sink = if (out) rsink else this { rsink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossTLSyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(false)(params) | ||||
|   def crossTLSyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): TLNode = crossTLSyncInOut(true )(params) | ||||
|   def crossTLAsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(false)(depth, sync) | ||||
|   def crossTLAsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): TLNode = crossTLAsyncInOut(true )(depth, sync) | ||||
|   def crossTLRationalIn (direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(false)(direction) | ||||
|   def crossTLRationalOut(direction: RationalDirection)(implicit p: Parameters): TLNode = crossTLRationalInOut(true )(direction) | ||||
|  | ||||
|   def crossTLIn(arg: SubsystemClockCrossing)(implicit p: Parameters): TLNode = arg match { | ||||
|     case x: SynchronousCrossing  => crossTLSyncIn(x.params) | ||||
|     case x: AsynchronousCrossing => crossTLAsyncIn(x.depth, x.sync) | ||||
|     case x: RationalCrossing     => crossTLRationalIn(x.direction) | ||||
|   } | ||||
|  | ||||
|   def crossTLOut(arg: SubsystemClockCrossing)(implicit p: Parameters): TLNode = arg match { | ||||
|     case x: SynchronousCrossing  => crossTLSyncOut(x.params) | ||||
|     case x: AsynchronousCrossing => crossTLAsyncOut(x.depth, x.sync) | ||||
|     case x: RationalCrossing     => crossTLRationalOut(x.direction) | ||||
|   } | ||||
|  | ||||
|   // AXI4 | ||||
|  | ||||
|   def crossAXI4SyncInOut(out: Boolean)(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = { | ||||
|     val node = this { LazyModule(new AXI4Buffer(params)).node } | ||||
|     checks = CrossingCheck(out, node, node) :: checks | ||||
|     node | ||||
|   } | ||||
|  | ||||
|   def crossAXI4AsyncInOut(out: Boolean)(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = { | ||||
|     lazy val axi4asource = LazyModule(new AXI4AsyncCrossingSource(sync)) | ||||
|     lazy val axi4asink = LazyModule(new AXI4AsyncCrossingSink(depth, sync)) | ||||
|     val source = if (out) this { axi4asource } else axi4asource | ||||
|     val sink = if (out) axi4asink else this { axi4asink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossAXI4SyncIn (params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(false)(params) | ||||
|   def crossAXI4SyncOut(params: BufferParams = BufferParams.default)(implicit p: Parameters): AXI4Node = crossAXI4SyncInOut(true )(params) | ||||
|   def crossAXI4AsyncIn (depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(false)(depth, sync) | ||||
|   def crossAXI4AsyncOut(depth: Int = 8, sync: Int = 3)(implicit p: Parameters): AXI4Node = crossAXI4AsyncInOut(true )(depth, sync) | ||||
|  | ||||
|   def crossAXI4In(arg: SubsystemClockCrossing)(implicit p: Parameters): AXI4Node = arg match { | ||||
|     case x: SynchronousCrossing  => crossAXI4SyncIn(x.params) | ||||
|     case x: AsynchronousCrossing => crossAXI4AsyncIn(x.depth, x.sync) | ||||
|     case x: RationalCrossing     => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented") | ||||
|   } | ||||
|  | ||||
|   def crossAXI4Out(arg: SubsystemClockCrossing)(implicit p: Parameters): AXI4Node = arg match { | ||||
|     case x: SynchronousCrossing  => crossAXI4SyncOut(x.params) | ||||
|     case x: AsynchronousCrossing => crossAXI4AsyncOut(x.depth, x.sync) | ||||
|     case x: RationalCrossing     => throw new IllegalArgumentException("AXI4 Rational crossing unimplemented") | ||||
|   } | ||||
|  | ||||
|   // Interrupts | ||||
|  | ||||
|   def crossIntSyncInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = { | ||||
|     lazy val intssource = LazyModule(new IntSyncCrossingSource(alreadyRegistered)) | ||||
|     lazy val intssink = LazyModule(new IntSyncCrossingSink(0)) | ||||
|     val source = if (out) this { intssource } else intssource | ||||
|     val sink = if (out) intssink else this { intssink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossIntAsyncInOut(out: Boolean)(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = { | ||||
|     lazy val intasource = LazyModule(new IntSyncCrossingSource(alreadyRegistered)) | ||||
|     lazy val intasink = LazyModule(new IntSyncCrossingSink(sync)) | ||||
|     val source = if (out) this { intasource } else intasource | ||||
|     val sink = if (out) intasink else this { intasink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossIntRationalInOut(out: Boolean)(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = { | ||||
|     lazy val intrsource = LazyModule(new IntSyncCrossingSource(alreadyRegistered)) | ||||
|     lazy val intrsink = LazyModule(new IntSyncCrossingSink(1)) | ||||
|     val source = if (out) this { intrsource } else intrsource | ||||
|     val sink = if (out) intrsink else this { intrsink } | ||||
|     sink.node :*=* source.node | ||||
|     checks = CrossingCheck(out, source.node, sink.node) :: checks | ||||
|     NodeHandle(source.node, sink.node) | ||||
|   } | ||||
|  | ||||
|   def crossIntSyncIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(false)(alreadyRegistered) | ||||
|   def crossIntSyncOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntSyncInOut(true )(alreadyRegistered) | ||||
|   def crossIntAsyncIn (sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(false)(sync, alreadyRegistered) | ||||
|   def crossIntAsyncOut(sync: Int = 3, alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntAsyncInOut(true )(sync, alreadyRegistered) | ||||
|   def crossIntRationalIn (alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(false)(alreadyRegistered) | ||||
|   def crossIntRationalOut(alreadyRegistered: Boolean = false)(implicit p: Parameters): IntNode = crossIntRationalInOut(true )(alreadyRegistered) | ||||
|  | ||||
|   def crossIntIn(arg: SubsystemClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match { | ||||
|     case x: SynchronousCrossing  => crossIntSyncIn(alreadyRegistered) | ||||
|     case x: AsynchronousCrossing => crossIntAsyncIn(x.sync, alreadyRegistered) | ||||
|     case x: RationalCrossing     => crossIntRationalIn(alreadyRegistered) | ||||
|   } | ||||
|  | ||||
|   def crossIntOut(arg: SubsystemClockCrossing, alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = arg match { | ||||
|     case x: SynchronousCrossing  => crossIntSyncOut(alreadyRegistered) | ||||
|     case x: AsynchronousCrossing => crossIntAsyncOut(x.sync, alreadyRegistered) | ||||
|     case x: RationalCrossing     => crossIntRationalOut(alreadyRegistered) | ||||
|   } | ||||
|  | ||||
|   def crossIntIn (arg: SubsystemClockCrossing)(implicit p: Parameters): IntNode = crossIntIn (arg, false) | ||||
|   def crossIntOut(arg: SubsystemClockCrossing)(implicit p: Parameters): IntNode = crossIntOut(arg, false) | ||||
| } | ||||
|  | ||||
| trait HasCrossing extends HasCrossingMethods | ||||
| { | ||||
|   this: LazyModule => | ||||
|   val crossing: SubsystemClockCrossing | ||||
|  | ||||
|   def crossTLIn   (implicit p: Parameters): TLNode  = crossTLIn   (crossing) | ||||
|   def crossTLOut  (implicit p: Parameters): TLNode  = crossTLOut  (crossing) | ||||
|   def crossAXI4In (implicit p: Parameters): AXI4Node= crossAXI4In (crossing) | ||||
|   def crossAXI4Out(implicit p: Parameters): AXI4Node= crossAXI4Out(crossing) | ||||
|   def crossIntIn  (implicit p: Parameters): IntNode = crossIntIn  (crossing) | ||||
|   def crossIntOut (implicit p: Parameters): IntNode = crossIntOut (crossing) | ||||
|  | ||||
|   def crossIntIn (alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntIn (crossing, alreadyRegistered) | ||||
|   def crossIntOut(alreadyRegistered: Boolean)(implicit p: Parameters): IntNode = crossIntOut(crossing, alreadyRegistered) | ||||
| } | ||||
|  | ||||
| class CrossingWrapper(val crossing: SubsystemClockCrossing)(implicit p: Parameters) extends SimpleLazyModule with HasCrossing | ||||
							
								
								
									
										55
									
								
								src/main/scala/subsystem/FrontBus.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/main/scala/subsystem/FrontBus.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| case class FrontBusParams( | ||||
|   beatBytes: Int, | ||||
|   blockBytes: Int, | ||||
|   masterBuffering: BufferParams = BufferParams.default, | ||||
|   slaveBuffering: BufferParams = BufferParams.default | ||||
| ) extends TLBusParams | ||||
|  | ||||
| case object FrontBusKey extends Field[FrontBusParams] | ||||
|  | ||||
| class FrontBus(params: FrontBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "FrontBus") { | ||||
|  | ||||
|   private val master_buffer = LazyModule(new TLBuffer(params.masterBuffering)) | ||||
|   private val master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all)) | ||||
|  | ||||
|   master_buffer.suggestName(s"${busName}_master_TLBuffer") | ||||
|   master_fixer.suggestName(s"${busName}_master_TLFIFOFixer") | ||||
|  | ||||
|   master_fixer.node :=* master_buffer.node | ||||
|   inwardNode :=* master_fixer.node | ||||
|  | ||||
|   def fromSyncPorts(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = { | ||||
|     TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _) | ||||
|   } | ||||
|  | ||||
|   def fromSyncMasters(addBuffers: Int = 0, name: Option[String] = None): TLInwardNode = { | ||||
|     TLBuffer.chain(addBuffers).foldLeft(master_buffer.node:TLInwardNode)(_ :=* _) | ||||
|   } | ||||
|  | ||||
|   def fromCoherentChip: TLInwardNode = inwardNode | ||||
|  | ||||
|   def toSystemBus : TLOutwardNode = TLBuffer(params.slaveBuffering) :=* xbar.node | ||||
|  | ||||
| } | ||||
|  | ||||
| /** Provides buses that serve as attachment points, | ||||
|   * for use in traits that connect individual devices or external ports. | ||||
|   */ | ||||
| trait HasFrontBus extends HasSystemBus { | ||||
|   private val frontbusParams = p(FrontBusKey) | ||||
|   val frontbusBeatBytes = frontbusParams.beatBytes | ||||
|  | ||||
|   val fbus = LazyModule(new FrontBus(frontbusParams)) | ||||
|  | ||||
|   FlipRendering { implicit p => sbus.fromFrontBus :=* fbus.toSystemBus } | ||||
| } | ||||
							
								
								
									
										53
									
								
								src/main/scala/subsystem/HasTiles.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/main/scala/subsystem/HasTiles.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import chisel3.experimental.dontTouch | ||||
| import freechips.rocketchip.config.Parameters | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.interrupts._ | ||||
| import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants} | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| class ClockedTileInputs(implicit val p: Parameters) extends ParameterizedBundle | ||||
|     with HasExternallyDrivenTileConstants | ||||
|     with Clocked | ||||
|  | ||||
| trait HasTiles extends HasSystemBus { | ||||
|   val tiles: Seq[BaseTile] | ||||
|   protected def tileParams: Seq[TileParams] = tiles.map(_.tileParams) | ||||
|   def nTiles: Int = tileParams.size | ||||
|   def hartIdList: Seq[Int] = tileParams.map(_.hartId) | ||||
|   def localIntCounts: Seq[Int] = tileParams.map(_.core.nLocalInterrupts) | ||||
| } | ||||
|  | ||||
| trait HasTilesBundle { | ||||
|   val tile_inputs: Vec[ClockedTileInputs] | ||||
| } | ||||
|  | ||||
| trait HasTilesModuleImp extends LazyModuleImp | ||||
|     with HasTilesBundle | ||||
|     with HasResetVectorWire { | ||||
|   val outer: HasTiles | ||||
|  | ||||
|   def resetVectorBits: Int = { | ||||
|     // Consider using the minimum over all widths, rather than enforcing homogeneity | ||||
|     val vectors = outer.tiles.map(_.module.constants.reset_vector) | ||||
|     require(vectors.tail.forall(_.getWidth == vectors.head.getWidth)) | ||||
|     vectors.head.getWidth | ||||
|   } | ||||
|  | ||||
|   val tile_inputs = dontTouch(Wire(Vec(outer.nTiles, new ClockedTileInputs()(p.alterPartial { | ||||
|     case SharedMemoryTLEdge => outer.sharedMemoryTLEdge | ||||
|   })))) // dontTouch keeps constant prop from sucking these signals into the tile | ||||
|  | ||||
|   // Unconditionally wire up the non-diplomatic tile inputs | ||||
|   outer.tiles.map(_.module).zip(tile_inputs).foreach { case(tile, wire) => | ||||
|     tile.clock := wire.clock | ||||
|     tile.reset := wire.reset | ||||
|     tile.constants.hartid := wire.hartid | ||||
|     tile.constants.reset_vector := wire.reset_vector | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										85
									
								
								src/main/scala/subsystem/InterruptBus.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/main/scala/subsystem/InterruptBus.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.interrupts._ | ||||
|  | ||||
| /** Collects interrupts from internal and external devices and feeds them into the PLIC */  | ||||
| class InterruptBusWrapper(implicit p: Parameters) { | ||||
|  | ||||
|   val int_bus = LazyModule(new IntXbar)    // Interrupt crossbar | ||||
|  | ||||
|   private def synchronize(sync: Int): IntInwardNode = { | ||||
|     val asyncXing = LazyModule(new IntXing(sync)) | ||||
|     int_bus.intnode := asyncXing.intnode | ||||
|     asyncXing.intnode | ||||
|   } | ||||
|  | ||||
|   def fromAsync: IntInwardNode = synchronize(3) | ||||
|   def fromRational: IntInwardNode = synchronize(1) | ||||
|   def fromSync: IntInwardNode = int_bus.intnode | ||||
|   def toPLIC: IntOutwardNode = int_bus.intnode | ||||
| } | ||||
|  | ||||
| trait HasInterruptBus { | ||||
|   implicit val p: Parameters | ||||
|   val ibus = new InterruptBusWrapper | ||||
| } | ||||
|  | ||||
| /** Specifies the number of external interrupts */ | ||||
| case object NExtTopInterrupts extends Field[Int](0) | ||||
|  | ||||
| /** This trait adds externally driven interrupts to the system.  | ||||
|   * However, it should not be used directly; instead one of the below | ||||
|   * synchronization wiring child traits should be used. | ||||
|   */ | ||||
| abstract trait HasExtInterrupts extends HasInterruptBus { | ||||
|   private val device = new Device with DeviceInterrupts { | ||||
|     def describe(resources: ResourceBindings): Description = { | ||||
|       Description("soc/external-interrupts", describeInterrupts(resources)) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   val nExtInterrupts = p(NExtTopInterrupts) | ||||
|   val extInterrupts = IntSourceNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int)) | ||||
| } | ||||
|  | ||||
| /** This trait should be used if the External Interrupts have NOT | ||||
|   * already been synchronized to the Periphery (PLIC) Clock. | ||||
|   */ | ||||
| trait HasAsyncExtInterrupts extends HasExtInterrupts { | ||||
|   if (nExtInterrupts > 0) { | ||||
|     ibus.fromAsync := extInterrupts | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** This trait can be used if the External Interrupts have already been synchronized | ||||
|   * to the Periphery (PLIC) Clock. | ||||
|   */ | ||||
| trait HasSyncExtInterrupts extends HasExtInterrupts { | ||||
|   if (nExtInterrupts > 0) { | ||||
|     ibus.fromSync := extInterrupts | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasExtInterruptsBundle { | ||||
|   val interrupts: UInt | ||||
|  | ||||
|   def tieOffInterrupts(dummy: Int = 1) { | ||||
|     interrupts := UInt(0) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** This trait performs the translation from a UInt IO into Diplomatic Interrupts. | ||||
|   * The wiring must be done in the concrete LazyModuleImp.  | ||||
|   */ | ||||
| trait HasExtInterruptsModuleImp extends LazyModuleImp with HasExtInterruptsBundle { | ||||
|   val outer: HasExtInterrupts | ||||
|   val interrupts = IO(UInt(INPUT, width = outer.nExtInterrupts)) | ||||
|  | ||||
|   outer.extInterrupts.out.map(_._1).flatten.zipWithIndex.foreach { case(o, i) => o := interrupts(i) } | ||||
| } | ||||
							
								
								
									
										79
									
								
								src/main/scala/subsystem/MemoryBus.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/main/scala/subsystem/MemoryBus.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config._ | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| // TODO: applies to all caches, for now | ||||
| case object CacheBlockBytes extends Field[Int](64) | ||||
|  | ||||
| /** L2 Broadcast Hub configuration */ | ||||
| case class BroadcastParams( | ||||
|   nTrackers:  Int     = 4, | ||||
|   bufferless: Boolean = false) | ||||
|  | ||||
| case object BroadcastKey extends Field(BroadcastParams()) | ||||
|  | ||||
| /** L2 memory subsystem configuration */ | ||||
| case class BankedL2Params( | ||||
|   nMemoryChannels:  Int = 1, | ||||
|   nBanksPerChannel: Int = 1, | ||||
|   coherenceManager: HasMemoryBus => (TLInwardNode, TLOutwardNode, () => Option[Bool]) = { subsystem => | ||||
|     implicit val p = subsystem.p | ||||
|     val BroadcastParams(nTrackers, bufferless) = p(BroadcastKey) | ||||
|     val bh = LazyModule(new TLBroadcast(subsystem.memBusBlockBytes, nTrackers, bufferless)) | ||||
|     val ww = LazyModule(new TLWidthWidget(subsystem.sbusBeatBytes)) | ||||
|     ww.node :*= bh.node | ||||
|     (bh.node, ww.node, () => None) | ||||
|   }) { | ||||
|   val nBanks = nMemoryChannels*nBanksPerChannel | ||||
| } | ||||
|  | ||||
| case object BankedL2Key extends Field(BankedL2Params()) | ||||
|  | ||||
| /** Parameterization of the memory-side bus created for each memory channel */ | ||||
| case class MemoryBusParams( | ||||
|   beatBytes: Int, | ||||
|   blockBytes: Int, | ||||
|   masterBuffering: BufferParams = BufferParams.none, | ||||
|   slaveBuffering: BufferParams = BufferParams.none | ||||
| ) extends TLBusParams | ||||
|  | ||||
| case object MemoryBusKey extends Field[MemoryBusParams] | ||||
|  | ||||
| /** Wrapper for creating TL nodes from a bus connected to the back of each mem channel */ | ||||
| class MemoryBus(params: MemoryBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "MemoryBus")(p) { | ||||
|   def fromCoherenceManager: TLInwardNode = inwardBufNode | ||||
|   def toDRAMController: TLOutwardNode = outwardBufNode | ||||
|   def toVariableWidthSlave: TLOutwardNode = outwardFragNode | ||||
| } | ||||
|  | ||||
| trait HasMemoryBus extends HasSystemBus with HasPeripheryBus with HasInterruptBus { | ||||
|   private val mbusParams = p(MemoryBusKey) | ||||
|   private val l2Params = p(BankedL2Key) | ||||
|   val MemoryBusParams(memBusBeatBytes, memBusBlockBytes, _, _) = mbusParams | ||||
|   val BankedL2Params(nMemoryChannels, nBanksPerChannel, coherenceManager) = l2Params | ||||
|   val nBanks = l2Params.nBanks | ||||
|   val cacheBlockBytes = memBusBlockBytes | ||||
|   private val (in, out, halt) = coherenceManager(this) | ||||
|   def memBusCanCauseHalt: () => Option[Bool] = halt | ||||
|  | ||||
|   require (isPow2(nMemoryChannels) || nMemoryChannels == 0) | ||||
|   require (isPow2(nBanksPerChannel)) | ||||
|   require (isPow2(memBusBlockBytes)) | ||||
|  | ||||
|   private val mask = ~BigInt((nBanks-1) * memBusBlockBytes) | ||||
|   val memBuses = Seq.tabulate(nMemoryChannels) { channel => | ||||
|     val mbus = LazyModule(new MemoryBus(mbusParams)) | ||||
|     for (bank <- 0 until nBanksPerChannel) { | ||||
|       val offset = (bank * nMemoryChannels) + channel | ||||
|       ForceFanout(a = true) { implicit p => in := sbus.toMemoryBus } | ||||
|       mbus.fromCoherenceManager := TLFilter(TLFilter.Mmask(AddressSet(offset * memBusBlockBytes, mask))) := out | ||||
|     } | ||||
|     mbus | ||||
|   } | ||||
| } | ||||
							
								
								
									
										61
									
								
								src/main/scala/subsystem/PeripheryBus.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/main/scala/subsystem/PeripheryBus.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
|  | ||||
| import freechips.rocketchip.config.Field | ||||
|  | ||||
| case class PeripheryBusParams( | ||||
|   beatBytes: Int, | ||||
|   blockBytes: Int, | ||||
|   masterBuffering: BufferParams = BufferParams.default, | ||||
|   slaveBuffering: BufferParams = BufferParams.none, | ||||
|   arithmetic: Boolean = true, | ||||
|   frequency: BigInt = BigInt(100000000) // 100 MHz as default bus frequency | ||||
| ) extends TLBusParams { | ||||
| } | ||||
|  | ||||
| case object PeripheryBusKey extends Field[PeripheryBusParams] | ||||
|  | ||||
| class PeripheryBus(params: PeripheryBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "PeripheryBus") { | ||||
|  | ||||
|   def toFixedWidthSingleBeatSlave(widthBytes: Int) = { | ||||
|     TLFragmenter(widthBytes, params.blockBytes) := outwardWWNode | ||||
|   } | ||||
|  | ||||
|   def toLargeBurstSlave(maxXferBytes: Int) = { | ||||
|     TLFragmenter(params.beatBytes, maxXferBytes) := outwardBufNode | ||||
|   } | ||||
|  | ||||
|   val fromSystemBus: TLInwardNode = { | ||||
|     val atomics = LazyModule(new TLAtomicAutomata(arithmetic = params.arithmetic)) | ||||
|     xbar.node :*= TLBuffer(params.masterBuffering) :*= atomics.node | ||||
|   } | ||||
|  | ||||
|   def toTile(name: Option[String] = None)(gen: Parameters => TLInwardNode) { | ||||
|     this { | ||||
|       LazyScope(s"${busName}ToTile${name.getOrElse("")}") { | ||||
|         FlipRendering { implicit p => | ||||
|           gen(p) :*= outwardNode | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Provides buses that serve as attachment points, | ||||
|   * for use in traits that connect individual devices or external ports. | ||||
|   */ | ||||
| trait HasPeripheryBus extends HasSystemBus { | ||||
|   private val pbusParams = p(PeripheryBusKey) | ||||
|   val pbusBeatBytes = pbusParams.beatBytes | ||||
|  | ||||
|   val pbus = LazyModule(new PeripheryBus(pbusParams)) | ||||
|  | ||||
|   // The peripheryBus hangs off of systemBus; here we convert TL-UH -> TL-UL | ||||
|   pbus.fromSystemBus :*= sbus.toPeripheryBus() | ||||
| } | ||||
							
								
								
									
										261
									
								
								src/main/scala/subsystem/Ports.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								src/main/scala/subsystem/Ports.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,261 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.amba.axi4._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| /** Specifies the size and width of external memory ports */ | ||||
| case class MasterPortParams( | ||||
|   base: BigInt, | ||||
|   size: BigInt, | ||||
|   beatBytes: Int, | ||||
|   idBits: Int, | ||||
|   maxXferBytes: Int = 256, | ||||
|   executable: Boolean = true) | ||||
| case object ExtMem extends Field[MasterPortParams] | ||||
| case object ExtBus extends Field[MasterPortParams] | ||||
|  | ||||
| /** Specifies the width of external slave ports */ | ||||
| case class SlavePortParams(beatBytes: Int, idBits: Int, sourceBits: Int) | ||||
| case object ExtIn extends Field[SlavePortParams] | ||||
|  | ||||
| ///// The following traits add ports to the sytem, in some cases converting to different interconnect standards | ||||
|  | ||||
| /** Adds a port to the system intended to master an AXI4 DRAM controller. */ | ||||
| trait HasMasterAXI4MemPort extends HasMemoryBus { | ||||
|   val module: HasMasterAXI4MemPortModuleImp | ||||
|  | ||||
|   private val params = p(ExtMem) | ||||
|   private val device = new MemoryDevice | ||||
|  | ||||
|   val mem_axi4 = AXI4SlaveNode(Seq.tabulate(nMemoryChannels) { channel => | ||||
|     val base = AddressSet(params.base, params.size-1) | ||||
|     val filter = AddressSet(channel * cacheBlockBytes, ~((nMemoryChannels-1) * cacheBlockBytes)) | ||||
|  | ||||
|     AXI4SlavePortParameters( | ||||
|       slaves = Seq(AXI4SlaveParameters( | ||||
|         address       = base.intersect(filter).toList, | ||||
|         resources     = device.reg, | ||||
|         regionType    = RegionType.UNCACHED,   // cacheable | ||||
|         executable    = true, | ||||
|         supportsWrite = TransferSizes(1, cacheBlockBytes), | ||||
|         supportsRead  = TransferSizes(1, cacheBlockBytes), | ||||
|         interleavedId = Some(0))),             // slave does not interleave read responses | ||||
|       beatBytes = params.beatBytes) | ||||
|   }) | ||||
|  | ||||
|   val converter = LazyModule(new TLToAXI4()) | ||||
|   val trim = LazyModule(new AXI4IdIndexer(params.idBits)) | ||||
|   val yank = LazyModule(new AXI4UserYanker) | ||||
|   val buffer = LazyModule(new AXI4Buffer) | ||||
|  | ||||
|   memBuses.map(_.toDRAMController).foreach { case node => | ||||
|     mem_axi4 := buffer.node := yank.node := trim.node := converter.node := node | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasMasterAXI4MemPortBundle { | ||||
|   implicit val p: Parameters | ||||
|   val mem_axi4: HeterogeneousBag[AXI4Bundle] | ||||
|   val nMemoryChannels: Int | ||||
|   def connectSimAXIMem(dummy: Int = 1) = { | ||||
|     if (nMemoryChannels > 0)  { | ||||
|       val mem = LazyModule(new SimAXIMem(nMemoryChannels)) | ||||
|       Module(mem.module).io.axi4 <> mem_axi4 | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Actually generates the corresponding IO in the concrete Module */ | ||||
| trait HasMasterAXI4MemPortModuleImp extends LazyModuleImp with HasMasterAXI4MemPortBundle { | ||||
|   val outer: HasMasterAXI4MemPort | ||||
|   val mem_axi4 = IO(HeterogeneousBag.fromNode(outer.mem_axi4.in)) | ||||
|   (mem_axi4 zip outer.mem_axi4.in) foreach { case (i, (o, _)) => i <> o } | ||||
|   val nMemoryChannels = outer.nMemoryChannels | ||||
| } | ||||
|  | ||||
| /** Adds a AXI4 port to the system intended to master an MMIO device bus */ | ||||
| trait HasMasterAXI4MMIOPort extends HasSystemBus { | ||||
|   private val params = p(ExtBus) | ||||
|   private val device = new SimpleBus("mmio", Nil) | ||||
|   val mmio_axi4 = AXI4SlaveNode(Seq(AXI4SlavePortParameters( | ||||
|     slaves = Seq(AXI4SlaveParameters( | ||||
|       address       = AddressSet.misaligned(params.base, params.size), | ||||
|       resources     = device.ranges, | ||||
|       executable    = params.executable, | ||||
|       supportsWrite = TransferSizes(1, params.maxXferBytes), | ||||
|       supportsRead  = TransferSizes(1, params.maxXferBytes))), | ||||
|     beatBytes = params.beatBytes))) | ||||
|  | ||||
|   (mmio_axi4 | ||||
|     := AXI4Buffer() | ||||
|     := AXI4UserYanker() | ||||
|     := AXI4Deinterleaver(sbus.blockBytes) | ||||
|     := AXI4IdIndexer(params.idBits) | ||||
|     := TLToAXI4() | ||||
|     := sbus.toFixedWidthPorts) | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasMasterAXI4MMIOPortBundle { | ||||
|   implicit val p: Parameters | ||||
|   val mmio_axi4: HeterogeneousBag[AXI4Bundle] | ||||
|   def connectSimAXIMMIO(dummy: Int = 1) { | ||||
|     val mmio_mem = LazyModule(new SimAXIMem(1, 4096)) | ||||
|     Module(mmio_mem.module).io.axi4 <> mmio_axi4 | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Actually generates the corresponding IO in the concrete Module */ | ||||
| trait HasMasterAXI4MMIOPortModuleImp extends LazyModuleImp with HasMasterAXI4MMIOPortBundle { | ||||
|   val outer: HasMasterAXI4MMIOPort | ||||
|   val mmio_axi4 = IO(HeterogeneousBag.fromNode(outer.mmio_axi4.in)) | ||||
|   (mmio_axi4 zip outer.mmio_axi4.in) foreach { case (i, (o, _)) => i <> o } | ||||
| } | ||||
|  | ||||
| /** Adds an AXI4 port to the system intended to be a slave on an MMIO device bus */ | ||||
| trait HasSlaveAXI4Port extends HasSystemBus { | ||||
|   private val params = p(ExtIn) | ||||
|   val l2FrontendAXI4Node = AXI4MasterNode(Seq(AXI4MasterPortParameters( | ||||
|     masters = Seq(AXI4MasterParameters( | ||||
|       name = "AXI4 periphery", | ||||
|       id   = IdRange(0, 1 << params.idBits)))))) | ||||
|  | ||||
|   private val fifoBits = 1 | ||||
|   (sbus.fromSyncPorts() | ||||
|     := TLWidthWidget(params.beatBytes) | ||||
|     := AXI4ToTL() | ||||
|     := AXI4UserYanker(Some(1 << (params.sourceBits - fifoBits - 1))) | ||||
|     := AXI4Fragmenter() | ||||
|     := AXI4IdIndexer(fifoBits) | ||||
|     := l2FrontendAXI4Node) | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasSlaveAXI4PortBundle { | ||||
|   implicit val p: Parameters | ||||
|   val l2_frontend_bus_axi4: HeterogeneousBag[AXI4Bundle] | ||||
|   def tieOffAXI4SlavePort(dummy: Int = 1) { | ||||
|     l2_frontend_bus_axi4.foreach { l2_axi4 => | ||||
|       l2_axi4.ar.valid := Bool(false) | ||||
|       l2_axi4.aw.valid := Bool(false) | ||||
|       l2_axi4.w .valid := Bool(false) | ||||
|       l2_axi4.r .ready := Bool(true) | ||||
|       l2_axi4.b .ready := Bool(true) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Actually generates the corresponding IO in the concrete Module */ | ||||
| trait HasSlaveAXI4PortModuleImp extends LazyModuleImp with HasSlaveAXI4PortBundle { | ||||
|   val outer: HasSlaveAXI4Port | ||||
|   val l2_frontend_bus_axi4 = IO(HeterogeneousBag.fromNode(outer.l2FrontendAXI4Node.out).flip) | ||||
|   (outer.l2FrontendAXI4Node.out zip l2_frontend_bus_axi4) foreach { case ((i, _), o) => i <> o } | ||||
| } | ||||
|  | ||||
| /** Adds a TileLink port to the system intended to master an MMIO device bus */ | ||||
| trait HasMasterTLMMIOPort extends HasSystemBus { | ||||
|   private val params = p(ExtBus) | ||||
|   private val device = new SimpleBus("mmio", Nil) | ||||
|   val mmio_tl = TLManagerNode(Seq(TLManagerPortParameters( | ||||
|     managers = Seq(TLManagerParameters( | ||||
|       address            = AddressSet.misaligned(params.base, params.size), | ||||
|       resources          = device.ranges, | ||||
|       executable         = params.executable, | ||||
|       supportsGet        = TransferSizes(1, sbus.blockBytes), | ||||
|       supportsPutFull    = TransferSizes(1, sbus.blockBytes), | ||||
|       supportsPutPartial = TransferSizes(1, sbus.blockBytes))), | ||||
|     beatBytes = params.beatBytes))) | ||||
|  | ||||
|   mmio_tl := TLBuffer() := TLSourceShrinker(1 << params.idBits) := sbus.toFixedWidthPorts | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasMasterTLMMIOPortBundle { | ||||
|   implicit val p: Parameters | ||||
|   val mmio_tl: HeterogeneousBag[TLBundle] | ||||
|   def tieOffTLMMIO(dummy: Int = 1) { | ||||
|     mmio_tl.foreach { tl => | ||||
|       tl.a.ready := Bool(true) | ||||
|       tl.b.valid := Bool(false) | ||||
|       tl.c.ready := Bool(true) | ||||
|       tl.d.valid := Bool(false) | ||||
|       tl.e.ready := Bool(true) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Actually generates the corresponding IO in the concrete Module */ | ||||
| trait HasMasterTLMMIOPortModuleImp extends LazyModuleImp with HasMasterTLMMIOPortBundle { | ||||
|   val outer: HasMasterTLMMIOPort | ||||
|   val mmio_tl = IO(HeterogeneousBag.fromNode(outer.mmio_tl.in)) | ||||
|   (mmio_tl zip outer.mmio_tl.in) foreach { case (i, (o, _)) => i <> o } | ||||
| } | ||||
|  | ||||
| /** Adds an TL port to the system intended to be a slave on an MMIO device bus. | ||||
|   * NOTE: this port is NOT allowed to issue Acquires. | ||||
|   */ | ||||
| trait HasSlaveTLPort extends HasSystemBus { | ||||
|   private val params = p(ExtIn) | ||||
|   val l2FrontendTLNode = TLClientNode(Seq(TLClientPortParameters( | ||||
|     clients = Seq(TLClientParameters( | ||||
|       name     = "Front Port (TL)", | ||||
|       sourceId = IdRange(0, 1 << params.idBits)))))) | ||||
|  | ||||
|   sbus.fromSyncPorts() := TLSourceShrinker(1 << params.sourceBits) := TLWidthWidget(params.beatBytes) := l2FrontendTLNode | ||||
| } | ||||
|  | ||||
| /** Common io name and methods for propagating or tying off the port bundle */ | ||||
| trait HasSlaveTLPortBundle { | ||||
|   implicit val p: Parameters | ||||
|   val l2_frontend_bus_tl: HeterogeneousBag[TLBundle] | ||||
|   def tieOffSlaveTLPort(dummy: Int = 1) { | ||||
|     l2_frontend_bus_tl.foreach { tl => | ||||
|       tl.a.valid := Bool(false) | ||||
|       tl.b.ready := Bool(true) | ||||
|       tl.c.valid := Bool(false) | ||||
|       tl.d.ready := Bool(true) | ||||
|       tl.e.valid := Bool(false) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Actually generates the corresponding IO in the concrete Module */ | ||||
| trait HasSlaveTLPortModuleImp extends LazyModuleImp with HasSlaveTLPortBundle { | ||||
|   val outer: HasSlaveTLPort | ||||
|   val l2_frontend_bus_tl = IO(HeterogeneousBag.fromNode(outer.l2FrontendTLNode.out).flip) | ||||
|   (outer.l2FrontendTLNode.in zip l2_frontend_bus_tl) foreach { case ((i, _), o) => i <> o } | ||||
| } | ||||
|  | ||||
| /** Memory with AXI port for use in elaboratable test harnesses. */ | ||||
| class SimAXIMem(channels: Int, forceSize: BigInt = 0)(implicit p: Parameters) extends LazyModule { | ||||
|   val config = p(ExtMem) | ||||
|   val totalSize = if (forceSize > 0) forceSize else config.size | ||||
|   val size = totalSize / channels | ||||
|   require(totalSize % channels == 0) | ||||
|  | ||||
|   val node = AXI4MasterNode(Seq.fill(channels) { | ||||
|     AXI4MasterPortParameters(Seq(AXI4MasterParameters( | ||||
|       name = "dut", | ||||
|       id   = IdRange(0, 1 << config.idBits) | ||||
|     ))) | ||||
|   }) | ||||
|  | ||||
|   for (i <- 0 until channels) { | ||||
|     val sram = LazyModule(new AXI4RAM(AddressSet(0, size-1), beatBytes = config.beatBytes)) | ||||
|     sram.node := AXI4Buffer() := AXI4Fragmenter() := node | ||||
|   } | ||||
|  | ||||
|   lazy val module = new LazyModuleImp(this) { | ||||
|     val io = IO(new Bundle { | ||||
|       val axi4 = HeterogeneousBag.fromNode(node.out).flip | ||||
|     }) | ||||
|     (node.out zip io.axi4) foreach { case ((i, _), o) => i <> o } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										24
									
								
								src/main/scala/subsystem/RTC.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/main/scala/subsystem/RTC.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.diplomacy.{LazyModuleImp, DTSTimebase} | ||||
| import freechips.rocketchip.devices.tilelink.HasPeripheryCLINT | ||||
|  | ||||
| trait HasRTCModuleImp extends LazyModuleImp { | ||||
|   val outer: HasPeripheryCLINT | ||||
|   private val pbusFreq = outer.p(PeripheryBusKey).frequency | ||||
|   private val rtcFreq = outer.p(DTSTimebase) | ||||
|   private val internalPeriod: BigInt = pbusFreq / rtcFreq | ||||
|  | ||||
|   // check whether pbusFreq >= rtcFreq | ||||
|   require(internalPeriod > 0) | ||||
|   // check wehther the integer division is within 5% of the real division | ||||
|   require((pbusFreq - rtcFreq * internalPeriod) * 100 / pbusFreq <= 5) | ||||
|  | ||||
|   // Use the static period to toggle the RTC | ||||
|   val (_, int_rtc_tick) = Counter(true.B, internalPeriod.toInt) | ||||
|  | ||||
|   outer.clint.module.io.rtcTick := int_rtc_tick | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/main/scala/subsystem/ResetVector.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/main/scala/subsystem/ResetVector.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
|  | ||||
| /** A single place for all tiles to find out the reset vector */ | ||||
| trait HasResetVectorWire { | ||||
|   def resetVectorBits: Int | ||||
|   val global_reset_vector = Wire(UInt(width = resetVectorBits)) | ||||
| } | ||||
							
								
								
									
										180
									
								
								src/main/scala/subsystem/RocketSubsystem.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								src/main/scala/subsystem/RocketSubsystem.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,180 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import chisel3.internal.sourceinfo.SourceInfo | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.devices.tilelink._ | ||||
| import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tile._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.interrupts._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| // TODO: how specific are these to RocketTiles? | ||||
| case class TileMasterPortParams( | ||||
|     addBuffers: Int = 0, | ||||
|     cork: Option[Boolean] = None) { | ||||
|  | ||||
|   def adapt(subsystem: HasPeripheryBus) | ||||
|            (masterNode: TLOutwardNode) | ||||
|            (implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { | ||||
|     val tile_master_cork = cork.map(u => (LazyModule(new TLCacheCork(unsafe = u)))) | ||||
|     val tile_master_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable)) | ||||
|  | ||||
|     (Seq(tile_master_fixer.node) ++ TLBuffer.chain(addBuffers) ++ tile_master_cork.map(_.node)) | ||||
|       .foldRight(masterNode)(_ :=* _) | ||||
|   } | ||||
| } | ||||
|  | ||||
| case class TileSlavePortParams( | ||||
|     addBuffers: Int = 0, | ||||
|     blockerCtrlAddr: Option[BigInt] = None) { | ||||
|  | ||||
|   def adapt(subsystem: HasPeripheryBus) | ||||
|            (slaveNode: TLInwardNode) | ||||
|            (implicit p: Parameters, sourceInfo: SourceInfo): TLInwardNode = { | ||||
|     val tile_slave_blocker = | ||||
|       blockerCtrlAddr | ||||
|         .map(BasicBusBlockerParams(_, subsystem.pbus.beatBytes, subsystem.sbus.beatBytes)) | ||||
|         .map(bp => LazyModule(new BasicBusBlocker(bp))) | ||||
|  | ||||
|     tile_slave_blocker.foreach { _.controlNode := subsystem.pbus.toVariableWidthSlaves } | ||||
|     (Seq() ++ tile_slave_blocker.map(_.node) ++ TLBuffer.chain(addBuffers)) | ||||
|     .foldLeft(slaveNode)(_ :*= _) | ||||
|   } | ||||
| } | ||||
|  | ||||
| case class RocketCrossingParams( | ||||
|     crossingType: SubsystemClockCrossing = SynchronousCrossing(), | ||||
|     master: TileMasterPortParams = TileMasterPortParams(), | ||||
|     slave: TileSlavePortParams = TileSlavePortParams()) { | ||||
|   def knownRatio: Option[Int] = crossingType match { | ||||
|     case RationalCrossing(_) => Some(2) | ||||
|     case _ => None | ||||
|   } | ||||
| } | ||||
|  | ||||
| case object RocketTilesKey extends Field[Seq[RocketTileParams]](Nil) | ||||
| case object RocketCrossingKey extends Field[Seq[RocketCrossingParams]](List(RocketCrossingParams())) | ||||
|  | ||||
| trait HasRocketTiles extends HasTiles | ||||
|     with HasPeripheryBus | ||||
|     with HasPeripheryPLIC | ||||
|     with HasPeripheryCLINT | ||||
|     with HasPeripheryDebug { | ||||
|   val module: HasRocketTilesModuleImp | ||||
|  | ||||
|   protected val rocketTileParams = p(RocketTilesKey) | ||||
|   private val NumRocketTiles = rocketTileParams.size | ||||
|   private val crossingParams = p(RocketCrossingKey) | ||||
|   private val crossings = crossingParams.size match { | ||||
|     case 1 => List.fill(NumRocketTiles) { crossingParams.head } | ||||
|     case NumRocketTiles => crossingParams | ||||
|     case _ => throw new Exception("RocketCrossingKey.size must == 1 or == RocketTilesKey.size") | ||||
|   } | ||||
|   private val crossingTuples = rocketTileParams.zip(crossings) | ||||
|  | ||||
|   // Make a tile and wire its nodes into the system, | ||||
|   // according to the specified type of clock crossing. | ||||
|   // Note that we also inject new nodes into the tile itself, | ||||
|   // also based on the crossing type. | ||||
|   val rocketTiles = crossingTuples.map { case (tp, crossing) => | ||||
|     // For legacy reasons, it is convenient to store some state | ||||
|     // in the global Parameters about the specific tile being built now | ||||
|     val rocket = LazyModule(new RocketTile(tp, crossing.crossingType)(p.alterPartial { | ||||
|         case TileKey => tp | ||||
|         case BuildRoCC => tp.rocc | ||||
|         case SharedMemoryTLEdge => sharedMemoryTLEdge | ||||
|       }) | ||||
|     ).suggestName(tp.name) | ||||
|  | ||||
|     // Connect the master ports of the tile to the system bus | ||||
|  | ||||
|     def tileMasterBuffering: TLOutwardNode = rocket { | ||||
|       // The buffers needed to cut feed-through paths are microarchitecture specific, so belong here | ||||
|       val masterBuffer = LazyModule(new TLBuffer(BufferParams.none, BufferParams.flow, BufferParams.none, BufferParams.flow, BufferParams(1))) | ||||
|       crossing.crossingType match { | ||||
|         case _: AsynchronousCrossing => rocket.masterNode | ||||
|         case SynchronousCrossing(b) => | ||||
|           require (!tp.boundaryBuffers || (b.depth >= 1 && !b.flow && !b.pipe), "Buffer misconfiguration creates feed-through paths") | ||||
|           rocket.masterNode | ||||
|         case RationalCrossing(dir) => | ||||
|           require (dir != SlowToFast, "Misconfiguration? Core slower than fabric") | ||||
|           if (tp.boundaryBuffers) { | ||||
|             masterBuffer.node :=* rocket.masterNode | ||||
|           } else { | ||||
|             rocket.masterNode | ||||
|           } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     sbus.fromTile(tp.name) { implicit p => crossing.master.adapt(this)(rocket.crossTLOut :=* tileMasterBuffering) } | ||||
|  | ||||
|     // Connect the slave ports of the tile to the periphery bus | ||||
|  | ||||
|     def tileSlaveBuffering: TLInwardNode = rocket { | ||||
|       val slaveBuffer  = LazyModule(new TLBuffer(BufferParams.flow, BufferParams.none, BufferParams.none, BufferParams.none, BufferParams.none)) | ||||
|       crossing.crossingType match { | ||||
|         case RationalCrossing(_) if (tp.boundaryBuffers) => rocket.slaveNode :*= slaveBuffer.node | ||||
|         case _ => rocket.slaveNode | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     pbus.toTile(tp.name) { implicit p => crossing.slave.adapt(this)( DisableMonitors { implicit p => | ||||
|       tileSlaveBuffering :*= rocket.crossTLIn | ||||
|     })} | ||||
|  | ||||
|     // Handle all the different types of interrupts crossing to or from the tile: | ||||
|     // 1. Debug interrupt is definitely asynchronous in all cases. | ||||
|     // 2. The CLINT and PLIC output interrupts are synchronous to the periphery clock, | ||||
|     //    so might need to be synchronized depending on the Tile's crossing type. | ||||
|     // 3. Local Interrupts are required to already be synchronous to the tile clock. | ||||
|     // 4. Interrupts coming out of the tile are sent to the PLIC, | ||||
|     //    so might need to be synchronized depending on the Tile's crossing type. | ||||
|     // NOTE: The order of calls to := matters! They must match how interrupts | ||||
|     //       are decoded from rocket.intNode inside the tile. | ||||
|  | ||||
|     // 1. always async crossing for debug | ||||
|     rocket.intInwardNode := rocket { IntSyncCrossingSink(3) } := debug.intnode | ||||
|  | ||||
|     // 2. clint+plic conditionally crossing | ||||
|     val periphIntNode = rocket.intInwardNode :=* rocket.crossIntIn | ||||
|     periphIntNode := clint.intnode                   // msip+mtip | ||||
|     periphIntNode := plic.intnode                    // meip | ||||
|     if (tp.core.useVM) periphIntNode := plic.intnode // seip | ||||
|  | ||||
|     // 3. local interrupts  never cross  | ||||
|     // rocket.intInwardNode is wired up externally     // lip | ||||
|  | ||||
|     // 4. conditional crossing from core to PLIC | ||||
|     FlipRendering { implicit p => | ||||
|       plic.intnode :=* rocket.crossIntOut :=* rocket.intOutwardNode | ||||
|     } | ||||
|  | ||||
|     rocket | ||||
|   } | ||||
| } | ||||
|  | ||||
| trait HasRocketTilesModuleImp extends HasTilesModuleImp | ||||
|     with HasPeripheryDebugModuleImp { | ||||
|   val outer: HasRocketTiles | ||||
| } | ||||
|  | ||||
| class RocketSubsystem(implicit p: Parameters) extends BaseSubsystem | ||||
|     with HasRocketTiles { | ||||
|   val tiles = rocketTiles | ||||
|   override lazy val module = new RocketSubsystemModule(this) | ||||
| } | ||||
|  | ||||
| class RocketSubsystemModule[+L <: RocketSubsystem](_outer: L) extends BaseSubsystemModule(_outer) | ||||
|     with HasRocketTilesModuleImp { | ||||
|   tile_inputs.zip(outer.hartIdList).foreach { case(wire, i) => | ||||
|     wire.clock := clock | ||||
|     wire.reset := reset | ||||
|     wire.hartid := UInt(i) | ||||
|     wire.reset_vector := global_reset_vector | ||||
|   } | ||||
| } | ||||
							
								
								
									
										83
									
								
								src/main/scala/subsystem/SystemBus.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/main/scala/subsystem/SystemBus.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package freechips.rocketchip.subsystem | ||||
|  | ||||
| import Chisel._ | ||||
| import freechips.rocketchip.config.{Field, Parameters} | ||||
| import freechips.rocketchip.diplomacy._ | ||||
| import freechips.rocketchip.tilelink._ | ||||
| import freechips.rocketchip.util._ | ||||
|  | ||||
| case class SystemBusParams( | ||||
|   beatBytes: Int, | ||||
|   blockBytes: Int, | ||||
|   masterBuffering: BufferParams = BufferParams.default, | ||||
|   slaveBuffering: BufferParams = BufferParams.default | ||||
| ) extends TLBusParams | ||||
|  | ||||
| case object SystemBusKey extends Field[SystemBusParams] | ||||
|  | ||||
| class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "SystemBus") { | ||||
|  | ||||
|   private val master_splitter = LazyModule(new TLSplitter)  // Allows cycle-free connection to external networks | ||||
|   master_splitter.suggestName(s"${busName}_master_TLSplitter") | ||||
|   inwardNode :=* master_splitter.node | ||||
|   def busView = master_splitter.node.edges.in.head | ||||
|  | ||||
|   protected def inwardSplitNode: TLInwardNode = master_splitter.node | ||||
|   protected def outwardSplitNode: TLOutwardNode = master_splitter.node | ||||
|  | ||||
|  | ||||
|   private val port_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all)) | ||||
|   port_fixer.suggestName(s"${busName}_port_TLFIFOFixer") | ||||
|   master_splitter.node :=* port_fixer.node | ||||
|  | ||||
|   private val pbus_fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.all)) | ||||
|   pbus_fixer.suggestName(s"${busName}_pbus_TLFIFOFixer") | ||||
|   pbus_fixer.node :*= outwardWWNode | ||||
|  | ||||
|   def toSplitSlaves: TLOutwardNode = outwardSplitNode | ||||
|  | ||||
|   def toPeripheryBus(addBuffers: Int = 0): TLOutwardNode = { | ||||
|     TLBuffer.chain(addBuffers).foldRight(pbus_fixer.node:TLOutwardNode)(_ :*= _) | ||||
|   } | ||||
|  | ||||
|   val toMemoryBus: TLOutwardNode = outwardNode | ||||
|  | ||||
|   val toSlave: TLOutwardNode = outwardBufNode | ||||
|  | ||||
|   def fromCoherentChip: TLInwardNode = inwardNode | ||||
|  | ||||
|   def fromFrontBus: TLInwardNode = master_splitter.node | ||||
|  | ||||
|   def fromTile(name: Option[String])(gen: Parameters => TLOutwardNode) { | ||||
|     this { | ||||
|       LazyScope(s"${busName}FromTile${name.getOrElse("")}") { | ||||
|         master_splitter.node :=* gen(p) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def fromSyncPorts(params: BufferParams =  BufferParams.default, name: Option[String] = None): TLInwardNode = { | ||||
|     val buffer = LazyModule(new TLBuffer(params)) | ||||
|     name.foreach { n => buffer.suggestName(s"${busName}_${n}_TLBuffer") } | ||||
|     port_fixer.node :=* buffer.node | ||||
|     buffer.node | ||||
|   } | ||||
|  | ||||
|   def fromSyncFIFOMaster(params: BufferParams =  BufferParams.default, name: Option[String] = None): TLInwardNode = { | ||||
|     fromSyncPorts(params, name) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** Provides buses that serve as attachment points, | ||||
|   * for use in traits that connect individual devices or external ports. | ||||
|   */ | ||||
| trait HasSystemBus extends HasInterruptBus { | ||||
|   private val sbusParams = p(SystemBusKey) | ||||
|   val sbusBeatBytes = sbusParams.beatBytes | ||||
|  | ||||
|   val sbus = LazyModule(new SystemBus(sbusParams)) | ||||
|  | ||||
|   def sharedMemoryTLEdge: TLEdge = sbus.busView | ||||
| } | ||||
		Reference in New Issue
	
	Block a user