2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
|
|
|
|
2017-07-07 19:48:16 +02:00
|
|
|
package freechips.rocketchip.coreplex
|
2016-09-22 01:54:35 +02:00
|
|
|
|
|
|
|
import Chisel._
|
2017-07-23 17:31:04 +02:00
|
|
|
import freechips.rocketchip.config.Parameters
|
2017-07-07 19:48:16 +02:00
|
|
|
import freechips.rocketchip.diplomacy._
|
|
|
|
import freechips.rocketchip.tilelink._
|
2017-10-06 09:56:23 +02:00
|
|
|
import freechips.rocketchip.devices.tilelink._
|
2017-10-08 02:29:50 +02:00
|
|
|
import freechips.rocketchip.tile.{BaseTile, TileParams, SharedMemoryTLEdge, HasExternallyDrivenTileConstants}
|
2017-10-06 09:56:23 +02:00
|
|
|
import freechips.rocketchip.devices.debug.{HasPeripheryDebug, HasPeripheryDebugModuleImp}
|
2017-07-07 19:48:16 +02:00
|
|
|
import freechips.rocketchip.util._
|
2016-09-22 01:54:35 +02:00
|
|
|
|
2017-07-23 17:31:04 +02:00
|
|
|
/** Enumerates the three types of clock crossing between tiles and system bus */
|
|
|
|
sealed trait CoreplexClockCrossing
|
|
|
|
case class SynchronousCrossing(params: BufferParams = BufferParams.default) extends CoreplexClockCrossing
|
|
|
|
case class RationalCrossing(direction: RationalDirection = FastToSlow) extends CoreplexClockCrossing
|
2017-07-28 00:44:51 +02:00
|
|
|
case class AsynchronousCrossing(depth: Int, sync: Int = 3) extends CoreplexClockCrossing
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
/** BareCoreplex is the root class for creating a coreplex sub-system */
|
|
|
|
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope {
|
|
|
|
lazy val dts = DTS(bindingTree)
|
|
|
|
lazy val dtb = DTB(dts)
|
|
|
|
lazy val json = JSON(bindingTree)
|
2016-09-22 01:54:35 +02:00
|
|
|
}
|
|
|
|
|
2017-09-14 03:06:03 +02:00
|
|
|
abstract class BareCoreplexModule[+L <: BareCoreplex](_outer: L) extends LazyModuleImp(_outer) {
|
2016-10-29 12:30:49 +02:00
|
|
|
val outer = _outer
|
2017-07-23 17:31:04 +02:00
|
|
|
ElaborationArtefacts.add("graphml", outer.graphML)
|
|
|
|
ElaborationArtefacts.add("dts", outer.dts)
|
|
|
|
ElaborationArtefacts.add("json", outer.json)
|
|
|
|
println(outer.dts)
|
2016-10-29 03:37:24 +02:00
|
|
|
}
|
|
|
|
|
2017-10-06 09:56:23 +02:00
|
|
|
trait HasTiles extends HasSystemBus {
|
|
|
|
protected def tileParams: Seq[TileParams]
|
|
|
|
def nRocketTiles = tileParams.size
|
|
|
|
def hartIdList = tileParams.map(_.hartid)
|
|
|
|
|
|
|
|
// Handle interrupts to be routed directly into each tile
|
|
|
|
// TODO: figure out how to merge the localIntNodes and coreIntXbar
|
|
|
|
def localIntCounts = tileParams.map(_.core.nLocalInterrupts)
|
2017-10-11 22:14:25 +02:00
|
|
|
lazy val localIntNodes = tileParams.zipWithIndex map { case (t, i) => {
|
|
|
|
(t.core.nLocalInterrupts > 0).option({
|
|
|
|
val n = LazyModule(new IntXbar)
|
|
|
|
n.suggestName(s"localIntXbar_${i}")
|
|
|
|
n.intnode})
|
|
|
|
}
|
2017-10-06 09:56:23 +02:00
|
|
|
}
|
|
|
|
|
2017-10-08 02:29:50 +02:00
|
|
|
val tiles: Seq[BaseTile]
|
2017-10-06 09:56:23 +02:00
|
|
|
}
|
|
|
|
|
2017-07-23 17:31:04 +02:00
|
|
|
/** Base Coreplex class with no peripheral devices or ports added */
|
2016-11-04 05:31:26 +01:00
|
|
|
abstract class BaseCoreplex(implicit p: Parameters) extends BareCoreplex
|
2017-07-23 17:31:04 +02:00
|
|
|
with HasInterruptBus
|
|
|
|
with HasSystemBus
|
|
|
|
with HasPeripheryBus
|
|
|
|
with HasMemoryBus {
|
|
|
|
override val module: BaseCoreplexModule[BaseCoreplex]
|
|
|
|
|
|
|
|
val root = new Device {
|
|
|
|
def describe(resources: ResourceBindings): Description = {
|
|
|
|
val width = resources("width").map(_.value)
|
|
|
|
Description("/", Map(
|
|
|
|
"#address-cells" -> width,
|
|
|
|
"#size-cells" -> width,
|
|
|
|
"model" -> Seq(ResourceString(p(DTSModel))),
|
|
|
|
"compatible" -> (p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-dev"))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
val soc = new Device {
|
|
|
|
def describe(resources: ResourceBindings): Description = {
|
|
|
|
val width = resources("width").map(_.value)
|
|
|
|
Description("soc", Map(
|
|
|
|
"#address-cells" -> width,
|
|
|
|
"#size-cells" -> width,
|
|
|
|
"compatible" -> ((p(DTSModel) +: p(DTSCompat)).map(s => ResourceString(s + "-soc")) :+ ResourceString("simple-bus")),
|
|
|
|
"ranges" -> Nil))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
val cpus = new Device {
|
|
|
|
def describe(resources: ResourceBindings): Description = {
|
|
|
|
Description("cpus", Map(
|
|
|
|
"#address-cells" -> Seq(ResourceInt(1)),
|
|
|
|
"#size-cells" -> Seq(ResourceInt(0)),
|
|
|
|
"timebase-frequency" -> Seq(ResourceInt(p(DTSTimebase)))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
Resource(root, "width").bind(width)
|
|
|
|
Resource(soc, "width").bind(width)
|
|
|
|
Resource(cpus, "null").bind(ResourceString(""))
|
|
|
|
|
|
|
|
managers.foreach { case manager =>
|
|
|
|
val value = manager.toResource
|
|
|
|
manager.resources.foreach { case resource =>
|
|
|
|
resource.bind(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-27 07:28:40 +02:00
|
|
|
}
|
|
|
|
|
2017-10-08 02:29:50 +02:00
|
|
|
class ClockedTileInputs(implicit val p: Parameters) extends ParameterizedBundle
|
|
|
|
with HasExternallyDrivenTileConstants
|
|
|
|
with Clocked
|
|
|
|
|
|
|
|
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.io.reset_vector)
|
|
|
|
require(vectors.tail.forall(_.getWidth == vectors.head.getWidth))
|
|
|
|
vectors.head.getWidth
|
|
|
|
}
|
|
|
|
val tile_inputs = Wire(Vec(outer.nRocketTiles, new ClockedTileInputs()(p.alterPartial {
|
|
|
|
case SharedMemoryTLEdge => outer.sharedMemoryTLEdge
|
|
|
|
})))
|
|
|
|
|
|
|
|
// 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.io.hartid := wire.hartid
|
|
|
|
tile.io.reset_vector := wire.reset_vector
|
|
|
|
}
|
|
|
|
|
|
|
|
// Default values for tile inputs; may be overriden in other traits
|
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-23 17:31:04 +02:00
|
|
|
abstract class BaseCoreplexModule[+L <: BaseCoreplex](_outer: L) extends BareCoreplexModule(_outer) {
|
|
|
|
println("Generated Address Map")
|
|
|
|
private val aw = (outer.sharedMemoryTLEdge.bundle.addressBits-1)/4 + 1
|
2017-10-19 01:44:53 +02:00
|
|
|
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s"
|
2017-07-23 17:31:04 +02:00
|
|
|
|
|
|
|
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)
|
2017-10-19 00:16:01 +02:00
|
|
|
private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c, a), names) =>
|
2017-07-23 17:31:04 +02:00
|
|
|
println(fmt.format(
|
|
|
|
range.base,
|
|
|
|
range.base+range.size,
|
|
|
|
if (r) 'R' else ' ',
|
|
|
|
if (w) 'W' else ' ',
|
|
|
|
if (x) 'X' else ' ',
|
|
|
|
if (c) 'C' else ' ',
|
2017-10-19 00:16:01 +02:00
|
|
|
if (a) 'A' else ' ',
|
2017-07-23 17:31:04 +02:00
|
|
|
names.mkString(", ")))
|
2017-10-19 00:16:01 +02:00
|
|
|
s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],"names":[${names.map('"'+_+'"').mkString(",")}]}"""
|
2017-07-23 17:31:04 +02:00
|
|
|
}
|
|
|
|
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("")
|
|
|
|
}
|
|
|
|
}
|