commit
46369850cf
@ -49,13 +49,12 @@ trait HasCoreplexParameters {
|
|||||||
lazy val cbusConfig = p(CBusConfig)
|
lazy val cbusConfig = p(CBusConfig)
|
||||||
lazy val l1tol2Config = p(L1toL2Config)
|
lazy val l1tol2Config = p(L1toL2Config)
|
||||||
lazy val nTiles = tilesParams.size
|
lazy val nTiles = tilesParams.size
|
||||||
lazy val hasSupervisor = tilesParams.exists(_.core.useVM) // TODO ask andrew about this
|
|
||||||
lazy val l2Config = p(BankedL2Config)
|
lazy val l2Config = p(BankedL2Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class CoreplexParameters(implicit val p: Parameters) extends HasCoreplexParameters
|
case class CoreplexParameters(implicit val p: Parameters) extends HasCoreplexParameters
|
||||||
|
|
||||||
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule
|
abstract class BareCoreplex(implicit p: Parameters) extends LazyModule with BindingScope
|
||||||
|
|
||||||
abstract class BareCoreplexBundle[+L <: BareCoreplex](_outer: L) extends GenericParameterizedBundle(_outer) {
|
abstract class BareCoreplexBundle[+L <: BareCoreplex](_outer: L) extends GenericParameterizedBundle(_outer) {
|
||||||
val outer = _outer
|
val outer = _outer
|
||||||
|
@ -11,6 +11,7 @@ import util._
|
|||||||
|
|
||||||
trait CoreplexNetwork extends HasCoreplexParameters {
|
trait CoreplexNetwork extends HasCoreplexParameters {
|
||||||
val module: CoreplexNetworkModule
|
val module: CoreplexNetworkModule
|
||||||
|
def bindingTree: ResourceMap
|
||||||
|
|
||||||
val l1tol2 = LazyModule(new TLXbar)
|
val l1tol2 = LazyModule(new TLXbar)
|
||||||
val l1tol2_beatBytes = l1tol2Config.beatBytes
|
val l1tol2_beatBytes = l1tol2Config.beatBytes
|
||||||
@ -40,6 +41,53 @@ trait CoreplexNetwork extends HasCoreplexParameters {
|
|||||||
mmio :=
|
mmio :=
|
||||||
TLWidthWidget(l1tol2_beatBytes)(
|
TLWidthWidget(l1tol2_beatBytes)(
|
||||||
l1tol2.node)
|
l1tol2.node)
|
||||||
|
|
||||||
|
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")),
|
||||||
|
"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)))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBinding {
|
||||||
|
val managers = l1tol2.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait CoreplexNetworkBundle extends HasCoreplexParameters {
|
trait CoreplexNetworkBundle extends HasCoreplexParameters {
|
||||||
@ -54,16 +102,17 @@ trait CoreplexNetworkModule extends HasCoreplexParameters {
|
|||||||
val outer: CoreplexNetwork
|
val outer: CoreplexNetwork
|
||||||
val io: CoreplexNetworkBundle
|
val io: CoreplexNetworkBundle
|
||||||
|
|
||||||
println("\nGenerated Address Map")
|
println("Generated Address Map")
|
||||||
for (manager <- outer.l1tol2.node.edgesIn(0).manager.managers) {
|
for (manager <- outer.l1tol2.node.edgesIn(0).manager.managers) {
|
||||||
val prot = (if (manager.supportsGet) "R" else "") +
|
val prot = (if (manager.supportsGet) "R" else "") +
|
||||||
(if (manager.supportsPutFull) "W" else "") +
|
(if (manager.supportsPutFull) "W" else "") +
|
||||||
(if (manager.executable) "X" else "") +
|
(if (manager.executable) "X" else "") +
|
||||||
(if (manager.supportsAcquireB) " [C]" else "")
|
(if (manager.supportsAcquireB) " [C]" else "")
|
||||||
manager.address.foreach { a =>
|
AddressRange.fromSets(manager.address).foreach { r =>
|
||||||
println(f"\t${manager.name}%s ${a.base}%x - ${a.base+a.mask+1}%x, $prot")
|
println(f"\t${manager.name}%s ${r.base}%x - ${r.base+r.size}%x, $prot")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
println("")
|
||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
@ -15,7 +15,7 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork {
|
|||||||
val module: CoreplexRISCVPlatformModule
|
val module: CoreplexRISCVPlatformModule
|
||||||
|
|
||||||
val debug = LazyModule(new TLDebugModule())
|
val debug = LazyModule(new TLDebugModule())
|
||||||
val plic = LazyModule(new TLPLIC(hasSupervisor, maxPriorities = 7))
|
val plic = LazyModule(new TLPLIC(maxPriorities = 7))
|
||||||
val clint = LazyModule(new CoreplexLocalInterrupter)
|
val clint = LazyModule(new CoreplexLocalInterrupter)
|
||||||
|
|
||||||
debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
|
debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
|
||||||
@ -24,10 +24,7 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork {
|
|||||||
|
|
||||||
plic.intnode := intBar.intnode
|
plic.intnode := intBar.intnode
|
||||||
|
|
||||||
lazy val configString = {
|
lazy val dts = DTS(bindingTree)
|
||||||
val managers = l1tol2.node.edgesIn(0).manager.managers
|
|
||||||
rocketchip.GenerateConfigString(p, clint, plic, managers)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle {
|
trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle {
|
||||||
@ -50,6 +47,6 @@ trait CoreplexRISCVPlatformModule extends CoreplexNetworkModule {
|
|||||||
val rtcLast = Reg(init = Bool(false), next=rtcSync)
|
val rtcLast = Reg(init = Bool(false), next=rtcSync)
|
||||||
outer.clint.module.io.rtcTick := Reg(init = Bool(false), next=(rtcSync & (~rtcLast)))
|
outer.clint.module.io.rtcTick := Reg(init = Bool(false), next=(rtcSync & (~rtcLast)))
|
||||||
|
|
||||||
println(s"\nGenerated Configuration String\n${outer.configString}")
|
println(outer.dts)
|
||||||
ElaborationArtefacts.add("cfg", outer.configString)
|
ElaborationArtefacts.add("dts", outer.dts)
|
||||||
}
|
}
|
||||||
|
@ -23,16 +23,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
private val crossing = p(RocketCrossing)
|
private val crossing = p(RocketCrossing)
|
||||||
private val configs = p(RocketTilesKey)
|
private val configs = p(RocketTilesKey)
|
||||||
|
|
||||||
private val rocketTileIntNodes = configs.map { _ => IntInternalOutputNode() }
|
|
||||||
rocketTileIntNodes.foreach { _ := plic.intnode }
|
|
||||||
|
|
||||||
private def wireInterrupts(x: TileInterrupts, i: Int) {
|
|
||||||
x := clint.module.io.tiles(i)
|
|
||||||
x.debug := debug.module.io.debugInterrupts(i)
|
|
||||||
x.meip := rocketTileIntNodes(i).bundleOut(0)(0)
|
|
||||||
x.seip.foreach { _ := rocketTileIntNodes(i).bundleOut(0)(1) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val rocketWires: Seq[HasRocketTilesBundle => Unit] = configs.zipWithIndex.map { case (c, i) =>
|
val rocketWires: Seq[HasRocketTilesBundle => Unit] = configs.zipWithIndex.map { case (c, i) =>
|
||||||
val pWithExtra = p.alterPartial {
|
val pWithExtra = p.alterPartial {
|
||||||
case TileKey => c
|
case TileKey => c
|
||||||
@ -41,50 +31,62 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
|||||||
case PAddrBits => l1tol2.node.edgesIn(0).bundle.addressBits
|
case PAddrBits => l1tol2.node.edgesIn(0).bundle.addressBits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hack debug interrupt into a node (future debug module should use diplomacy)
|
||||||
|
val debugNode = IntInternalInputNode(IntSourcePortSimple())
|
||||||
|
|
||||||
|
val intBar = LazyModule(new IntXbar)
|
||||||
|
intBar.intnode := debugNode
|
||||||
|
intBar.intnode := clint.intnode // msip+mtip
|
||||||
|
intBar.intnode := plic.intnode // meip
|
||||||
|
if (c.core.useVM) intBar.intnode := plic.intnode // seip
|
||||||
|
|
||||||
crossing match {
|
crossing match {
|
||||||
case Synchronous => {
|
case Synchronous => {
|
||||||
val tile = LazyModule(new RocketTile(c)(pWithExtra))
|
val tile = LazyModule(new RocketTile(c, i)(pWithExtra))
|
||||||
val buffer = LazyModule(new TLBuffer)
|
val buffer = LazyModule(new TLBuffer)
|
||||||
buffer.node :=* tile.masterNode
|
buffer.node :=* tile.masterNode
|
||||||
l1tol2.node :=* buffer.node
|
l1tol2.node :=* buffer.node
|
||||||
tile.slaveNode :*= cbus.node
|
tile.slaveNode :*= cbus.node
|
||||||
|
tile.intNode := intBar.intnode
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
// leave clock as default (simpler for hierarchical PnR)
|
// leave clock as default (simpler for hierarchical PnR)
|
||||||
tile.module.io.hartid := UInt(i)
|
tile.module.io.hartid := UInt(i)
|
||||||
tile.module.io.resetVector := io.resetVector
|
tile.module.io.resetVector := io.resetVector
|
||||||
wireInterrupts(tile.module.io.interrupts, i)
|
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Asynchronous(depth, sync) => {
|
case Asynchronous(depth, sync) => {
|
||||||
val wrapper = LazyModule(new AsyncRocketTile(c)(pWithExtra))
|
val wrapper = LazyModule(new AsyncRocketTile(c, i)(pWithExtra))
|
||||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||||
sink.node :=* wrapper.masterNode
|
sink.node :=* wrapper.masterNode
|
||||||
l1tol2.node :=* sink.node
|
l1tol2.node :=* sink.node
|
||||||
wrapper.slaveNode :*= source.node
|
wrapper.slaveNode :*= source.node
|
||||||
|
wrapper.intNode := intBar.intnode
|
||||||
source.node :*= cbus.node
|
source.node :*= cbus.node
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
wrapper.module.clock := io.tcrs(i).clock
|
wrapper.module.clock := io.tcrs(i).clock
|
||||||
wrapper.module.reset := io.tcrs(i).reset
|
wrapper.module.reset := io.tcrs(i).reset
|
||||||
wrapper.module.io.hartid := UInt(i)
|
wrapper.module.io.hartid := UInt(i)
|
||||||
wrapper.module.io.resetVector := io.resetVector
|
wrapper.module.io.resetVector := io.resetVector
|
||||||
wireInterrupts(wrapper.module.io.interrupts, i)
|
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Rational => {
|
case Rational => {
|
||||||
val wrapper = LazyModule(new RationalRocketTile(c)(pWithExtra))
|
val wrapper = LazyModule(new RationalRocketTile(c, i)(pWithExtra))
|
||||||
val sink = LazyModule(new TLRationalCrossingSink(util.FastToSlow))
|
val sink = LazyModule(new TLRationalCrossingSink(util.FastToSlow))
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
val source = LazyModule(new TLRationalCrossingSource)
|
||||||
sink.node :=* wrapper.masterNode
|
sink.node :=* wrapper.masterNode
|
||||||
l1tol2.node :=* sink.node
|
l1tol2.node :=* sink.node
|
||||||
wrapper.slaveNode :*= source.node
|
wrapper.slaveNode :*= source.node
|
||||||
|
wrapper.intNode := intBar.intnode
|
||||||
source.node :*= cbus.node
|
source.node :*= cbus.node
|
||||||
(io: HasRocketTilesBundle) => {
|
(io: HasRocketTilesBundle) => {
|
||||||
wrapper.module.clock := io.tcrs(i).clock
|
wrapper.module.clock := io.tcrs(i).clock
|
||||||
wrapper.module.reset := io.tcrs(i).reset
|
wrapper.module.reset := io.tcrs(i).reset
|
||||||
wrapper.module.io.hartid := UInt(i)
|
wrapper.module.io.hartid := UInt(i)
|
||||||
wrapper.module.io.resetVector := io.resetVector
|
wrapper.module.io.resetVector := io.resetVector
|
||||||
wireInterrupts(wrapper.module.io.interrupts, i)
|
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
117
src/main/scala/diplomacy/DeviceTree.scala
Normal file
117
src/main/scala/diplomacy/DeviceTree.scala
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package diplomacy
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
|
||||||
|
case object DTSModel extends Field[String]
|
||||||
|
case object DTSCompat extends Field[Seq[String]] // -dev, -soc
|
||||||
|
case object DTSTimebase extends Field[BigInt] // Clock frequency of clint RTC (use 0 if you don't know it)
|
||||||
|
|
||||||
|
object DTS
|
||||||
|
{
|
||||||
|
def apply(res: ResourceValue): String = "/dts-v1/;\n\n" + helper(res, "", defaultCells).mkString("")
|
||||||
|
|
||||||
|
private val nodeStartChars = (('a' to 'z') ++ ('A' to 'Z')).toSet
|
||||||
|
private val nodeChars = (('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') ++ Seq(',', '.', '_', '+', '-', '@')).toSet
|
||||||
|
def legalNode(x: String): Boolean =
|
||||||
|
x == "/" || (!x.isEmpty && x.size < 32 && nodeStartChars.contains(x(0)) && x.forall(nodeChars.contains(_)))
|
||||||
|
|
||||||
|
// the DTS spec does not list '-', but uses it everywhere ...
|
||||||
|
private val propChars = (('a' to 'z') ++ ('A' to 'Z') ++ ('0' to '9') ++ Seq(',', '.', '_', '+', '?', '#', '-')).toSet
|
||||||
|
def legalProperty(x: String): Boolean =
|
||||||
|
x == "/" || (!x.isEmpty && x.size < 32 && x.forall(propChars.contains(_)))
|
||||||
|
|
||||||
|
// The DTS spec doesn't say what is allowed in a string, so just use our own judgement
|
||||||
|
private val strChars = (('#' to '[') ++ (']' to '~') ++ Seq(' ', '!')).toSet
|
||||||
|
def legalString(x: String): Boolean = x.forall(strChars.contains(_))
|
||||||
|
|
||||||
|
private case class Cells(
|
||||||
|
parentAddress: Int,
|
||||||
|
parentSize: Int,
|
||||||
|
selfAddress: Int,
|
||||||
|
selfSize: Int)
|
||||||
|
private val defaultCells = Cells(2, 1, 2, 1)
|
||||||
|
|
||||||
|
private def fmtCell(x: BigInt, cells: Int): Seq[String] = {
|
||||||
|
val cellbits = 32
|
||||||
|
val mask = (BigInt(1) << cellbits) - 1
|
||||||
|
(0 until cells).reverse map { case i => "0x%x".format((x >> (i*cellbits)) & mask) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtAddress(x: ResourceAddress, cells: Cells): Seq[String] = {
|
||||||
|
val ranges = AddressRange.fromSets(x.address)
|
||||||
|
ranges.flatMap { case AddressRange(base, size) =>
|
||||||
|
fmtCell(base, cells.parentAddress) ++ fmtCell(size, cells.parentSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtMapping(x: ResourceMapping, cells: Cells): Seq[String] = {
|
||||||
|
val ranges = AddressRange.fromSets(x.address)
|
||||||
|
ranges.flatMap { case AddressRange(base, size) =>
|
||||||
|
fmtCell(base+x.offset, cells.selfAddress) ++ fmtCell(base, cells.parentAddress) ++ fmtCell(size, cells.selfSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtString(x: ResourceString): Seq[String] = {
|
||||||
|
require (legalString(x.value), s"The string '${x.value}' contains chars probably unwise for use in a DTS string")
|
||||||
|
Seq("\"" + x.value + "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
private def fmtMap(x: ResourceMap, indent: String, cells: Cells): Seq[String] = {
|
||||||
|
val (nodes, props) = x.value.partition(_ match {
|
||||||
|
case (_, Seq(ResourceMap(_, _))) => true
|
||||||
|
case _ => false
|
||||||
|
})
|
||||||
|
|
||||||
|
def getInt(x: ResourceValue) = x match {
|
||||||
|
case ResourceInt(value) => Some(value.toInt)
|
||||||
|
case _ => None
|
||||||
|
}
|
||||||
|
val selfAddress = x.value.getOrElse("#address-cells", Nil).headOption.flatMap(getInt)
|
||||||
|
val selfSize = x.value.getOrElse("#size-cells", Nil).headOption.flatMap(getInt)
|
||||||
|
|
||||||
|
val myCells = Cells(
|
||||||
|
parentAddress = cells.selfAddress,
|
||||||
|
parentSize = cells.selfSize,
|
||||||
|
selfAddress = selfAddress.getOrElse(defaultCells.selfAddress),
|
||||||
|
selfSize = selfSize .getOrElse(defaultCells.selfSize))
|
||||||
|
|
||||||
|
props.flatMap { case (k, seq) =>
|
||||||
|
require (legalProperty(k), s"The string '${k}' is not a legal DTS property name")
|
||||||
|
seq.headOption match {
|
||||||
|
case None => Seq(indent, k, ";\n")
|
||||||
|
case Some(ResourceString(_)) => {
|
||||||
|
seq.foreach { r => r match {
|
||||||
|
case ResourceString(_) => Unit
|
||||||
|
case _ => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
} }
|
||||||
|
Seq(indent, k, " = ", seq.flatMap(z => helper(z, "", myCells)).mkString(", "), ";\n")
|
||||||
|
}
|
||||||
|
case Some(_) => {
|
||||||
|
seq.foreach { r => r match {
|
||||||
|
case ResourceMap(_, _) => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
case ResourceString(_) => require(false, s"The property '${k}' has values of conflicting type: ${seq}")
|
||||||
|
case _ => Unit
|
||||||
|
} }
|
||||||
|
Seq(indent, k, " = <", seq.flatMap(z => helper(z, "", myCells)).mkString(" "), ">;\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.toList ++
|
||||||
|
nodes.flatMap { case (k, Seq(s: ResourceMap)) =>
|
||||||
|
require (legalNode(k), s"The string '${k}' is not a legal DTS node name")
|
||||||
|
Seq(indent) ++ s.labels.map(_ + ": ").filter(_ => !indent.isEmpty) ++ // labels on root not allowed
|
||||||
|
Seq(k, " {\n") ++ helper(s, indent + "\t", myCells) ++ Seq(indent, "};\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def helper(res: ResourceValue, indent: String, cells: Cells): Seq[String] = res match {
|
||||||
|
case x: ResourceAddress => fmtAddress(x, cells)
|
||||||
|
case x: ResourceMapping => fmtMapping(x, cells)
|
||||||
|
case x: ResourceInt => Seq(x.value.toString)
|
||||||
|
case x: ResourceString => fmtString(x)
|
||||||
|
case x: ResourceReference => Seq("&" + x.value)
|
||||||
|
case x: ResourceMap => fmtMap(x, indent, cells)
|
||||||
|
}
|
||||||
|
}
|
@ -302,8 +302,8 @@ class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
|||||||
numPI: Range.Inclusive = 1 to 999)
|
numPI: Range.Inclusive = 1 to 999)
|
||||||
extends MixedNode(inner, outer)(numPO, numPI)
|
extends MixedNode(inner, outer)(numPO, numPI)
|
||||||
{
|
{
|
||||||
require (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}")
|
// require (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}")
|
||||||
require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}")
|
// require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}")
|
||||||
|
|
||||||
val externalIn: Boolean = true
|
val externalIn: Boolean = true
|
||||||
val externalOut: Boolean = true
|
val externalOut: Boolean = true
|
||||||
|
@ -76,6 +76,32 @@ object TransferSizes {
|
|||||||
implicit def asBool(x: TransferSizes) = !x.none
|
implicit def asBool(x: TransferSizes) = !x.none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use AddressSet instead -- this is just for pretty printing
|
||||||
|
case class AddressRange(base: BigInt, size: BigInt) extends Ordered[AddressRange]
|
||||||
|
{
|
||||||
|
val end = base + size
|
||||||
|
|
||||||
|
require (base >= 0)
|
||||||
|
require (size > 0)
|
||||||
|
|
||||||
|
def compare(x: AddressRange) = {
|
||||||
|
val primary = (this.base - x.base).signum
|
||||||
|
val secondary = (x.size - this.size).signum
|
||||||
|
if (primary != 0) primary else secondary
|
||||||
|
}
|
||||||
|
|
||||||
|
def contains(x: AddressRange) = base <= x.base && x.end <= end
|
||||||
|
def union(x: AddressRange): Option[AddressRange] = {
|
||||||
|
if (base > x.end || x.base > end) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
val obase = if (base < x.base) base else x.base
|
||||||
|
val oend = if (end > x.end) end else x.end
|
||||||
|
Some(AddressRange(obase, oend-obase))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddressSets specify the address space managed by the manager
|
// AddressSets specify the address space managed by the manager
|
||||||
// Base is the base address, and mask are the bits consumed by the manager
|
// Base is the base address, and mask are the bits consumed by the manager
|
||||||
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
||||||
@ -132,6 +158,32 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
|||||||
"AddressSet(0x%x, ~0x%x)".format(base, ~mask)
|
"AddressSet(0x%x, ~0x%x)".format(base, ~mask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def toRanges = {
|
||||||
|
require (finite)
|
||||||
|
val size = alignment
|
||||||
|
val fragments = mask & ~(size-1)
|
||||||
|
val bits = bitIndexes(fragments)
|
||||||
|
(BigInt(0) until (BigInt(1) << bits.size)).map { i =>
|
||||||
|
val off = bitIndexes(i).foldLeft(base) { case (a, b) => a.setBit(bits(b)) }
|
||||||
|
AddressRange(off, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AddressRange
|
||||||
|
{
|
||||||
|
def fromSets(seq: Seq[AddressSet]): Seq[AddressRange] = unify(seq.flatMap(_.toRanges))
|
||||||
|
def unify(seq: Seq[AddressRange]): Seq[AddressRange] = {
|
||||||
|
if (seq.isEmpty) return Nil
|
||||||
|
val ranges = seq.sorted
|
||||||
|
ranges.tail.foldLeft(Seq(ranges.head)) { case (head :: tail, x) =>
|
||||||
|
head.union(x) match {
|
||||||
|
case Some(z) => z :: tail
|
||||||
|
case None => x :: head :: tail
|
||||||
|
}
|
||||||
|
}.reverse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object AddressSet
|
object AddressSet
|
||||||
|
189
src/main/scala/diplomacy/Resources.scala
Normal file
189
src/main/scala/diplomacy/Resources.scala
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
// See LICENSE.SiFive for license details.
|
||||||
|
|
||||||
|
package diplomacy
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import config._
|
||||||
|
import scala.collection.immutable.{ListMap,SortedMap}
|
||||||
|
|
||||||
|
sealed trait ResourceValue
|
||||||
|
final case class ResourceAddress(address: Seq[AddressSet], r: Boolean, w: Boolean, x: Boolean) extends ResourceValue
|
||||||
|
final case class ResourceMapping(address: Seq[AddressSet], offset: BigInt) extends ResourceValue
|
||||||
|
final case class ResourceInt(value: BigInt) extends ResourceValue
|
||||||
|
final case class ResourceString(value: String) extends ResourceValue
|
||||||
|
final case class ResourceReference(value: String) extends ResourceValue
|
||||||
|
final case class ResourceMap(value: Map[String, Seq[ResourceValue]], labels: Seq[String] = Nil) extends ResourceValue
|
||||||
|
|
||||||
|
/* If device is None, the value is global */
|
||||||
|
case class Binding(device: Option[Device], value: ResourceValue)
|
||||||
|
case class ResourceBindings(map: Map[String, Seq[Binding]])
|
||||||
|
{
|
||||||
|
def apply(key: String): Seq[Binding] = map.getOrElse(key, Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
case class Description(name: String, mapping: Map[String, Seq[ResourceValue]])
|
||||||
|
|
||||||
|
abstract class Device
|
||||||
|
{
|
||||||
|
def describe(resources: ResourceBindings): Description
|
||||||
|
|
||||||
|
val label = "L" + Device.index.toString
|
||||||
|
Device.index = Device.index + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
object Device
|
||||||
|
{
|
||||||
|
private var index: Int = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DeviceInterrupts
|
||||||
|
{
|
||||||
|
this: Device =>
|
||||||
|
val alwaysExtended = false
|
||||||
|
def describeInterrupts(resources: ResourceBindings): Map[String, Seq[ResourceValue]] = {
|
||||||
|
val int = resources("int")
|
||||||
|
|
||||||
|
int.foreach { b => require (b.device.isDefined, "Device ${devname} property 'int' is missing user device") }
|
||||||
|
val parents = int.map(_.device.get).distinct
|
||||||
|
val simple = parents.size == 1 && !alwaysExtended
|
||||||
|
|
||||||
|
val parent =
|
||||||
|
if (!simple) None else
|
||||||
|
Some("interrupt-parent" -> Seq(ResourceReference(parents.head.label)))
|
||||||
|
val interrupts =
|
||||||
|
if (!simple) None else
|
||||||
|
Some("interrupts" -> int.map(_.value))
|
||||||
|
|
||||||
|
val interrupts_extended =
|
||||||
|
if (simple || parents.isEmpty) None else
|
||||||
|
Some("interrupts-extended" -> int.flatMap(b => Seq(ResourceReference(b.device.get.label), b.value)))
|
||||||
|
|
||||||
|
ListMap() ++ parent ++ interrupts ++ interrupts_extended
|
||||||
|
}
|
||||||
|
|
||||||
|
def int = Seq(Resource(this, "int"))
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DeviceRegName
|
||||||
|
{
|
||||||
|
this: Device =>
|
||||||
|
val prefix = "soc/" // nearly everything on-chip belongs here
|
||||||
|
def describeName(devname: String, resources: ResourceBindings): String = {
|
||||||
|
val reg = resources("reg")
|
||||||
|
require (!reg.isEmpty, "Device is missing the 'reg' property")
|
||||||
|
reg.head.value match {
|
||||||
|
case x: ResourceAddress => s"${prefix}${devname}@${x.address.head.base.toString(16)}"
|
||||||
|
case _ => require(false, "Device has the wrong type of 'reg' property (${reg.head})"); ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def reg = Seq(Resource(this, "reg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleDevice(devname: String, devcompat: Seq[String]) extends Device with DeviceInterrupts with DeviceRegName
|
||||||
|
{
|
||||||
|
def describe(resources: ResourceBindings): Description = {
|
||||||
|
val name = describeName(devname, resources)
|
||||||
|
val int = describeInterrupts(resources)
|
||||||
|
val compat =
|
||||||
|
if (devcompat.isEmpty) None else
|
||||||
|
Some("compatible" -> devcompat.map(ResourceString(_)))
|
||||||
|
|
||||||
|
Description(name,
|
||||||
|
ListMap("reg" -> resources("reg").map(_.value))
|
||||||
|
++ compat ++ int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryDevice extends Device with DeviceRegName
|
||||||
|
{
|
||||||
|
override val prefix = ""
|
||||||
|
def describe(resources: ResourceBindings): Description = {
|
||||||
|
Description(describeName("memory", resources), ListMap(
|
||||||
|
"reg" -> resources("reg").map(_.value),
|
||||||
|
"device_type" -> Seq(ResourceString("memory"))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case class Resource(owner: Device, key: String)
|
||||||
|
{
|
||||||
|
def bind(user: Device, value: ResourceValue) {
|
||||||
|
val scope = BindingScope.active.get
|
||||||
|
scope.resourceBindings = (this, Some(user), value) +: scope.resourceBindings
|
||||||
|
}
|
||||||
|
def bind(value: ResourceValue) {
|
||||||
|
val scope = BindingScope.active.get
|
||||||
|
scope.resourceBindings = (this, None, value) +: scope.resourceBindings
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait BindingScope
|
||||||
|
{
|
||||||
|
this: LazyModule =>
|
||||||
|
|
||||||
|
private val parentScope = BindingScope.find(parent)
|
||||||
|
protected[diplomacy] var resourceBindingFns: Seq[() => Unit] = Nil
|
||||||
|
protected[diplomacy] var resourceBindings: Seq[(Resource, Option[Device], ResourceValue)] = Nil
|
||||||
|
|
||||||
|
private case class ExpandedValue(path: Seq[String], labels: Seq[String], value: Seq[ResourceValue])
|
||||||
|
private def eval() {
|
||||||
|
require (LazyModule.stack.isEmpty, "May not evaluate binding while still constructing LazyModules")
|
||||||
|
parentScope.foreach { _.eval() }
|
||||||
|
resourceBindings = parentScope.map(_.resourceBindings).getOrElse(Nil)
|
||||||
|
BindingScope.active = Some(this)
|
||||||
|
resourceBindingFns.reverse.foreach { _() }
|
||||||
|
BindingScope.active = None
|
||||||
|
resourceBindingFns = Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private def makeTree(list: Seq[ExpandedValue]): Seq[ResourceValue] = {
|
||||||
|
val (values_p, keys_p) = list.partition(_.path.isEmpty)
|
||||||
|
val values = values_p.flatMap(_.value)
|
||||||
|
val labels = values_p.flatMap(_.labels)
|
||||||
|
val keys = keys_p.groupBy(_.path.head).toList.map { case (key, seq) =>
|
||||||
|
(key -> makeTree(seq.map { x => x.copy(path = x.path.tail) }))
|
||||||
|
// case ExpandedValue(keys, values) => ExpandedValue(keys.tail, values) }))
|
||||||
|
}
|
||||||
|
if (keys.isEmpty) values else ResourceMap(SortedMap(keys:_*), labels) +: values
|
||||||
|
}
|
||||||
|
|
||||||
|
private def expand(path: Seq[String], values: Seq[ResourceValue]): Seq[ExpandedValue] = {
|
||||||
|
ExpandedValue(path, Nil, Nil) +:
|
||||||
|
values.flatMap {
|
||||||
|
case ResourceMap(map, labels) =>
|
||||||
|
ExpandedValue(path, labels, Nil) +:
|
||||||
|
map.toList.flatMap { case (key, values) => expand(path :+ key, values) }
|
||||||
|
case z => Seq(ExpandedValue(path, Nil, Seq(z)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def bindingTree: ResourceMap = {
|
||||||
|
eval()
|
||||||
|
val map: Map[Device, ResourceBindings] =
|
||||||
|
resourceBindings.reverse.groupBy(_._1.owner).mapValues(seq => ResourceBindings(
|
||||||
|
seq.groupBy(_._1.key).mapValues(_.map(z => Binding(z._2, z._3)))))
|
||||||
|
val tree = makeTree(map.toList.flatMap { case (d, m) =>
|
||||||
|
val Description(name, mapping) = d.describe(m)
|
||||||
|
val tokens = name.split("/").toList
|
||||||
|
expand(tokens, Seq(ResourceMap(mapping, Seq(d.label)))) })
|
||||||
|
ResourceMap(SortedMap("/" -> tree))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object BindingScope
|
||||||
|
{
|
||||||
|
protected[diplomacy] var active: Option[BindingScope] = None
|
||||||
|
protected[diplomacy] def find(m: Option[LazyModule] = LazyModule.stack.headOption): Option[BindingScope] = m.flatMap {
|
||||||
|
case s: BindingScope => Some(s)
|
||||||
|
case x => find(x.parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ResourceBinding
|
||||||
|
{
|
||||||
|
def apply(block: => Unit) {
|
||||||
|
val scope = BindingScope.find()
|
||||||
|
require (scope.isDefined, "ResourceBinding must be called from within a BindingScope")
|
||||||
|
scope.get.resourceBindingFns = { () => block } +: scope.get.resourceBindingFns
|
||||||
|
}
|
||||||
|
}
|
@ -9,4 +9,14 @@ package object diplomacy
|
|||||||
case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
|
case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
|
||||||
case _ => ""
|
case _ => ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def bitIndexes(x: BigInt, tail: Seq[Int] = Nil): Seq[Int] = {
|
||||||
|
require (x >= 0)
|
||||||
|
if (x == 0) {
|
||||||
|
tail.reverse
|
||||||
|
} else {
|
||||||
|
val lowest = x.lowestSetBit
|
||||||
|
bitIndexes(x.clearBit(lowest), lowest +: tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import util._
|
|||||||
import Chisel.ImplicitConversions._
|
import Chisel.ImplicitConversions._
|
||||||
|
|
||||||
case class RocketCoreParams(
|
case class RocketCoreParams(
|
||||||
|
bootFreqHz: BigInt = 0,
|
||||||
useVM: Boolean = true,
|
useVM: Boolean = true,
|
||||||
useUser: Boolean = false,
|
useUser: Boolean = false,
|
||||||
useDebug: Boolean = true,
|
useDebug: Boolean = true,
|
||||||
|
@ -23,12 +23,85 @@ case class RocketTileParams(
|
|||||||
require(dcache.isDefined)
|
require(dcache.isDefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RocketTile(val rocketParams: RocketTileParams)(implicit p: Parameters) extends BaseTile(rocketParams)(p)
|
class RocketTile(val rocketParams: RocketTileParams, val hartid: Int)(implicit p: Parameters) extends BaseTile(rocketParams)(p)
|
||||||
with CanHaveLegacyRoccs // implies CanHaveSharedFPU with CanHavePTW with HasHellaCache
|
with CanHaveLegacyRoccs // implies CanHaveSharedFPU with CanHavePTW with HasHellaCache
|
||||||
with CanHaveScratchpad { // implies CanHavePTW with HasHellaCache with HasICacheFrontend
|
with CanHaveScratchpad { // implies CanHavePTW with HasHellaCache with HasICacheFrontend
|
||||||
|
|
||||||
nDCachePorts += 1 // core TODO dcachePorts += () => module.core.io.dmem ??
|
nDCachePorts += 1 // core TODO dcachePorts += () => module.core.io.dmem ??
|
||||||
|
|
||||||
|
val device = new Device {
|
||||||
|
def ofInt(x: Int) = Seq(ResourceInt(BigInt(x)))
|
||||||
|
def ofStr(x: String) = Seq(ResourceString(x))
|
||||||
|
def describe(resources: ResourceBindings): Description = {
|
||||||
|
val block = p(CacheBlockBytes)
|
||||||
|
val m = if (rocketParams.core.mulDiv.nonEmpty) "m" else ""
|
||||||
|
val a = if (rocketParams.core.useAtomics) "a" else ""
|
||||||
|
val f = if (rocketParams.core.fpu.nonEmpty) "f" else ""
|
||||||
|
val d = if (rocketParams.core.fpu.nonEmpty && p(XLen) > 32) "d" else ""
|
||||||
|
val c = if (rocketParams.core.useCompressed) "c" else ""
|
||||||
|
val s = if (rocketParams.core.useVM) "s" else ""
|
||||||
|
val isa = s"rv${p(XLen)}i$m$a$f$d$c$s"
|
||||||
|
|
||||||
|
val dcache = rocketParams.dcache.map(d => Map(
|
||||||
|
"d-tlb-size" -> ofInt(d.nTLBEntries),
|
||||||
|
"d-tlb-sets" -> ofInt(1),
|
||||||
|
"d-cache-block-size" -> ofInt(block),
|
||||||
|
"d-cache-sets" -> ofInt(d.nSets),
|
||||||
|
"d-cache-size" -> ofInt(d.nSets * d.nWays * block))).getOrElse(Map())
|
||||||
|
|
||||||
|
val icache = rocketParams.icache.map(i => Map(
|
||||||
|
"i-tlb-size" -> ofInt(i.nTLBEntries),
|
||||||
|
"i-tlb-sets" -> ofInt(1),
|
||||||
|
"i-cache-block-size" -> ofInt(block),
|
||||||
|
"i-cache-sets" -> ofInt(i.nSets),
|
||||||
|
"i-cache-size" -> ofInt(i.nSets * i.nWays * block))).getOrElse(Map())
|
||||||
|
|
||||||
|
// Find all the caches
|
||||||
|
val outer = masterNode.edgesOut
|
||||||
|
.flatMap(_.manager.managers)
|
||||||
|
.filter(_.supportsAcquireB)
|
||||||
|
.flatMap(_.resources.headOption)
|
||||||
|
.map(_.owner.label)
|
||||||
|
.distinct
|
||||||
|
val nextlevel: Option[(String, Seq[ResourceValue])] =
|
||||||
|
if (outer.isEmpty) None else
|
||||||
|
Some("next-level-cache" -> outer.map(l => ResourceReference(l)).toList)
|
||||||
|
|
||||||
|
Description(s"cpus/cpu@${hartid}", Map(
|
||||||
|
"reg" -> resources("reg").map(_.value),
|
||||||
|
"device_type" -> ofStr("cpu"),
|
||||||
|
"compatible" -> ofStr("riscv"),
|
||||||
|
"status" -> ofStr("okay"),
|
||||||
|
"clock-frequency" -> Seq(ResourceInt(rocketParams.core.bootFreqHz)),
|
||||||
|
"riscv,isa" -> ofStr(isa),
|
||||||
|
"mmu-type" -> ofStr(p(PgLevels) match {
|
||||||
|
case 2 => "riscv,sv32"
|
||||||
|
case 3 => "riscv,sv39"
|
||||||
|
case 4 => "riscv,sv48" }),
|
||||||
|
"tlb-split" -> Nil,
|
||||||
|
"interrupt-controller" -> Nil,
|
||||||
|
"#interrupt-cells" -> ofInt(1))
|
||||||
|
++ dcache ++ icache ++ nextlevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBinding {
|
||||||
|
Resource(device, "reg").bind(ResourceInt(BigInt(hartid)))
|
||||||
|
|
||||||
|
// debug, msip, mtip, meip, seip offsets in CSRs
|
||||||
|
val intMap = Seq(65535, 3, 7, 11, 9)
|
||||||
|
|
||||||
|
intNode.edgesIn.flatMap(_.source.sources).map { case s =>
|
||||||
|
for (i <- s.range.start until s.range.end) {
|
||||||
|
intMap.lift(i).foreach { j =>
|
||||||
|
s.resources.foreach { r =>
|
||||||
|
r.bind(device, ResourceInt(j))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override lazy val module = new RocketTileModule(this)
|
override lazy val module = new RocketTileModule(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +113,6 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
|||||||
with CanHaveScratchpadModule {
|
with CanHaveScratchpadModule {
|
||||||
|
|
||||||
val core = Module(p(BuildCore)(outer.p))
|
val core = Module(p(BuildCore)(outer.p))
|
||||||
core.io.interrupts := io.interrupts
|
|
||||||
core.io.hartid := io.hartid
|
core.io.hartid := io.hartid
|
||||||
outer.frontend.module.io.cpu <> core.io.imem
|
outer.frontend.module.io.cpu <> core.io.imem
|
||||||
outer.frontend.module.io.resetVector := io.resetVector
|
outer.frontend.module.io.resetVector := io.resetVector
|
||||||
@ -55,6 +127,13 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
|||||||
core.io.rocc.interrupt := lr.module.io.core.interrupt
|
core.io.rocc.interrupt := lr.module.io.core.interrupt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode the interrupt vector
|
||||||
|
core.io.interrupts.debug := io.interrupts(0)(0)
|
||||||
|
core.io.interrupts.msip := io.interrupts(0)(1)
|
||||||
|
core.io.interrupts.mtip := io.interrupts(0)(2)
|
||||||
|
core.io.interrupts.meip := io.interrupts(0)(3)
|
||||||
|
core.io.interrupts.seip.foreach { _ := io.interrupts(0)(4) }
|
||||||
|
|
||||||
// TODO eliminate this redundancy
|
// TODO eliminate this redundancy
|
||||||
val h = dcachePorts.size
|
val h = dcachePorts.size
|
||||||
val c = core.dcacheArbPorts
|
val c = core.dcacheArbPorts
|
||||||
@ -66,8 +145,8 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
|||||||
ptwOpt foreach { ptw => ptw.io.requestor <> ptwPorts }
|
ptwOpt foreach { ptw => ptw.io.requestor <> ptwPorts }
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends LazyModule {
|
class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
val rocket = LazyModule(new RocketTile(rtp))
|
val rocket = LazyModule(new RocketTile(rtp, hartid))
|
||||||
|
|
||||||
val masterNode = TLAsyncOutputNode()
|
val masterNode = TLAsyncOutputNode()
|
||||||
val source = LazyModule(new TLAsyncCrossingSource)
|
val source = LazyModule(new TLAsyncCrossingSource)
|
||||||
@ -79,23 +158,27 @@ class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends Laz
|
|||||||
rocket.slaveNode :*= sink.node
|
rocket.slaveNode :*= sink.node
|
||||||
sink.node :*= slaveNode
|
sink.node :*= slaveNode
|
||||||
|
|
||||||
|
val intNode = IntInputNode()
|
||||||
|
val xing = LazyModule(new IntXing(3))
|
||||||
|
rocket.intNode := xing.intnode
|
||||||
|
xing.intnode := intNode
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val master = masterNode.bundleOut
|
val master = masterNode.bundleOut
|
||||||
val slave = slaveNode.bundleIn
|
val slave = slaveNode.bundleIn
|
||||||
|
val interrupts = intNode.bundleIn
|
||||||
val hartid = UInt(INPUT, p(XLen))
|
val hartid = UInt(INPUT, p(XLen))
|
||||||
val interrupts = new TileInterrupts()(p).asInput
|
|
||||||
val resetVector = UInt(INPUT, p(XLen))
|
val resetVector = UInt(INPUT, p(XLen))
|
||||||
}
|
}
|
||||||
rocket.module.io.interrupts := ShiftRegister(io.interrupts, 3)
|
|
||||||
// signals that do not change:
|
// signals that do not change:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
rocket.module.io.resetVector := io.resetVector
|
rocket.module.io.resetVector := io.resetVector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends LazyModule {
|
class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends LazyModule {
|
||||||
val rocket = LazyModule(new RocketTile(rtp))
|
val rocket = LazyModule(new RocketTile(rtp, hartid))
|
||||||
|
|
||||||
val masterNode = TLRationalOutputNode()
|
val masterNode = TLRationalOutputNode()
|
||||||
val source = LazyModule(new TLRationalCrossingSource)
|
val source = LazyModule(new TLRationalCrossingSource)
|
||||||
@ -107,15 +190,19 @@ class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends
|
|||||||
rocket.slaveNode :*= sink.node
|
rocket.slaveNode :*= sink.node
|
||||||
sink.node :*= slaveNode
|
sink.node :*= slaveNode
|
||||||
|
|
||||||
|
val intNode = IntInputNode()
|
||||||
|
val xing = LazyModule(new IntXing(1))
|
||||||
|
rocket.intNode := xing.intnode
|
||||||
|
xing.intnode := intNode
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
val io = new Bundle {
|
val io = new Bundle {
|
||||||
val master = masterNode.bundleOut
|
val master = masterNode.bundleOut
|
||||||
val slave = slaveNode.bundleIn
|
val slave = slaveNode.bundleIn
|
||||||
|
val interrupts = intNode.bundleIn
|
||||||
val hartid = UInt(INPUT, p(XLen))
|
val hartid = UInt(INPUT, p(XLen))
|
||||||
val interrupts = new TileInterrupts()(p).asInput
|
|
||||||
val resetVector = UInt(INPUT, p(XLen))
|
val resetVector = UInt(INPUT, p(XLen))
|
||||||
}
|
}
|
||||||
rocket.module.io.interrupts := ShiftRegister(io.interrupts, 1)
|
|
||||||
// signals that do not change:
|
// signals that do not change:
|
||||||
rocket.module.io.hartid := io.hartid
|
rocket.module.io.hartid := io.hartid
|
||||||
rocket.module.io.resetVector := io.resetVector
|
rocket.module.io.resetVector := io.resetVector
|
||||||
|
@ -20,6 +20,10 @@ import DefaultTestSuites._
|
|||||||
import config._
|
import config._
|
||||||
|
|
||||||
class BasePlatformConfig extends Config((site, here, up) => {
|
class BasePlatformConfig extends Config((site, here, up) => {
|
||||||
|
// DTS descriptive parameters
|
||||||
|
case DTSModel => "ucbbar,rocketchip-unknown"
|
||||||
|
case DTSCompat => Nil
|
||||||
|
case DTSTimebase => BigInt(0)
|
||||||
// TileLink connection parameters
|
// TileLink connection parameters
|
||||||
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
||||||
case TLFuzzReadyValid => false
|
case TLFuzzReadyValid => false
|
||||||
@ -139,6 +143,11 @@ class WithExtMemSize(n: Long) extends Config((site, here, up) => {
|
|||||||
case ExtMem => up(ExtMem, site).copy(size = n)
|
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 WithScratchpad extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))
|
class WithScratchpad extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))
|
||||||
|
|
||||||
class DefaultFPGASmallConfig extends Config(new WithNSmallCores(1) ++ new DefaultFPGAConfig)
|
class DefaultFPGASmallConfig extends Config(new WithNSmallCores(1) ++ new DefaultFPGAConfig)
|
||||||
|
@ -51,8 +51,14 @@ trait HasPeripheryParameters {
|
|||||||
trait PeripheryExtInterrupts {
|
trait PeripheryExtInterrupts {
|
||||||
this: HasTopLevelNetworks =>
|
this: HasTopLevelNetworks =>
|
||||||
|
|
||||||
|
private val device = new Device with DeviceInterrupts {
|
||||||
|
def describe(resources: ResourceBindings): Description = {
|
||||||
|
Description("soc/offchip-interrupts", describeInterrupts(resources))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val nExtInterrupts = p(NExtTopInterrupts)
|
val nExtInterrupts = p(NExtTopInterrupts)
|
||||||
val extInterrupts = IntInternalInputNode(nExtInterrupts)
|
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
||||||
val extInterruptXing = LazyModule(new IntXing)
|
val extInterruptXing = LazyModule(new IntXing)
|
||||||
|
|
||||||
intBus.intnode := extInterruptXing.intnode
|
intBus.intnode := extInterruptXing.intnode
|
||||||
@ -84,6 +90,8 @@ trait PeripheryMasterAXI4Mem {
|
|||||||
private val channels = p(BankedL2Config).nMemoryChannels
|
private val channels = p(BankedL2Config).nMemoryChannels
|
||||||
private val lineBytes = p(CacheBlockBytes)
|
private val lineBytes = p(CacheBlockBytes)
|
||||||
|
|
||||||
|
private val device = new MemoryDevice
|
||||||
|
|
||||||
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(channels) { channel =>
|
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(channels) { channel =>
|
||||||
val base = AddressSet(config.base, config.size-1)
|
val base = AddressSet(config.base, config.size-1)
|
||||||
val filter = AddressSet(channel * lineBytes, ~((channels-1) * lineBytes))
|
val filter = AddressSet(channel * lineBytes, ~((channels-1) * lineBytes))
|
||||||
@ -91,6 +99,7 @@ trait PeripheryMasterAXI4Mem {
|
|||||||
AXI4SlavePortParameters(
|
AXI4SlavePortParameters(
|
||||||
slaves = Seq(AXI4SlaveParameters(
|
slaves = Seq(AXI4SlaveParameters(
|
||||||
address = base.intersect(filter).toList,
|
address = base.intersect(filter).toList,
|
||||||
|
resources = device.reg,
|
||||||
regionType = RegionType.UNCACHED, // cacheable
|
regionType = RegionType.UNCACHED, // cacheable
|
||||||
executable = true,
|
executable = true,
|
||||||
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
||||||
@ -160,9 +169,11 @@ trait PeripheryMasterAXI4MMIO {
|
|||||||
this: HasTopLevelNetworks =>
|
this: HasTopLevelNetworks =>
|
||||||
|
|
||||||
private val config = p(ExtBus)
|
private val config = p(ExtBus)
|
||||||
|
private val device = new SimpleDevice("mmio", Nil)
|
||||||
val mmio_axi4 = AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
val mmio_axi4 = AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
||||||
slaves = Seq(AXI4SlaveParameters(
|
slaves = Seq(AXI4SlaveParameters(
|
||||||
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
||||||
|
resources = device.reg,
|
||||||
executable = true, // Can we run programs on this memory?
|
executable = true, // Can we run programs on this memory?
|
||||||
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
||||||
supportsRead = TransferSizes(1, 256),
|
supportsRead = TransferSizes(1, 256),
|
||||||
@ -227,9 +238,11 @@ trait PeripheryMasterTLMMIO {
|
|||||||
this: HasTopLevelNetworks =>
|
this: HasTopLevelNetworks =>
|
||||||
|
|
||||||
private val config = p(ExtBus)
|
private val config = p(ExtBus)
|
||||||
|
private val device = new SimpleDevice("mmio", Nil)
|
||||||
val mmio_tl = TLBlindOutputNode(Seq(TLManagerPortParameters(
|
val mmio_tl = TLBlindOutputNode(Seq(TLManagerPortParameters(
|
||||||
managers = Seq(TLManagerParameters(
|
managers = Seq(TLManagerParameters(
|
||||||
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
||||||
|
resources = device.reg,
|
||||||
executable = true,
|
executable = true,
|
||||||
supportsGet = TransferSizes(1, cacheBlockBytes),
|
supportsGet = TransferSizes(1, cacheBlockBytes),
|
||||||
supportsPutFull = TransferSizes(1, cacheBlockBytes),
|
supportsPutFull = TransferSizes(1, cacheBlockBytes),
|
||||||
@ -292,7 +305,7 @@ trait PeripheryBootROM {
|
|||||||
|
|
||||||
private val bootrom_address = 0x1000
|
private val bootrom_address = 0x1000
|
||||||
private val bootrom_size = 0x1000
|
private val bootrom_size = 0x1000
|
||||||
private lazy val bootrom_contents = GenerateBootROM(p, bootrom_address, coreplex.configString)
|
private lazy val bootrom_contents = GenerateBootROM(p, bootrom_address, coreplex.dts)
|
||||||
val bootrom = LazyModule(new TLROM(bootrom_address, bootrom_size, bootrom_contents, true, peripheryBusConfig.beatBytes))
|
val bootrom = LazyModule(new TLROM(bootrom_address, bootrom_size, bootrom_contents, true, peripheryBusConfig.beatBytes))
|
||||||
bootrom.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
bootrom.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||||
}
|
}
|
||||||
|
@ -52,50 +52,18 @@ class GlobalVariable[T] {
|
|||||||
def get: T = { require(assigned); variable }
|
def get: T = { require(assigned); variable }
|
||||||
}
|
}
|
||||||
|
|
||||||
object GenerateConfigString {
|
|
||||||
def apply(p: Parameters, clint: CoreplexLocalInterrupter, plic: TLPLIC, peripheryManagers: Seq[TLManagerParameters]) = {
|
|
||||||
val c = CoreplexParameters()(p)
|
|
||||||
val res = new StringBuilder
|
|
||||||
res append plic.globalConfigString
|
|
||||||
res append clint.globalConfigString
|
|
||||||
res append "core {\n"
|
|
||||||
c.tilesParams.zipWithIndex.map { case(t, i) =>
|
|
||||||
val isa = {
|
|
||||||
val m = if (t.core.mulDiv.nonEmpty) "m" else ""
|
|
||||||
val a = if (t.core.useAtomics) "a" else ""
|
|
||||||
val f = if (t.core.fpu.nonEmpty) "f" else ""
|
|
||||||
val d = if (t.core.fpu.nonEmpty && p(XLen) > 32) "d" else ""
|
|
||||||
val c = if (t.core.useCompressed) "c" else ""
|
|
||||||
val s = if (t.core.useVM) "s" else ""
|
|
||||||
s"rv${p(XLen)}i$m$a$f$d$c$s"
|
|
||||||
}
|
|
||||||
res append s" $i {\n"
|
|
||||||
res append " 0 {\n"
|
|
||||||
res append s" isa $isa;\n"
|
|
||||||
res append clint.hartConfigStrings(i)
|
|
||||||
res append plic.hartConfigStrings(i)
|
|
||||||
res append " };\n"
|
|
||||||
res append " };\n"
|
|
||||||
}
|
|
||||||
res append "};\n"
|
|
||||||
peripheryManagers.foreach { manager => res append manager.dts }
|
|
||||||
res append '\u0000'
|
|
||||||
res.toString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object GenerateBootROM {
|
object GenerateBootROM {
|
||||||
def apply(p: Parameters, address: BigInt, configString: String) = {
|
def apply(p: Parameters, address: BigInt, dts: String) = {
|
||||||
val romdata = Files.readAllBytes(Paths.get(p(BootROMFile)))
|
val romdata = Files.readAllBytes(Paths.get(p(BootROMFile)))
|
||||||
val rom = ByteBuffer.wrap(romdata)
|
val rom = ByteBuffer.wrap(romdata)
|
||||||
|
|
||||||
rom.order(ByteOrder.LITTLE_ENDIAN)
|
rom.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
|
||||||
require(address == address.toInt)
|
require(address == address.toInt)
|
||||||
val configStringAddr = address.toInt + rom.capacity
|
val dtsAddr = address.toInt + rom.capacity
|
||||||
require(rom.getInt(12) == 0,
|
require(rom.getInt(12) == 0,
|
||||||
"Config string address position should not be occupied by code")
|
"DTS address position should not be occupied by code")
|
||||||
rom.putInt(12, configStringAddr)
|
rom.putInt(12, dtsAddr)
|
||||||
rom.array() ++ (configString.getBytes.toSeq)
|
rom.array() ++ (dts.getBytes.toSeq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,11 +53,13 @@ trait HasTileLinkMasterPort extends HasTileParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val module: HasTileLinkMasterPortModule
|
val module: HasTileLinkMasterPortModule
|
||||||
val masterNode = TLOutputNode()
|
val masterNode = TLOutputNode()
|
||||||
|
val intNode = IntSinkNode(IntSinkPortSimple())
|
||||||
}
|
}
|
||||||
|
|
||||||
trait HasTileLinkMasterPortBundle {
|
trait HasTileLinkMasterPortBundle {
|
||||||
val outer: HasTileLinkMasterPort
|
val outer: HasTileLinkMasterPort
|
||||||
val master = outer.masterNode.bundleOut
|
val master = outer.masterNode.bundleOut
|
||||||
|
val interrupts = outer.intNode.bundleIn
|
||||||
}
|
}
|
||||||
|
|
||||||
trait HasTileLinkMasterPortModule {
|
trait HasTileLinkMasterPortModule {
|
||||||
@ -73,7 +75,6 @@ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends
|
|||||||
class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer)
|
class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer)
|
||||||
with HasTileLinkMasterPortBundle {
|
with HasTileLinkMasterPortBundle {
|
||||||
val hartid = UInt(INPUT, p(XLen))
|
val hartid = UInt(INPUT, p(XLen))
|
||||||
val interrupts = new TileInterrupts()(p).asInput
|
|
||||||
val resetVector = UInt(INPUT, p(XLen))
|
val resetVector = UInt(INPUT, p(XLen))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
|||||||
|
|
||||||
case class AHBSlaveParameters(
|
case class AHBSlaveParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
|
resources: Seq[Resource] = Nil,
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
executable: Boolean = false, // processor can execute from this memory
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
nodePath: Seq[BaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
|
@ -77,7 +77,7 @@ object AHBRegisterNode
|
|||||||
abstract class AHBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class AHBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = AHBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = AHBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(interrupts)
|
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AHBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AHBBundle])(implicit val p: Parameters)
|
case class AHBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AHBBundle])(implicit val p: Parameters)
|
||||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
|||||||
|
|
||||||
case class APBSlaveParameters(
|
case class APBSlaveParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
|
resources: Seq[Resource] = Nil,
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
executable: Boolean = false, // processor can execute from this memory
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
nodePath: Seq[BaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
|
@ -61,7 +61,7 @@ object APBRegisterNode
|
|||||||
abstract class APBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class APBRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = APBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = APBRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(interrupts)
|
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class APBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[APBBundle])(implicit val p: Parameters)
|
case class APBRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[APBBundle])(implicit val p: Parameters)
|
||||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
|||||||
|
|
||||||
case class AXI4SlaveParameters(
|
case class AXI4SlaveParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
|
resources: Seq[Resource] = Nil,
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
executable: Boolean = false, // processor can execute from this memory
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
nodePath: Seq[BaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
|
@ -82,7 +82,7 @@ object AXI4RegisterNode
|
|||||||
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class AXI4RegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val node = AXI4RegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||||
val intnode = uncore.tilelink2.IntSourceNode(interrupts)
|
val intnode = uncore.tilelink2.IntSourceNode(uncore.tilelink2.IntSourcePortSimple(num = interrupts))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class AXI4RegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AXI4Bundle])(implicit val p: Parameters)
|
case class AXI4RegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[AXI4Bundle])(implicit val p: Parameters)
|
||||||
|
@ -20,6 +20,7 @@ case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
|||||||
slaves = mp.managers.map { m =>
|
slaves = mp.managers.map { m =>
|
||||||
AXI4SlaveParameters(
|
AXI4SlaveParameters(
|
||||||
address = m.address,
|
address = m.address,
|
||||||
|
resources = m.resources,
|
||||||
regionType = m.regionType,
|
regionType = m.regionType,
|
||||||
executable = m.executable,
|
executable = m.executable,
|
||||||
nodePath = m.nodePath,
|
nodePath = m.nodePath,
|
||||||
|
@ -849,7 +849,7 @@ trait DebugModule extends Module with HasDebugModuleParameters with HasRegMap {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class TLDebugModule(address: BigInt = 0)(implicit p: Parameters)
|
class TLDebugModule(address: BigInt = 0)(implicit p: Parameters)
|
||||||
extends TLRegisterRouter(address, beatBytes=p(XLen)/8, executable=true)(
|
extends TLRegisterRouter(address, "debug", Nil, beatBytes=p(XLen)/8, executable=true)(
|
||||||
new TLRegBundle((), _ ) with DebugModuleBundle)(
|
new TLRegBundle((), _ ) with DebugModuleBundle)(
|
||||||
new TLRegModule((), _, _) with DebugModule)
|
new TLRegModule((), _, _) with DebugModule)
|
||||||
|
|
||||||
|
@ -53,57 +53,52 @@ object PLICConsts
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Platform-Level Interrupt Controller */
|
/** Platform-Level Interrupt Controller */
|
||||||
class TLPLIC(supervisor: Boolean, maxPriorities: Int, address: BigInt = 0xC000000)(implicit p: Parameters) extends LazyModule
|
class TLPLIC(maxPriorities: Int, address: BigInt = 0xC000000)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val contextsPerHart = if (supervisor) 2 else 1
|
|
||||||
require (maxPriorities >= 0)
|
require (maxPriorities >= 0)
|
||||||
|
|
||||||
|
// plic0 => max devices 1023
|
||||||
|
val device = new SimpleDevice("interrupt-controller", Seq("riscv,plic0")) {
|
||||||
|
override val alwaysExtended = true
|
||||||
|
override def describe(resources: ResourceBindings): Description = {
|
||||||
|
val Description(name, mapping) = super.describe(resources)
|
||||||
|
val extra = Map(
|
||||||
|
"interrupt-controller" -> Nil,
|
||||||
|
"riscv,ndev" -> Seq(ResourceInt(nDevices)),
|
||||||
|
"#interrupt-cells" -> Seq(ResourceInt(1)),
|
||||||
|
"#address-cells" -> Seq(ResourceInt(0)))
|
||||||
|
Description(name, mapping ++ extra)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val node = TLRegisterNode(
|
val node = TLRegisterNode(
|
||||||
address = AddressSet(address, PLICConsts.size-1),
|
address = AddressSet(address, PLICConsts.size-1),
|
||||||
|
device = device,
|
||||||
beatBytes = p(XLen)/8,
|
beatBytes = p(XLen)/8,
|
||||||
undefZero = false)
|
undefZero = false)
|
||||||
|
|
||||||
val intnode = IntNexusNode(
|
val intnode = IntNexusNode(
|
||||||
numSourcePorts = 0 to 1024,
|
numSourcePorts = 0 to 1024,
|
||||||
numSinkPorts = 0 to 1024,
|
numSinkPorts = 0 to 1024,
|
||||||
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(contextsPerHart))) },
|
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(1, Seq(Resource(device, "int"))))) },
|
||||||
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
|
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
|
||||||
|
|
||||||
/* Negotiated sizes */
|
/* Negotiated sizes */
|
||||||
def nDevices = intnode.edgesIn.map(_.source.num).sum
|
def nDevices: Int = intnode.edgesIn.map(_.source.num).sum
|
||||||
def nPriorities = min(maxPriorities, nDevices)
|
def nPriorities = min(maxPriorities, nDevices)
|
||||||
def nHarts = intnode.edgesOut.map(_.source.num).sum
|
def nHarts = intnode.edgesOut.map(_.source.num).sum
|
||||||
|
|
||||||
def context(i: Int, mode: Char) = mode match {
|
// Assign all the devices unique ranges
|
||||||
case 'M' => i * contextsPerHart
|
lazy val sources = intnode.edgesIn.map(_.source)
|
||||||
case 'S' => require(supervisor); i * contextsPerHart + 1
|
lazy val flatSources = (sources zip sources.map(_.num).scanLeft(0)(_+_).init).map {
|
||||||
}
|
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
|
||||||
def claimAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode)) + PLICConsts.claimOffset
|
}.flatten
|
||||||
def threshAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode))
|
|
||||||
def enableAddr(i: Int, mode: Char) = address + PLICConsts.enableBase(context(i, mode))
|
|
||||||
|
|
||||||
// Create the global PLIC config string
|
ResourceBinding {
|
||||||
lazy val globalConfigString = Seq(
|
flatSources.foreach { s => s.resources.foreach { r =>
|
||||||
s"plic {\n",
|
// +1 because interrupt 0 is reserved
|
||||||
s" priority 0x${address.toString(16)};\n",
|
(s.range.start until s.range.end).foreach { i => r.bind(device, ResourceInt(i+1)) }
|
||||||
s" pending 0x${(address + PLICConsts.pendingBase).toString(16)};\n",
|
} }
|
||||||
s" ndevs ${nDevices};\n",
|
|
||||||
s"};\n").mkString
|
|
||||||
|
|
||||||
// Create the per-Hart config string
|
|
||||||
lazy val hartConfigStrings = Seq.tabulate(intnode.edgesOut.size) { i => (Seq(
|
|
||||||
s" plic {\n",
|
|
||||||
s" m {\n",
|
|
||||||
s" ie 0x${enableAddr(i, 'M').toString(16)};\n",
|
|
||||||
s" thresh 0x${threshAddr(i, 'M').toString(16)};\n",
|
|
||||||
s" claim 0x${claimAddr(i, 'M').toString(16)};\n",
|
|
||||||
s" };\n") ++ (if (!supervisor) Seq() else Seq(
|
|
||||||
s" s {\n",
|
|
||||||
s" ie 0x${enableAddr(i, 'S').toString(16)};\n",
|
|
||||||
s" thresh 0x${threshAddr(i, 'S').toString(16)};\n",
|
|
||||||
s" claim 0x${claimAddr(i, 'S').toString(16)};\n",
|
|
||||||
s" };\n")) ++ Seq(
|
|
||||||
s" };\n")).mkString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
lazy val module = new LazyModuleImp(this) {
|
||||||
@ -113,21 +108,17 @@ class TLPLIC(supervisor: Boolean, maxPriorities: Int, address: BigInt = 0xC00000
|
|||||||
val harts = intnode.bundleOut
|
val harts = intnode.bundleOut
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign all the devices unique ranges
|
|
||||||
val sources = intnode.edgesIn.map(_.source)
|
|
||||||
val flatSources = (sources zip sources.map(_.num).scanLeft(0)(_+_).init).map {
|
|
||||||
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
|
|
||||||
}.flatten
|
|
||||||
// Compact the interrupt vector the same way
|
// Compact the interrupt vector the same way
|
||||||
val interrupts = (intnode.edgesIn zip io.devices).map { case (e, i) => i.take(e.source.num) }.flatten
|
val interrupts = (intnode.edgesIn zip io.devices).map { case (e, i) => i.take(e.source.num) }.flatten
|
||||||
// This flattens the harts into an MSMSMSMSMS... or MMMMM.... sequence
|
// This flattens the harts into an MSMSMSMSMS... or MMMMM.... sequence
|
||||||
val harts = io.harts.flatten
|
val harts = io.harts.flatten
|
||||||
|
|
||||||
println("\nInterrupt map:")
|
println(s"Interrupt map (${nHarts} harts ${nDevices} interrupts):")
|
||||||
flatSources.foreach { s =>
|
flatSources.foreach { s =>
|
||||||
// +1 because 0 is reserved, +1-1 because the range is half-open
|
// +1 because 0 is reserved, +1-1 because the range is half-open
|
||||||
println(s" [${s.range.start+1}, ${s.range.end}] => ${s.name}")
|
println(s" [${s.range.start+1}, ${s.range.end}] => ${s.name}")
|
||||||
}
|
}
|
||||||
|
println("")
|
||||||
|
|
||||||
require (nDevices == interrupts.size)
|
require (nDevices == interrupts.size)
|
||||||
require (nHarts == harts.size)
|
require (nHarts == harts.size)
|
||||||
|
@ -17,11 +17,6 @@ import tile.XLen
|
|||||||
/** Number of tiles */
|
/** Number of tiles */
|
||||||
case object NTiles extends Field[Int]
|
case object NTiles extends Field[Int]
|
||||||
|
|
||||||
class CoreplexLocalInterrupts extends Bundle {
|
|
||||||
val mtip = Bool()
|
|
||||||
val msip = Bool()
|
|
||||||
}
|
|
||||||
|
|
||||||
object ClintConsts
|
object ClintConsts
|
||||||
{
|
{
|
||||||
def msipOffset(hart: Int) = hart * msipBytes
|
def msipOffset(hart: Int) = hart * msipBytes
|
||||||
@ -30,23 +25,37 @@ object ClintConsts
|
|||||||
def msipBytes = 4
|
def msipBytes = 4
|
||||||
def timecmpBytes = 8
|
def timecmpBytes = 8
|
||||||
def size = 0x10000
|
def size = 0x10000
|
||||||
|
def timeWidth = 64
|
||||||
|
def regWidth = 32
|
||||||
|
def ints = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
trait MixCoreplexLocalInterrupterParameters {
|
class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit p: Parameters) extends LazyModule
|
||||||
implicit val p: Parameters
|
{
|
||||||
}
|
import ClintConsts._
|
||||||
|
|
||||||
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
|
// clint0 => at most 4095 devices
|
||||||
val tiles = Vec(p(NTiles), new CoreplexLocalInterrupts).asOutput
|
val device = new SimpleDevice("clint", Seq("riscv,clint0")) {
|
||||||
|
override val alwaysExtended = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val node = TLRegisterNode(
|
||||||
|
address = AddressSet(address, size-1),
|
||||||
|
device = device,
|
||||||
|
beatBytes = p(XLen)/8)
|
||||||
|
|
||||||
|
val intnode = IntNexusNode(
|
||||||
|
numSourcePorts = 0 to 1024,
|
||||||
|
numSinkPorts = 0 to 0,
|
||||||
|
sourceFn = { _ => IntSourcePortParameters(Seq(IntSourceParameters(ints, Seq(Resource(device, "int"))))) },
|
||||||
|
sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) })
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
val rtcTick = Bool(INPUT)
|
val rtcTick = Bool(INPUT)
|
||||||
}
|
val int = intnode.bundleOut
|
||||||
|
val in = node.bundleIn
|
||||||
trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters {
|
}
|
||||||
val io: CoreplexLocalInterrupterBundle
|
|
||||||
val address: AddressSet
|
|
||||||
|
|
||||||
val timeWidth = 64
|
|
||||||
val regWidth = 32
|
|
||||||
|
|
||||||
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
|
val time = Seq.fill(timeWidth/regWidth)(Reg(init=UInt(0, width = regWidth)))
|
||||||
when (io.rtcTick) {
|
when (io.rtcTick) {
|
||||||
@ -58,9 +67,9 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
|
|||||||
val timecmp = Seq.fill(p(NTiles)) { Seq.fill(timeWidth/regWidth)(Reg(UInt(width = regWidth))) }
|
val timecmp = Seq.fill(p(NTiles)) { Seq.fill(timeWidth/regWidth)(Reg(UInt(width = regWidth))) }
|
||||||
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
||||||
|
|
||||||
for ((tile, i) <- io.tiles zipWithIndex) {
|
io.int.zipWithIndex.foreach { case (int, i) =>
|
||||||
tile.msip := ipi(i)(0)
|
int(0) := ipi(i)(0) // msip
|
||||||
tile.mtip := time.asUInt >= timecmp(i).asUInt
|
int(1) := time.asUInt >= timecmp(i).asUInt // mtip
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 0000 msip hart 0
|
/* 0000 msip hart 0
|
||||||
@ -73,27 +82,11 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
|
|||||||
* bffc mtime hi
|
* bffc mtime hi
|
||||||
*/
|
*/
|
||||||
|
|
||||||
regmap(
|
|
||||||
0 -> makeRegFields(ipi),
|
|
||||||
ClintConsts.timecmpOffset(0) -> makeRegFields(timecmp.flatten),
|
|
||||||
ClintConsts.timeOffset -> makeRegFields(time))
|
|
||||||
|
|
||||||
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
|
def makeRegFields(s: Seq[UInt]) = s.map(r => RegField(regWidth, r))
|
||||||
}
|
|
||||||
|
|
||||||
/** Power, Reset, Clock, Interrupt */
|
node.regmap(
|
||||||
// Magic TL2 Incantation to create a TL2 Slave
|
0 -> makeRegFields(ipi),
|
||||||
class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit p: Parameters)
|
timecmpOffset(0) -> makeRegFields(timecmp.flatten),
|
||||||
extends TLRegisterRouter(address, size = ClintConsts.size, beatBytes = p(XLen)/8, undefZero = true)(
|
timeOffset -> makeRegFields(time))
|
||||||
new TLRegBundle((), _) with CoreplexLocalInterrupterBundle)(
|
|
||||||
new TLRegModule((), _, _) with CoreplexLocalInterrupterModule)
|
|
||||||
{
|
|
||||||
val globalConfigString = Seq(
|
|
||||||
s"rtc {\n",
|
|
||||||
s" addr 0x${(address + ClintConsts.timeOffset).toString(16)};\n",
|
|
||||||
s"};\n").mkString
|
|
||||||
val hartConfigStrings = (0 until p(NTiles)).map { i => Seq(
|
|
||||||
s" timecmp 0x${(address + ClintConsts.timecmpOffset(i)).toString(16)};\n",
|
|
||||||
s" ipi 0x${(address + ClintConsts.msipOffset(i)).toString(16)};\n").mkString
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,11 @@ import config._
|
|||||||
|
|
||||||
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
|
val device = new SimpleDevice("rom", Nil)
|
||||||
|
|
||||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = List(AddressSet(base, size-1)),
|
address = List(AddressSet(base, size-1)),
|
||||||
|
resources = device.reg,
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
executable = executable,
|
executable = executable,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
@ -34,6 +34,7 @@ trait ExampleModule extends HasRegMap
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a concrete TL2 version of the abstract Example slave
|
// Create a concrete TL2 version of the abstract Example slave
|
||||||
class TLExample(params: ExampleParams)(implicit p: Parameters) extends TLRegisterRouter(params.address, 4)(
|
class TLExample(params: ExampleParams)(implicit p: Parameters)
|
||||||
|
extends TLRegisterRouter(params.address, "somedev", Seq("ucbbar,random-interface"), 4)(
|
||||||
new TLRegBundle(params, _) with ExampleBundle)(
|
new TLRegBundle(params, _) with ExampleBundle)(
|
||||||
new TLRegModule(params, _, _) with ExampleModule)
|
new TLRegModule(params, _, _) with ExampleModule)
|
||||||
|
@ -18,6 +18,7 @@ case class IntRange(start: Int, end: Int)
|
|||||||
def overlaps(x: IntRange) = start < x.end && x.start < end
|
def overlaps(x: IntRange) = start < x.end && x.start < end
|
||||||
def offset(x: Int) = IntRange(x+start, x+end)
|
def offset(x: Int) = IntRange(x+start, x+end)
|
||||||
}
|
}
|
||||||
|
|
||||||
object IntRange
|
object IntRange
|
||||||
{
|
{
|
||||||
implicit def apply(end: Int): IntRange = apply(0, end)
|
implicit def apply(end: Int): IntRange = apply(0, end)
|
||||||
@ -25,6 +26,7 @@ object IntRange
|
|||||||
|
|
||||||
case class IntSourceParameters(
|
case class IntSourceParameters(
|
||||||
range: IntRange,
|
range: IntRange,
|
||||||
|
resources: Seq[Resource] = Seq(),
|
||||||
nodePath: Seq[BaseNode] = Seq())
|
nodePath: Seq[BaseNode] = Seq())
|
||||||
{
|
{
|
||||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||||
@ -44,8 +46,19 @@ case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
|
|||||||
// The interrupts must perfectly cover the range
|
// The interrupts must perfectly cover the range
|
||||||
require (sources.isEmpty || sources.map(_.range.end).max == num)
|
require (sources.isEmpty || sources.map(_.range.end).max == num)
|
||||||
}
|
}
|
||||||
|
object IntSourcePortSimple
|
||||||
|
{
|
||||||
|
def apply(num: Int = 1, ports: Int = 1, sources: Int = 1, resources: Seq[Resource] = Nil) =
|
||||||
|
if (num == 0) Nil else
|
||||||
|
Seq.fill(ports)(IntSourcePortParameters(Seq.fill(sources)(IntSourceParameters(range = IntRange(0, num), resources = resources))))
|
||||||
|
}
|
||||||
|
|
||||||
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
|
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
|
||||||
|
object IntSinkPortSimple
|
||||||
|
{
|
||||||
|
def apply(ports: Int = 1, sinks: Int = 1) =
|
||||||
|
Seq.fill(ports)(IntSinkPortParameters(Seq.fill(sinks)(IntSinkParameters())))
|
||||||
|
}
|
||||||
|
|
||||||
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters)
|
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters)
|
||||||
|
|
||||||
@ -74,10 +87,8 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
|
|||||||
}
|
}
|
||||||
|
|
||||||
case class IntIdentityNode() extends IdentityNode(IntImp)
|
case class IntIdentityNode() extends IdentityNode(IntImp)
|
||||||
case class IntSourceNode(num: Int) extends SourceNode(IntImp)(
|
case class IntSourceNode(portParams: Seq[IntSourcePortParameters]) extends SourceNode(IntImp)(portParams)
|
||||||
if (num == 0) Seq() else Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
case class IntSinkNode(portParams: Seq[IntSinkPortParameters]) extends SinkNode(IntImp)(portParams)
|
||||||
case class IntSinkNode() extends SinkNode(IntImp)(
|
|
||||||
Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
|
||||||
|
|
||||||
case class IntNexusNode(
|
case class IntNexusNode(
|
||||||
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
|
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
|
||||||
@ -89,11 +100,11 @@ case class IntNexusNode(
|
|||||||
case class IntOutputNode() extends OutputNode(IntImp)
|
case class IntOutputNode() extends OutputNode(IntImp)
|
||||||
case class IntInputNode() extends InputNode(IntImp)
|
case class IntInputNode() extends InputNode(IntImp)
|
||||||
|
|
||||||
case class IntBlindOutputNode() extends BlindOutputNode(IntImp)(Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
case class IntBlindOutputNode(portParams: Seq[IntSinkPortParameters]) extends BlindOutputNode(IntImp)(portParams)
|
||||||
case class IntBlindInputNode(num: Int) extends BlindInputNode(IntImp)(Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
case class IntBlindInputNode(portParams: Seq[IntSourcePortParameters]) extends BlindInputNode(IntImp)(portParams)
|
||||||
|
|
||||||
case class IntInternalOutputNode() extends InternalOutputNode(IntImp)(Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
case class IntInternalOutputNode(portParams: Seq[IntSinkPortParameters]) extends InternalOutputNode(IntImp)(portParams)
|
||||||
case class IntInternalInputNode(num: Int) extends InternalInputNode(IntImp)(Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
case class IntInternalInputNode(portParams: Seq[IntSourcePortParameters]) extends InternalInputNode(IntImp)(portParams)
|
||||||
|
|
||||||
class IntXbar()(implicit p: Parameters) extends LazyModule
|
class IntXbar()(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
@ -116,7 +127,7 @@ class IntXbar()(implicit p: Parameters) extends LazyModule
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class IntXing()(implicit p: Parameters) extends LazyModule
|
class IntXing(sync: Int = 3)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val intnode = IntIdentityNode()
|
val intnode = IntIdentityNode()
|
||||||
|
|
||||||
@ -127,7 +138,7 @@ class IntXing()(implicit p: Parameters) extends LazyModule
|
|||||||
}
|
}
|
||||||
|
|
||||||
(io.in zip io.out) foreach { case (in, out) =>
|
(io.in zip io.out) foreach { case (in, out) =>
|
||||||
out := RegNext(RegNext(RegNext(in)))
|
out := (0 to sync).foldLeft(in) { case (a, _) => RegNext(a) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import util.RationalDirection
|
|||||||
|
|
||||||
case class TLManagerParameters(
|
case class TLManagerParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
|
resources: Seq[Resource] = Seq(),
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||||
executable: Boolean = false, // processor can execute from this memory
|
executable: Boolean = false, // processor can execute from this memory
|
||||||
nodePath: Seq[BaseNode] = Seq(),
|
nodePath: Seq[BaseNode] = Seq(),
|
||||||
@ -22,8 +23,7 @@ case class TLManagerParameters(
|
|||||||
supportsPutPartial: TransferSizes = TransferSizes.none,
|
supportsPutPartial: TransferSizes = TransferSizes.none,
|
||||||
supportsHint: TransferSizes = TransferSizes.none,
|
supportsHint: TransferSizes = TransferSizes.none,
|
||||||
// If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order
|
// If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order
|
||||||
fifoId: Option[Int] = None,
|
fifoId: Option[Int] = None)
|
||||||
customDTS: Option[String]= None)
|
|
||||||
{
|
{
|
||||||
require (!address.isEmpty)
|
require (!address.isEmpty)
|
||||||
address.foreach { a => require (a.finite) }
|
address.foreach { a => require (a.finite) }
|
||||||
@ -53,20 +53,16 @@ case class TLManagerParameters(
|
|||||||
|
|
||||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||||
|
|
||||||
// Generate the config string (in future device tree)
|
|
||||||
lazy val dts = customDTS.getOrElse {
|
|
||||||
val header = s"${name} {\n"
|
|
||||||
val middle = address.map { a =>
|
|
||||||
require (a.contiguous) // Config String is not so flexible
|
|
||||||
" addr 0x%x;\n size 0x%x;\n".format(a.base, a.mask+1)
|
|
||||||
}
|
|
||||||
val footer = "}\n"
|
|
||||||
header + middle.reduce(_ + _) + footer
|
|
||||||
}
|
|
||||||
|
|
||||||
// The device had better not support a transfer larger than it's alignment
|
// The device had better not support a transfer larger than it's alignment
|
||||||
val minAlignment = address.map(_.alignment).min
|
val minAlignment = address.map(_.alignment).min
|
||||||
require (minAlignment >= maxTransfer)
|
require (minAlignment >= maxTransfer)
|
||||||
|
|
||||||
|
def toResource: ResourceAddress = {
|
||||||
|
ResourceAddress(address,
|
||||||
|
r = supportsAcquireB || supportsGet,
|
||||||
|
w = supportsAcquireT || supportsPutFull,
|
||||||
|
x = executable)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLManagerPortParameters(
|
case class TLManagerPortParameters(
|
||||||
|
@ -8,10 +8,18 @@ import diplomacy._
|
|||||||
import regmapper._
|
import regmapper._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
class TLRegisterNode(
|
||||||
|
address: AddressSet,
|
||||||
|
device: Device,
|
||||||
|
deviceKey: String = "reg",
|
||||||
|
concurrency: Int = 0,
|
||||||
|
beatBytes: Int = 4,
|
||||||
|
undefZero: Boolean = true,
|
||||||
|
executable: Boolean = false)
|
||||||
extends TLManagerNode(Seq(TLManagerPortParameters(
|
extends TLManagerNode(Seq(TLManagerPortParameters(
|
||||||
Seq(TLManagerParameters(
|
Seq(TLManagerParameters(
|
||||||
address = Seq(address),
|
address = Seq(address),
|
||||||
|
resources = Seq(Resource(device, deviceKey)),
|
||||||
executable = executable,
|
executable = executable,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
@ -72,18 +80,26 @@ class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int =
|
|||||||
|
|
||||||
object TLRegisterNode
|
object TLRegisterNode
|
||||||
{
|
{
|
||||||
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false) =
|
def apply(
|
||||||
new TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
address: AddressSet,
|
||||||
|
device: Device,
|
||||||
|
deviceKey: String = "reg",
|
||||||
|
concurrency: Int = 0,
|
||||||
|
beatBytes: Int = 4,
|
||||||
|
undefZero: Boolean = true,
|
||||||
|
executable: Boolean = false) =
|
||||||
|
new TLRegisterNode(address, device, deviceKey, concurrency, beatBytes, undefZero, executable)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These convenience methods below combine to make it possible to create a TL2
|
// These convenience methods below combine to make it possible to create a TL2
|
||||||
// register mapped device from a totally abstract register mapped device.
|
// register mapped device from a totally abstract register mapped device.
|
||||||
// See GPIO.scala in this directory for an example
|
// See GPIO.scala in this directory for an example
|
||||||
|
|
||||||
abstract class TLRegisterRouterBase(val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
abstract class TLRegisterRouterBase(devname: String, devcompat: Seq[String], val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
val device = new SimpleDevice(devname, devcompat)
|
||||||
val intnode = IntSourceNode(interrupts)
|
val node = TLRegisterNode(address, device, "reg", concurrency, beatBytes, undefZero, executable)
|
||||||
|
val intnode = IntSourceNode(IntSourcePortSimple(num = interrupts, resources = Seq(Resource(device, "int"))))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class TLRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[TLBundle])(implicit val p: Parameters)
|
case class TLRegBundleArg(interrupts: util.HeterogeneousBag[Vec[Bool]], in: util.HeterogeneousBag[TLBundle])(implicit val p: Parameters)
|
||||||
@ -106,11 +122,19 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
|
|||||||
def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*)
|
def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp](
|
||||||
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Int = 0, val beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false)
|
val base: BigInt,
|
||||||
|
val devname: String,
|
||||||
|
val devcompat: Seq[String],
|
||||||
|
val interrupts: Int = 0,
|
||||||
|
val size: BigInt = 4096,
|
||||||
|
val concurrency: Int = 0,
|
||||||
|
val beatBytes: Int = 4,
|
||||||
|
val undefZero: Boolean = true,
|
||||||
|
val executable: Boolean = false)
|
||||||
(bundleBuilder: TLRegBundleArg => B)
|
(bundleBuilder: TLRegBundleArg => B)
|
||||||
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)(implicit p: Parameters)
|
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)(implicit p: Parameters)
|
||||||
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero, executable)
|
extends TLRegisterRouterBase(devname, devcompat, AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero, executable)
|
||||||
{
|
{
|
||||||
require (isPow2(size))
|
require (isPow2(size))
|
||||||
// require (size >= 4096) ... not absolutely required, but highly recommended
|
// require (size >= 4096) ... not absolutely required, but highly recommended
|
||||||
|
@ -214,7 +214,7 @@ trait RRTest0Module extends HasRegMap
|
|||||||
regmap(RRTest0Map.map:_*)
|
regmap(RRTest0Map.map:_*)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RRTest0(address: BigInt)(implicit p: Parameters) extends TLRegisterRouter(address, 0, 32, 0, 4)(
|
class RRTest0(address: BigInt)(implicit p: Parameters) extends TLRegisterRouter(address, "test0", Nil, 0, 32, 0, 4)(
|
||||||
new TLRegBundle((), _) with RRTest0Bundle)(
|
new TLRegBundle((), _) with RRTest0Bundle)(
|
||||||
new TLRegModule((), _, _) with RRTest0Module)
|
new TLRegModule((), _, _) with RRTest0Module)
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ trait RRTest1Module extends Module with HasRegMap
|
|||||||
regmap(map:_*)
|
regmap(map:_*)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RRTest1(address: BigInt)(implicit p: Parameters) extends TLRegisterRouter(address, 0, 32, 6, 4)(
|
class RRTest1(address: BigInt)(implicit p: Parameters) extends TLRegisterRouter(address, "test1", Nil, 0, 32, 6, 4)(
|
||||||
new TLRegBundle((), _) with RRTest1Bundle)(
|
new TLRegBundle((), _) with RRTest1Bundle)(
|
||||||
new TLRegModule((), _, _) with RRTest1Module)
|
new TLRegModule((), _, _) with RRTest1Module)
|
||||||
|
|
||||||
|
@ -9,9 +9,12 @@ import util._
|
|||||||
|
|
||||||
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
|
val device = new MemoryDevice
|
||||||
|
|
||||||
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
||||||
Seq(TLManagerParameters(
|
Seq(TLManagerParameters(
|
||||||
address = List(address),
|
address = List(address),
|
||||||
|
resources = device.reg,
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
executable = executable,
|
executable = executable,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
@ -19,6 +19,7 @@ case class TLToAHBNode() extends MixedAdapterNode(TLImp, AHBImp)(
|
|||||||
val managers = slaves.map { case s =>
|
val managers = slaves.map { case s =>
|
||||||
TLManagerParameters(
|
TLManagerParameters(
|
||||||
address = s.address,
|
address = s.address,
|
||||||
|
resources = s.resources,
|
||||||
regionType = s.regionType,
|
regionType = s.regionType,
|
||||||
executable = s.executable,
|
executable = s.executable,
|
||||||
nodePath = s.nodePath,
|
nodePath = s.nodePath,
|
||||||
|
@ -19,6 +19,7 @@ case class TLToAPBNode() extends MixedAdapterNode(TLImp, APBImp)(
|
|||||||
val managers = slaves.map { case s =>
|
val managers = slaves.map { case s =>
|
||||||
TLManagerParameters(
|
TLManagerParameters(
|
||||||
address = s.address,
|
address = s.address,
|
||||||
|
resources = s.resources,
|
||||||
regionType = s.regionType,
|
regionType = s.regionType,
|
||||||
executable = s.executable,
|
executable = s.executable,
|
||||||
nodePath = s.nodePath,
|
nodePath = s.nodePath,
|
||||||
|
@ -23,6 +23,7 @@ case class TLToAXI4Node(idBits: Int) extends MixedAdapterNode(TLImp, AXI4Imp)(
|
|||||||
managers = p.slaves.map { case s =>
|
managers = p.slaves.map { case s =>
|
||||||
TLManagerParameters(
|
TLManagerParameters(
|
||||||
address = s.address,
|
address = s.address,
|
||||||
|
resources = s.resources,
|
||||||
regionType = s.regionType,
|
regionType = s.regionType,
|
||||||
executable = s.executable,
|
executable = s.executable,
|
||||||
nodePath = s.nodePath,
|
nodePath = s.nodePath,
|
||||||
|
@ -8,9 +8,12 @@ import diplomacy._
|
|||||||
|
|
||||||
class TLZero(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
class TLZero(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||||
{
|
{
|
||||||
|
val device = new SimpleDevice("rom", Seq("ucbbar,cacheable-zero"))
|
||||||
|
|
||||||
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
||||||
Seq(TLManagerParameters(
|
Seq(TLManagerParameters(
|
||||||
address = List(address),
|
address = List(address),
|
||||||
|
resources = device.reg,
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
executable = executable,
|
executable = executable,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
|
Loading…
Reference in New Issue
Block a user