commit
46369850cf
@ -49,13 +49,12 @@ trait HasCoreplexParameters {
|
||||
lazy val cbusConfig = p(CBusConfig)
|
||||
lazy val l1tol2Config = p(L1toL2Config)
|
||||
lazy val nTiles = tilesParams.size
|
||||
lazy val hasSupervisor = tilesParams.exists(_.core.useVM) // TODO ask andrew about this
|
||||
lazy val l2Config = p(BankedL2Config)
|
||||
}
|
||||
|
||||
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) {
|
||||
val outer = _outer
|
||||
|
@ -11,6 +11,7 @@ import util._
|
||||
|
||||
trait CoreplexNetwork extends HasCoreplexParameters {
|
||||
val module: CoreplexNetworkModule
|
||||
def bindingTree: ResourceMap
|
||||
|
||||
val l1tol2 = LazyModule(new TLXbar)
|
||||
val l1tol2_beatBytes = l1tol2Config.beatBytes
|
||||
@ -40,6 +41,53 @@ trait CoreplexNetwork extends HasCoreplexParameters {
|
||||
mmio :=
|
||||
TLWidthWidget(l1tol2_beatBytes)(
|
||||
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 {
|
||||
@ -54,16 +102,17 @@ trait CoreplexNetworkModule extends HasCoreplexParameters {
|
||||
val outer: CoreplexNetwork
|
||||
val io: CoreplexNetworkBundle
|
||||
|
||||
println("\nGenerated Address Map")
|
||||
println("Generated Address Map")
|
||||
for (manager <- outer.l1tol2.node.edgesIn(0).manager.managers) {
|
||||
val prot = (if (manager.supportsGet) "R" else "") +
|
||||
(if (manager.supportsPutFull) "W" else "") +
|
||||
(if (manager.executable) "X" else "") +
|
||||
(if (manager.supportsAcquireB) " [C]" else "")
|
||||
manager.address.foreach { a =>
|
||||
println(f"\t${manager.name}%s ${a.base}%x - ${a.base+a.mask+1}%x, $prot")
|
||||
AddressRange.fromSets(manager.address).foreach { r =>
|
||||
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 debug = LazyModule(new TLDebugModule())
|
||||
val plic = LazyModule(new TLPLIC(hasSupervisor, maxPriorities = 7))
|
||||
val plic = LazyModule(new TLPLIC(maxPriorities = 7))
|
||||
val clint = LazyModule(new CoreplexLocalInterrupter)
|
||||
|
||||
debug.node := TLFragmenter(cbus_beatBytes, cbus_lineBytes)(cbus.node)
|
||||
@ -24,10 +24,7 @@ trait CoreplexRISCVPlatform extends CoreplexNetwork {
|
||||
|
||||
plic.intnode := intBar.intnode
|
||||
|
||||
lazy val configString = {
|
||||
val managers = l1tol2.node.edgesIn(0).manager.managers
|
||||
rocketchip.GenerateConfigString(p, clint, plic, managers)
|
||||
}
|
||||
lazy val dts = DTS(bindingTree)
|
||||
}
|
||||
|
||||
trait CoreplexRISCVPlatformBundle extends CoreplexNetworkBundle {
|
||||
@ -50,6 +47,6 @@ trait CoreplexRISCVPlatformModule extends CoreplexNetworkModule {
|
||||
val rtcLast = Reg(init = Bool(false), next=rtcSync)
|
||||
outer.clint.module.io.rtcTick := Reg(init = Bool(false), next=(rtcSync & (~rtcLast)))
|
||||
|
||||
println(s"\nGenerated Configuration String\n${outer.configString}")
|
||||
ElaborationArtefacts.add("cfg", outer.configString)
|
||||
println(outer.dts)
|
||||
ElaborationArtefacts.add("dts", outer.dts)
|
||||
}
|
||||
|
@ -23,16 +23,6 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
private val crossing = p(RocketCrossing)
|
||||
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 pWithExtra = p.alterPartial {
|
||||
case TileKey => c
|
||||
@ -41,50 +31,62 @@ trait HasRocketTiles extends CoreplexRISCVPlatform {
|
||||
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 {
|
||||
case Synchronous => {
|
||||
val tile = LazyModule(new RocketTile(c)(pWithExtra))
|
||||
val tile = LazyModule(new RocketTile(c, i)(pWithExtra))
|
||||
val buffer = LazyModule(new TLBuffer)
|
||||
buffer.node :=* tile.masterNode
|
||||
l1tol2.node :=* buffer.node
|
||||
tile.slaveNode :*= cbus.node
|
||||
tile.intNode := intBar.intnode
|
||||
(io: HasRocketTilesBundle) => {
|
||||
// leave clock as default (simpler for hierarchical PnR)
|
||||
tile.module.io.hartid := UInt(i)
|
||||
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) => {
|
||||
val wrapper = LazyModule(new AsyncRocketTile(c)(pWithExtra))
|
||||
val wrapper = LazyModule(new AsyncRocketTile(c, i)(pWithExtra))
|
||||
val sink = LazyModule(new TLAsyncCrossingSink(depth, sync))
|
||||
val source = LazyModule(new TLAsyncCrossingSource(sync))
|
||||
sink.node :=* wrapper.masterNode
|
||||
l1tol2.node :=* sink.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.intNode := intBar.intnode
|
||||
source.node :*= cbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
wrapper.module.reset := io.tcrs(i).reset
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
wrapper.module.io.resetVector := io.resetVector
|
||||
wireInterrupts(wrapper.module.io.interrupts, i)
|
||||
debugNode.bundleOut(0)(0) := debug.module.io.debugInterrupts(i)
|
||||
}
|
||||
}
|
||||
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 source = LazyModule(new TLRationalCrossingSource)
|
||||
sink.node :=* wrapper.masterNode
|
||||
l1tol2.node :=* sink.node
|
||||
wrapper.slaveNode :*= source.node
|
||||
wrapper.intNode := intBar.intnode
|
||||
source.node :*= cbus.node
|
||||
(io: HasRocketTilesBundle) => {
|
||||
wrapper.module.clock := io.tcrs(i).clock
|
||||
wrapper.module.reset := io.tcrs(i).reset
|
||||
wrapper.module.io.hartid := UInt(i)
|
||||
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)
|
||||
extends MixedNode(inner, outer)(numPO, numPI)
|
||||
{
|
||||
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 (numPO.end >= 1, s"${name} does not accept outputs${lazyModule.line}")
|
||||
// require (numPI.end >= 1, s"${name} does not accept inputs${lazyModule.line}")
|
||||
|
||||
val externalIn: Boolean = true
|
||||
val externalOut: Boolean = true
|
||||
|
@ -76,6 +76,32 @@ object TransferSizes {
|
||||
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
|
||||
// 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
|
||||
@ -132,6 +158,32 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
||||
"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
|
||||
|
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 _ => ""
|
||||
}
|
||||
|
||||
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._
|
||||
|
||||
case class RocketCoreParams(
|
||||
bootFreqHz: BigInt = 0,
|
||||
useVM: Boolean = true,
|
||||
useUser: Boolean = false,
|
||||
useDebug: Boolean = true,
|
||||
|
@ -23,12 +23,85 @@ case class RocketTileParams(
|
||||
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 CanHaveScratchpad { // implies CanHavePTW with HasHellaCache with HasICacheFrontend
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -40,7 +113,6 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
||||
with CanHaveScratchpadModule {
|
||||
|
||||
val core = Module(p(BuildCore)(outer.p))
|
||||
core.io.interrupts := io.interrupts
|
||||
core.io.hartid := io.hartid
|
||||
outer.frontend.module.io.cpu <> core.io.imem
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
val h = dcachePorts.size
|
||||
val c = core.dcacheArbPorts
|
||||
@ -66,8 +145,8 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne
|
||||
ptwOpt foreach { ptw => ptw.io.requestor <> ptwPorts }
|
||||
}
|
||||
|
||||
class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends LazyModule {
|
||||
val rocket = LazyModule(new RocketTile(rtp))
|
||||
class AsyncRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val rocket = LazyModule(new RocketTile(rtp, hartid))
|
||||
|
||||
val masterNode = TLAsyncOutputNode()
|
||||
val source = LazyModule(new TLAsyncCrossingSource)
|
||||
@ -79,23 +158,27 @@ class AsyncRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends Laz
|
||||
rocket.slaveNode :*= sink.node
|
||||
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) {
|
||||
val io = new Bundle {
|
||||
val master = masterNode.bundleOut
|
||||
val slave = slaveNode.bundleIn
|
||||
val interrupts = intNode.bundleIn
|
||||
val hartid = UInt(INPUT, p(XLen))
|
||||
val interrupts = new TileInterrupts()(p).asInput
|
||||
val resetVector = UInt(INPUT, p(XLen))
|
||||
}
|
||||
rocket.module.io.interrupts := ShiftRegister(io.interrupts, 3)
|
||||
// signals that do not change:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
rocket.module.io.resetVector := io.resetVector
|
||||
}
|
||||
}
|
||||
|
||||
class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends LazyModule {
|
||||
val rocket = LazyModule(new RocketTile(rtp))
|
||||
class RationalRocketTile(rtp: RocketTileParams, hartid: Int)(implicit p: Parameters) extends LazyModule {
|
||||
val rocket = LazyModule(new RocketTile(rtp, hartid))
|
||||
|
||||
val masterNode = TLRationalOutputNode()
|
||||
val source = LazyModule(new TLRationalCrossingSource)
|
||||
@ -107,15 +190,19 @@ class RationalRocketTile(rtp: RocketTileParams)(implicit p: Parameters) extends
|
||||
rocket.slaveNode :*= sink.node
|
||||
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) {
|
||||
val io = new Bundle {
|
||||
val master = masterNode.bundleOut
|
||||
val slave = slaveNode.bundleIn
|
||||
val interrupts = intNode.bundleIn
|
||||
val hartid = UInt(INPUT, p(XLen))
|
||||
val interrupts = new TileInterrupts()(p).asInput
|
||||
val resetVector = UInt(INPUT, p(XLen))
|
||||
}
|
||||
rocket.module.io.interrupts := ShiftRegister(io.interrupts, 1)
|
||||
// signals that do not change:
|
||||
rocket.module.io.hartid := io.hartid
|
||||
rocket.module.io.resetVector := io.resetVector
|
||||
|
@ -20,6 +20,10 @@ import DefaultTestSuites._
|
||||
import config._
|
||||
|
||||
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
|
||||
case TLMonitorBuilder => (args: TLMonitorArgs) => Some(LazyModule(new TLMonitor(args)))
|
||||
case TLFuzzReadyValid => false
|
||||
@ -139,6 +143,11 @@ class WithExtMemSize(n: Long) extends Config((site, here, up) => {
|
||||
case ExtMem => up(ExtMem, site).copy(size = n)
|
||||
})
|
||||
|
||||
class WithDTS(model: String, compat: Seq[String]) extends Config((site, here, up) => {
|
||||
case DTSModel => model
|
||||
case DTSCompat => compat
|
||||
})
|
||||
|
||||
class WithScratchpad extends Config(new WithNMemoryChannels(0) ++ new WithDataScratchpad(16384))
|
||||
|
||||
class DefaultFPGASmallConfig extends Config(new WithNSmallCores(1) ++ new DefaultFPGAConfig)
|
||||
|
@ -51,8 +51,14 @@ trait HasPeripheryParameters {
|
||||
trait PeripheryExtInterrupts {
|
||||
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 extInterrupts = IntInternalInputNode(nExtInterrupts)
|
||||
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
||||
val extInterruptXing = LazyModule(new IntXing)
|
||||
|
||||
intBus.intnode := extInterruptXing.intnode
|
||||
@ -84,6 +90,8 @@ trait PeripheryMasterAXI4Mem {
|
||||
private val channels = p(BankedL2Config).nMemoryChannels
|
||||
private val lineBytes = p(CacheBlockBytes)
|
||||
|
||||
private val device = new MemoryDevice
|
||||
|
||||
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(channels) { channel =>
|
||||
val base = AddressSet(config.base, config.size-1)
|
||||
val filter = AddressSet(channel * lineBytes, ~((channels-1) * lineBytes))
|
||||
@ -91,6 +99,7 @@ trait PeripheryMasterAXI4Mem {
|
||||
AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = base.intersect(filter).toList,
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED, // cacheable
|
||||
executable = true,
|
||||
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
||||
@ -160,9 +169,11 @@ trait PeripheryMasterAXI4MMIO {
|
||||
this: HasTopLevelNetworks =>
|
||||
|
||||
private val config = p(ExtBus)
|
||||
private val device = new SimpleDevice("mmio", Nil)
|
||||
val mmio_axi4 = AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
||||
resources = device.reg,
|
||||
executable = true, // Can we run programs on this memory?
|
||||
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
||||
supportsRead = TransferSizes(1, 256),
|
||||
@ -227,9 +238,11 @@ trait PeripheryMasterTLMMIO {
|
||||
this: HasTopLevelNetworks =>
|
||||
|
||||
private val config = p(ExtBus)
|
||||
private val device = new SimpleDevice("mmio", Nil)
|
||||
val mmio_tl = TLBlindOutputNode(Seq(TLManagerPortParameters(
|
||||
managers = Seq(TLManagerParameters(
|
||||
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
||||
resources = device.reg,
|
||||
executable = true,
|
||||
supportsGet = TransferSizes(1, cacheBlockBytes),
|
||||
supportsPutFull = TransferSizes(1, cacheBlockBytes),
|
||||
@ -292,7 +305,7 @@ trait PeripheryBootROM {
|
||||
|
||||
private val bootrom_address = 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))
|
||||
bootrom.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
||||
}
|
||||
|
@ -52,50 +52,18 @@ class GlobalVariable[T] {
|
||||
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 {
|
||||
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 rom = ByteBuffer.wrap(romdata)
|
||||
|
||||
rom.order(ByteOrder.LITTLE_ENDIAN)
|
||||
|
||||
require(address == address.toInt)
|
||||
val configStringAddr = address.toInt + rom.capacity
|
||||
val dtsAddr = address.toInt + rom.capacity
|
||||
require(rom.getInt(12) == 0,
|
||||
"Config string address position should not be occupied by code")
|
||||
rom.putInt(12, configStringAddr)
|
||||
rom.array() ++ (configString.getBytes.toSeq)
|
||||
"DTS address position should not be occupied by code")
|
||||
rom.putInt(12, dtsAddr)
|
||||
rom.array() ++ (dts.getBytes.toSeq)
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +53,13 @@ trait HasTileLinkMasterPort extends HasTileParameters {
|
||||
implicit val p: Parameters
|
||||
val module: HasTileLinkMasterPortModule
|
||||
val masterNode = TLOutputNode()
|
||||
val intNode = IntSinkNode(IntSinkPortSimple())
|
||||
}
|
||||
|
||||
trait HasTileLinkMasterPortBundle {
|
||||
val outer: HasTileLinkMasterPort
|
||||
val master = outer.masterNode.bundleOut
|
||||
val interrupts = outer.intNode.bundleIn
|
||||
}
|
||||
|
||||
trait HasTileLinkMasterPortModule {
|
||||
@ -73,7 +75,6 @@ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends
|
||||
class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer)
|
||||
with HasTileLinkMasterPortBundle {
|
||||
val hartid = UInt(INPUT, p(XLen))
|
||||
val interrupts = new TileInterrupts()(p).asInput
|
||||
val resetVector = UInt(INPUT, p(XLen))
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
||||
|
||||
case class AHBSlaveParameters(
|
||||
address: Seq[AddressSet],
|
||||
resources: Seq[Resource] = Nil,
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
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
|
||||
{
|
||||
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)
|
||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
||||
|
||||
case class APBSlaveParameters(
|
||||
address: Seq[AddressSet],
|
||||
resources: Seq[Resource] = Nil,
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
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
|
||||
{
|
||||
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)
|
||||
|
@ -9,6 +9,7 @@ import scala.math.max
|
||||
|
||||
case class AXI4SlaveParameters(
|
||||
address: Seq[AddressSet],
|
||||
resources: Seq[Resource] = Nil,
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
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
|
||||
{
|
||||
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)
|
||||
|
@ -20,6 +20,7 @@ case class AXI4ToTLNode() extends MixedAdapterNode(AXI4Imp, TLImp)(
|
||||
slaves = mp.managers.map { m =>
|
||||
AXI4SlaveParameters(
|
||||
address = m.address,
|
||||
resources = m.resources,
|
||||
regionType = m.regionType,
|
||||
executable = m.executable,
|
||||
nodePath = m.nodePath,
|
||||
|
@ -849,7 +849,7 @@ trait DebugModule extends Module with HasDebugModuleParameters with HasRegMap {
|
||||
*/
|
||||
|
||||
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 TLRegModule((), _, _) with DebugModule)
|
||||
|
||||
|
@ -53,57 +53,52 @@ object PLICConsts
|
||||
}
|
||||
|
||||
/** 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)
|
||||
|
||||
// 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(
|
||||
address = AddressSet(address, PLICConsts.size-1),
|
||||
device = device,
|
||||
beatBytes = p(XLen)/8,
|
||||
undefZero = false)
|
||||
|
||||
val intnode = IntNexusNode(
|
||||
numSourcePorts = 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())) })
|
||||
|
||||
/* 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 nHarts = intnode.edgesOut.map(_.source.num).sum
|
||||
|
||||
def context(i: Int, mode: Char) = mode match {
|
||||
case 'M' => i * contextsPerHart
|
||||
case 'S' => require(supervisor); i * contextsPerHart + 1
|
||||
}
|
||||
def claimAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode)) + PLICConsts.claimOffset
|
||||
def threshAddr(i: Int, mode: Char) = address + PLICConsts.hartBase(context(i, mode))
|
||||
def enableAddr(i: Int, mode: Char) = address + PLICConsts.enableBase(context(i, mode))
|
||||
// Assign all the devices unique ranges
|
||||
lazy val sources = intnode.edgesIn.map(_.source)
|
||||
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)))
|
||||
}.flatten
|
||||
|
||||
// Create the global PLIC config string
|
||||
lazy val globalConfigString = Seq(
|
||||
s"plic {\n",
|
||||
s" priority 0x${address.toString(16)};\n",
|
||||
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
|
||||
ResourceBinding {
|
||||
flatSources.foreach { s => s.resources.foreach { r =>
|
||||
// +1 because interrupt 0 is reserved
|
||||
(s.range.start until s.range.end).foreach { i => r.bind(device, ResourceInt(i+1)) }
|
||||
} }
|
||||
}
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
@ -113,21 +108,17 @@ class TLPLIC(supervisor: Boolean, maxPriorities: Int, address: BigInt = 0xC00000
|
||||
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
|
||||
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
|
||||
val harts = io.harts.flatten
|
||||
|
||||
println("\nInterrupt map:")
|
||||
println(s"Interrupt map (${nHarts} harts ${nDevices} interrupts):")
|
||||
flatSources.foreach { s =>
|
||||
// +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("")
|
||||
|
||||
require (nDevices == interrupts.size)
|
||||
require (nHarts == harts.size)
|
||||
|
@ -17,11 +17,6 @@ import tile.XLen
|
||||
/** Number of tiles */
|
||||
case object NTiles extends Field[Int]
|
||||
|
||||
class CoreplexLocalInterrupts extends Bundle {
|
||||
val mtip = Bool()
|
||||
val msip = Bool()
|
||||
}
|
||||
|
||||
object ClintConsts
|
||||
{
|
||||
def msipOffset(hart: Int) = hart * msipBytes
|
||||
@ -30,24 +25,38 @@ object ClintConsts
|
||||
def msipBytes = 4
|
||||
def timecmpBytes = 8
|
||||
def size = 0x10000
|
||||
def timeWidth = 64
|
||||
def regWidth = 32
|
||||
def ints = 2
|
||||
}
|
||||
|
||||
trait MixCoreplexLocalInterrupterParameters {
|
||||
implicit val p: Parameters
|
||||
class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
import ClintConsts._
|
||||
|
||||
// clint0 => at most 4095 devices
|
||||
val device = new SimpleDevice("clint", Seq("riscv,clint0")) {
|
||||
override val alwaysExtended = true
|
||||
}
|
||||
|
||||
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
|
||||
val tiles = Vec(p(NTiles), new CoreplexLocalInterrupts).asOutput
|
||||
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 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)))
|
||||
when (io.rtcTick) {
|
||||
val newTime = time.asUInt + UInt(1)
|
||||
@ -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 ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
||||
|
||||
for ((tile, i) <- io.tiles zipWithIndex) {
|
||||
tile.msip := ipi(i)(0)
|
||||
tile.mtip := time.asUInt >= timecmp(i).asUInt
|
||||
io.int.zipWithIndex.foreach { case (int, i) =>
|
||||
int(0) := ipi(i)(0) // msip
|
||||
int(1) := time.asUInt >= timecmp(i).asUInt // mtip
|
||||
}
|
||||
|
||||
/* 0000 msip hart 0
|
||||
@ -73,27 +82,11 @@ trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCorep
|
||||
* 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))
|
||||
}
|
||||
|
||||
/** Power, Reset, Clock, Interrupt */
|
||||
// Magic TL2 Incantation to create a TL2 Slave
|
||||
class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit p: Parameters)
|
||||
extends TLRegisterRouter(address, size = ClintConsts.size, beatBytes = p(XLen)/8, undefZero = true)(
|
||||
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
|
||||
node.regmap(
|
||||
0 -> makeRegFields(ipi),
|
||||
timecmpOffset(0) -> makeRegFields(timecmp.flatten),
|
||||
timeOffset -> makeRegFields(time))
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
val device = new SimpleDevice("rom", Nil)
|
||||
|
||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||
address = List(AddressSet(base, size-1)),
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = executable,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
|
@ -34,6 +34,7 @@ trait ExampleModule extends HasRegMap
|
||||
}
|
||||
|
||||
// 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 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 offset(x: Int) = IntRange(x+start, x+end)
|
||||
}
|
||||
|
||||
object IntRange
|
||||
{
|
||||
implicit def apply(end: Int): IntRange = apply(0, end)
|
||||
@ -25,6 +26,7 @@ object IntRange
|
||||
|
||||
case class IntSourceParameters(
|
||||
range: IntRange,
|
||||
resources: Seq[Resource] = Seq(),
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
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
|
||||
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])
|
||||
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)
|
||||
|
||||
@ -74,10 +87,8 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
|
||||
}
|
||||
|
||||
case class IntIdentityNode() extends IdentityNode(IntImp)
|
||||
case class IntSourceNode(num: Int) extends SourceNode(IntImp)(
|
||||
if (num == 0) Seq() else Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
||||
case class IntSinkNode() extends SinkNode(IntImp)(
|
||||
Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
||||
case class IntSourceNode(portParams: Seq[IntSourcePortParameters]) extends SourceNode(IntImp)(portParams)
|
||||
case class IntSinkNode(portParams: Seq[IntSinkPortParameters]) extends SinkNode(IntImp)(portParams)
|
||||
|
||||
case class IntNexusNode(
|
||||
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
|
||||
@ -89,11 +100,11 @@ case class IntNexusNode(
|
||||
case class IntOutputNode() extends OutputNode(IntImp)
|
||||
case class IntInputNode() extends InputNode(IntImp)
|
||||
|
||||
case class IntBlindOutputNode() extends BlindOutputNode(IntImp)(Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
||||
case class IntBlindInputNode(num: Int) extends BlindInputNode(IntImp)(Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
||||
case class IntBlindOutputNode(portParams: Seq[IntSinkPortParameters]) extends BlindOutputNode(IntImp)(portParams)
|
||||
case class IntBlindInputNode(portParams: Seq[IntSourcePortParameters]) extends BlindInputNode(IntImp)(portParams)
|
||||
|
||||
case class IntInternalOutputNode() extends InternalOutputNode(IntImp)(Seq(IntSinkPortParameters(Seq(IntSinkParameters()))))
|
||||
case class IntInternalInputNode(num: Int) extends InternalInputNode(IntImp)(Seq(IntSourcePortParameters(Seq(IntSourceParameters(num)))))
|
||||
case class IntInternalOutputNode(portParams: Seq[IntSinkPortParameters]) extends InternalOutputNode(IntImp)(portParams)
|
||||
case class IntInternalInputNode(portParams: Seq[IntSourcePortParameters]) extends InternalInputNode(IntImp)(portParams)
|
||||
|
||||
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()
|
||||
|
||||
@ -127,7 +138,7 @@ class IntXing()(implicit p: Parameters) extends LazyModule
|
||||
}
|
||||
|
||||
(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(
|
||||
address: Seq[AddressSet],
|
||||
resources: Seq[Resource] = Seq(),
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
nodePath: Seq[BaseNode] = Seq(),
|
||||
@ -22,8 +23,7 @@ case class TLManagerParameters(
|
||||
supportsPutPartial: 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
|
||||
fifoId: Option[Int] = None,
|
||||
customDTS: Option[String]= None)
|
||||
fifoId: Option[Int] = None)
|
||||
{
|
||||
require (!address.isEmpty)
|
||||
address.foreach { a => require (a.finite) }
|
||||
@ -53,20 +53,16 @@ case class TLManagerParameters(
|
||||
|
||||
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
|
||||
val minAlignment = address.map(_.alignment).min
|
||||
require (minAlignment >= maxTransfer)
|
||||
|
||||
def toResource: ResourceAddress = {
|
||||
ResourceAddress(address,
|
||||
r = supportsAcquireB || supportsGet,
|
||||
w = supportsAcquireT || supportsPutFull,
|
||||
x = executable)
|
||||
}
|
||||
}
|
||||
|
||||
case class TLManagerPortParameters(
|
||||
|
@ -8,10 +8,18 @@ import diplomacy._
|
||||
import regmapper._
|
||||
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(
|
||||
Seq(TLManagerParameters(
|
||||
address = Seq(address),
|
||||
resources = Seq(Resource(device, deviceKey)),
|
||||
executable = executable,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||
@ -72,18 +80,26 @@ class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int =
|
||||
|
||||
object TLRegisterNode
|
||||
{
|
||||
def apply(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true, executable: Boolean = false) =
|
||||
new TLRegisterNode(address, concurrency, beatBytes, undefZero, executable)
|
||||
def apply(
|
||||
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
|
||||
// register mapped device from a totally abstract register mapped device.
|
||||
// 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 intnode = IntSourceNode(interrupts)
|
||||
val device = new SimpleDevice(devname, devcompat)
|
||||
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)
|
||||
@ -106,11 +122,19 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
|
||||
def regmap(mapping: RegField.Map*) = router.node.regmap(mapping:_*)
|
||||
}
|
||||
|
||||
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)
|
||||
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp](
|
||||
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)
|
||||
(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 (size >= 4096) ... not absolutely required, but highly recommended
|
||||
|
@ -214,7 +214,7 @@ trait RRTest0Module extends HasRegMap
|
||||
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 TLRegModule((), _, _) with RRTest0Module)
|
||||
|
||||
@ -251,7 +251,7 @@ trait RRTest1Module extends Module with HasRegMap
|
||||
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 TLRegModule((), _, _) with RRTest1Module)
|
||||
|
||||
|
@ -9,9 +9,12 @@ import util._
|
||||
|
||||
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4)(implicit p: Parameters) extends LazyModule
|
||||
{
|
||||
val device = new MemoryDevice
|
||||
|
||||
val node = TLManagerNode(Seq(TLManagerPortParameters(
|
||||
Seq(TLManagerParameters(
|
||||
address = List(address),
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = executable,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
|
@ -19,6 +19,7 @@ case class TLToAHBNode() extends MixedAdapterNode(TLImp, AHBImp)(
|
||||
val managers = slaves.map { case s =>
|
||||
TLManagerParameters(
|
||||
address = s.address,
|
||||
resources = s.resources,
|
||||
regionType = s.regionType,
|
||||
executable = s.executable,
|
||||
nodePath = s.nodePath,
|
||||
|
@ -19,6 +19,7 @@ case class TLToAPBNode() extends MixedAdapterNode(TLImp, APBImp)(
|
||||
val managers = slaves.map { case s =>
|
||||
TLManagerParameters(
|
||||
address = s.address,
|
||||
resources = s.resources,
|
||||
regionType = s.regionType,
|
||||
executable = s.executable,
|
||||
nodePath = s.nodePath,
|
||||
|
@ -23,6 +23,7 @@ case class TLToAXI4Node(idBits: Int) extends MixedAdapterNode(TLImp, AXI4Imp)(
|
||||
managers = p.slaves.map { case s =>
|
||||
TLManagerParameters(
|
||||
address = s.address,
|
||||
resources = s.resources,
|
||||
regionType = s.regionType,
|
||||
executable = s.executable,
|
||||
nodePath = s.nodePath,
|
||||
|
@ -8,9 +8,12 @@ import diplomacy._
|
||||
|
||||
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(
|
||||
Seq(TLManagerParameters(
|
||||
address = List(address),
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = executable,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
|
Loading…
Reference in New Issue
Block a user