commit
72e8c6f589
@ -3,6 +3,7 @@ package coreplex
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
import junctions._
|
import junctions._
|
||||||
|
import diplomacy._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.coherence._
|
import uncore.coherence._
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import scala.math.{max,min}
|
import scala.math.{max,min}
|
@ -1,17 +1,17 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package diplomacy
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
||||||
|
|
||||||
abstract class LazyModule
|
abstract class LazyModule
|
||||||
{
|
{
|
||||||
protected[tilelink2] var bindings = List[() => Unit]()
|
protected[diplomacy] var bindings = List[() => Unit]()
|
||||||
protected[tilelink2] var children = List[LazyModule]()
|
protected[diplomacy] var children = List[LazyModule]()
|
||||||
protected[tilelink2] var nodes = List[BaseNode]()
|
protected[diplomacy] var nodes = List[BaseNode]()
|
||||||
protected[tilelink2] var info: SourceInfo = UnlocatableSourceInfo
|
protected[diplomacy] var info: SourceInfo = UnlocatableSourceInfo
|
||||||
protected[tilelink2] val parent = LazyModule.stack.headOption
|
protected[diplomacy] val parent = LazyModule.stack.headOption
|
||||||
|
|
||||||
LazyModule.stack = this :: LazyModule.stack
|
LazyModule.stack = this :: LazyModule.stack
|
||||||
parent.foreach(p => p.children = this :: p.children)
|
parent.foreach(p => p.children = this :: p.children)
|
||||||
@ -21,7 +21,7 @@ abstract class LazyModule
|
|||||||
|
|
||||||
def module: LazyModuleImp
|
def module: LazyModuleImp
|
||||||
|
|
||||||
protected[tilelink2] def instantiate() = {
|
protected[diplomacy] def instantiate() = {
|
||||||
children.reverse.foreach { c =>
|
children.reverse.foreach { c =>
|
||||||
// !!! fix chisel3 so we can pass the desired sourceInfo
|
// !!! fix chisel3 so we can pass the desired sourceInfo
|
||||||
// implicit val sourceInfo = c.module.outer.info
|
// implicit val sourceInfo = c.module.outer.info
|
||||||
@ -71,7 +71,7 @@ abstract class LazyModule
|
|||||||
|
|
||||||
object LazyModule
|
object LazyModule
|
||||||
{
|
{
|
||||||
protected[tilelink2] var stack = List[LazyModule]()
|
protected[diplomacy] var stack = List[LazyModule]()
|
||||||
private var index = 0
|
private var index = 0
|
||||||
|
|
||||||
def apply[T <: LazyModule](bc: T)(implicit sourceInfo: SourceInfo): T = {
|
def apply[T <: LazyModule](bc: T)(implicit sourceInfo: SourceInfo): T = {
|
193
src/main/scala/diplomacy/Nodes.scala
Normal file
193
src/main/scala/diplomacy/Nodes.scala
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package diplomacy
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
|
||||||
|
// DI = Downwards flowing Parameters received on the inner side of the node
|
||||||
|
// UI = Upwards flowing Parameters generated by the inner side of the node
|
||||||
|
// EI = Edge Parameters describing a connection on the inner side of the node
|
||||||
|
// BI = Bundle type used when connecting to the inner side of the node
|
||||||
|
trait InwardNodeImp[DI, UI, EI, BI <: Data]
|
||||||
|
{
|
||||||
|
def edgeI(pd: DI, pu: UI): EI
|
||||||
|
def bundleI(ei: Seq[EI]): Vec[BI]
|
||||||
|
def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu
|
||||||
|
def colour: String
|
||||||
|
def connect(bo: => BI, bi: => BI, e: => EI)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO = Downwards flowing Parameters generated by the outner side of the node
|
||||||
|
// UO = Upwards flowing Parameters received on the outner side of the node
|
||||||
|
// EO = Edge Parameters describing a connection on the outer side of the node
|
||||||
|
// BO = Bundle type used when connecting to the outer side of the node
|
||||||
|
trait OutwardNodeImp[DO, UO, EO, BO <: Data]
|
||||||
|
{
|
||||||
|
def edgeO(pd: DO, pu: UO): EO
|
||||||
|
def bundleO(eo: Seq[EO]): Vec[BO]
|
||||||
|
def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NodeImp[D, U, EO, EI, B <: Data]
|
||||||
|
extends Object with InwardNodeImp[D, U, EI, B] with OutwardNodeImp[D, U, EO, B]
|
||||||
|
|
||||||
|
abstract class BaseNode
|
||||||
|
{
|
||||||
|
// You cannot create a Node outside a LazyModule!
|
||||||
|
require (!LazyModule.stack.isEmpty)
|
||||||
|
|
||||||
|
val lazyModule = LazyModule.stack.head
|
||||||
|
val index = lazyModule.nodes.size
|
||||||
|
lazyModule.nodes = this :: lazyModule.nodes
|
||||||
|
|
||||||
|
def name = lazyModule.name + "." + getClass.getName.split('.').last
|
||||||
|
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
||||||
|
|
||||||
|
protected[diplomacy] def outputs: Seq[BaseNode]
|
||||||
|
protected[diplomacy] def inputs: Seq[BaseNode]
|
||||||
|
protected[diplomacy] def colour: String
|
||||||
|
}
|
||||||
|
|
||||||
|
trait InwardNode[DI, UI, BI <: Data] extends BaseNode
|
||||||
|
{
|
||||||
|
protected[diplomacy] val numPI: Range.Inclusive
|
||||||
|
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
||||||
|
require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
|
||||||
|
|
||||||
|
private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI])]()
|
||||||
|
private var iRealized = false
|
||||||
|
|
||||||
|
protected[diplomacy] def iPushed = accPI.size
|
||||||
|
protected[diplomacy] def iPush(index: Int, node: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo) {
|
||||||
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
|
val noIs = numPI.size == 1 && numPI.contains(0)
|
||||||
|
require (!noIs, s"${name}${lazyModule.line} was incorrectly connected as a sink" + info)
|
||||||
|
require (!iRealized, s"${name}${lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info)
|
||||||
|
accPI += ((index, node))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def reqI() = require(numPI.contains(accPI.size), s"${name} has ${accPI.size} inputs, expected ${numPI}${lazyModule.line}")
|
||||||
|
protected[diplomacy] lazy val iPorts = { iRealized = true; reqI(); accPI.result() }
|
||||||
|
|
||||||
|
protected[diplomacy] val iParams: Seq[UI]
|
||||||
|
protected[diplomacy] def iConnect: Vec[BI]
|
||||||
|
}
|
||||||
|
|
||||||
|
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode
|
||||||
|
{
|
||||||
|
protected[diplomacy] val numPO: Range.Inclusive
|
||||||
|
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
||||||
|
require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
|
||||||
|
|
||||||
|
private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO])]()
|
||||||
|
private var oRealized = false
|
||||||
|
|
||||||
|
protected[diplomacy] def oPushed = accPO.size
|
||||||
|
protected[diplomacy] def oPush(index: Int, node: InwardNode [DO, UO, BO])(implicit sourceInfo: SourceInfo) {
|
||||||
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
|
val noOs = numPO.size == 1 && numPO.contains(0)
|
||||||
|
require (!noOs, s"${name}${lazyModule.line} was incorrectly connected as a source" + info)
|
||||||
|
require (!oRealized, s"${name}${lazyModule.line} was incorrectly connected as a source after it's .module was used" + info)
|
||||||
|
accPO += ((index, node))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}")
|
||||||
|
protected[diplomacy] lazy val oPorts = { oRealized = true; reqO(); accPO.result() }
|
||||||
|
|
||||||
|
protected[diplomacy] val oParams: Seq[DO]
|
||||||
|
protected[diplomacy] def oConnect: Vec[BO]
|
||||||
|
}
|
||||||
|
|
||||||
|
class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
||||||
|
inner: InwardNodeImp [DI, UI, EI, BI],
|
||||||
|
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
||||||
|
private val dFn: (Int, Seq[DI]) => Seq[DO],
|
||||||
|
private val uFn: (Int, Seq[UO]) => Seq[UI],
|
||||||
|
protected[diplomacy] val numPO: Range.Inclusive,
|
||||||
|
protected[diplomacy] val numPI: Range.Inclusive)
|
||||||
|
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
||||||
|
{
|
||||||
|
// meta-data for printing the node graph
|
||||||
|
protected[diplomacy] def colour = inner.colour
|
||||||
|
protected[diplomacy] def outputs = oPorts.map(_._2)
|
||||||
|
protected[diplomacy] def inputs = iPorts.map(_._2)
|
||||||
|
|
||||||
|
private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}")
|
||||||
|
protected[diplomacy] lazy val oParams: Seq[DO] = {
|
||||||
|
val o = dFn(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) })
|
||||||
|
reqE(oPorts.size, o.size)
|
||||||
|
o.map(outer.mixO(_, this))
|
||||||
|
}
|
||||||
|
protected[diplomacy] lazy val iParams: Seq[UI] = {
|
||||||
|
val i = uFn(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) })
|
||||||
|
reqE(i.size, iPorts.size)
|
||||||
|
i.map(inner.mixI(_, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => outer.edgeO(o, n.iParams(i)) }
|
||||||
|
lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => inner.edgeI(n.oParams(o), i) }
|
||||||
|
|
||||||
|
lazy val bundleOut = outer.bundleO(edgesOut)
|
||||||
|
lazy val bundleIn = inner.bundleI(edgesIn)
|
||||||
|
|
||||||
|
def oConnect = bundleOut
|
||||||
|
def iConnect = bundleIn
|
||||||
|
|
||||||
|
// connects the outward part of a node with the inward part of this node
|
||||||
|
def := (y: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
|
||||||
|
val x = this // x := y
|
||||||
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
|
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
||||||
|
val i = x.iPushed
|
||||||
|
val o = y.oPushed
|
||||||
|
y.oPush(i, x)
|
||||||
|
x.iPush(o, y)
|
||||||
|
val (out, binding) = inner.connect(y.oConnect(o), x.iConnect(i), x.edgesIn(i))
|
||||||
|
LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
||||||
|
oFn: (Int, Seq[D]) => Seq[D],
|
||||||
|
iFn: (Int, Seq[U]) => Seq[U],
|
||||||
|
numPO: Range.Inclusive,
|
||||||
|
numPI: Range.Inclusive)
|
||||||
|
extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI)
|
||||||
|
|
||||||
|
class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
||||||
|
extends SimpleNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999)
|
||||||
|
|
||||||
|
class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
||||||
|
{
|
||||||
|
override def oConnect = bundleOut
|
||||||
|
override def iConnect = bundleOut
|
||||||
|
}
|
||||||
|
|
||||||
|
class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
||||||
|
{
|
||||||
|
override def oConnect = bundleIn
|
||||||
|
override def iConnect = bundleIn
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1)
|
||||||
|
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0)
|
||||||
|
{
|
||||||
|
require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}")
|
||||||
|
}
|
||||||
|
|
||||||
|
class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1)
|
||||||
|
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num)
|
||||||
|
{
|
||||||
|
require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}")
|
||||||
|
}
|
||||||
|
|
||||||
|
class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
||||||
|
(oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive)
|
||||||
|
extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI)
|
||||||
|
{
|
||||||
|
require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}")
|
||||||
|
require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}")
|
||||||
|
}
|
146
src/main/scala/diplomacy/Parameters.scala
Normal file
146
src/main/scala/diplomacy/Parameters.scala
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package diplomacy
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
import scala.math.max
|
||||||
|
|
||||||
|
/** Options for memory regions */
|
||||||
|
object RegionType {
|
||||||
|
sealed trait T
|
||||||
|
case object CACHED extends T
|
||||||
|
case object TRACKED extends T
|
||||||
|
case object UNCACHED extends T
|
||||||
|
case object PUT_EFFECTS extends T
|
||||||
|
case object GET_EFFECTS extends T // GET_EFFECTS => PUT_EFFECTS
|
||||||
|
val cases = Seq(CACHED, TRACKED, UNCACHED, PUT_EFFECTS, GET_EFFECTS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A non-empty half-open range; [start, end)
|
||||||
|
case class IdRange(start: Int, end: Int)
|
||||||
|
{
|
||||||
|
require (start >= 0)
|
||||||
|
require (start < end) // not empty
|
||||||
|
|
||||||
|
// This is a strict partial ordering
|
||||||
|
def <(x: IdRange) = end <= x.start
|
||||||
|
def >(x: IdRange) = x < this
|
||||||
|
|
||||||
|
def overlaps(x: IdRange) = start < x.end && x.start < end
|
||||||
|
def contains(x: IdRange) = start <= x.start && x.end <= end
|
||||||
|
// contains => overlaps (because empty is forbidden)
|
||||||
|
|
||||||
|
def contains(x: Int) = start <= x && x < end
|
||||||
|
def contains(x: UInt) =
|
||||||
|
if (start+1 == end) { UInt(start) === x }
|
||||||
|
else if (isPow2(end-start) && ((end | start) & (end-start-1)) == 0)
|
||||||
|
{ ~(~(UInt(start) ^ x) | UInt(end-start-1)) === UInt(0) }
|
||||||
|
else { UInt(start) <= x && x < UInt(end) }
|
||||||
|
|
||||||
|
def shift(x: Int) = IdRange(start+x, end+x)
|
||||||
|
def size = end - start
|
||||||
|
}
|
||||||
|
|
||||||
|
// An potentially empty inclusive range of 2-powers [min, max] (in bytes)
|
||||||
|
case class TransferSizes(min: Int, max: Int)
|
||||||
|
{
|
||||||
|
def this(x: Int) = this(x, x)
|
||||||
|
|
||||||
|
require (min <= max)
|
||||||
|
require (min >= 0 && max >= 0)
|
||||||
|
require (max == 0 || isPow2(max))
|
||||||
|
require (min == 0 || isPow2(min))
|
||||||
|
require (max == 0 || min != 0) // 0 is forbidden unless (0,0)
|
||||||
|
|
||||||
|
def none = min == 0
|
||||||
|
def contains(x: Int) = isPow2(x) && min <= x && x <= max
|
||||||
|
def containsLg(x: Int) = contains(1 << x)
|
||||||
|
def containsLg(x: UInt) =
|
||||||
|
if (none) Bool(false)
|
||||||
|
else if (min == max) { UInt(log2Ceil(min)) === x }
|
||||||
|
else { UInt(log2Ceil(min)) <= x && x <= UInt(log2Ceil(max)) }
|
||||||
|
|
||||||
|
def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
||||||
|
|
||||||
|
def intersect(x: TransferSizes) =
|
||||||
|
if (x.max < min || max < x.min) TransferSizes.none
|
||||||
|
else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max))
|
||||||
|
}
|
||||||
|
|
||||||
|
object TransferSizes {
|
||||||
|
def apply(x: Int) = new TransferSizes(x)
|
||||||
|
val none = new TransferSizes(0)
|
||||||
|
|
||||||
|
implicit def asBool(x: TransferSizes) = !x.none
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
||||||
|
case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
||||||
|
{
|
||||||
|
// Forbid misaligned base address (and empty sets)
|
||||||
|
require ((base & mask) == 0)
|
||||||
|
require (base >= 0) // TL2 address widths are not fixed => negative is ambiguous
|
||||||
|
// We do allow negative mask (=> ignore all high bits)
|
||||||
|
|
||||||
|
def contains(x: BigInt) = ((x ^ base) & ~mask) == 0
|
||||||
|
def contains(x: UInt) = ((x ^ UInt(base)).zext() & SInt(~mask)) === SInt(0)
|
||||||
|
|
||||||
|
// overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1)
|
||||||
|
def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0
|
||||||
|
// contains iff bitwise: x.mask => mask && contains(x.base)
|
||||||
|
def contains(x: AddressSet) = ((x.mask | (base ^ x.base)) & ~mask) == 0
|
||||||
|
|
||||||
|
// The number of bytes to which the manager must be aligned
|
||||||
|
def alignment = ((mask + 1) & ~mask)
|
||||||
|
// Is this a contiguous memory range
|
||||||
|
def contiguous = alignment == mask+1
|
||||||
|
|
||||||
|
def finite = mask >= 0
|
||||||
|
def max = { require (finite); base | mask }
|
||||||
|
|
||||||
|
// Widen the match function to ignore all bits in imask
|
||||||
|
def widen(imask: BigInt) = AddressSet(base & ~imask, mask | imask)
|
||||||
|
|
||||||
|
// AddressSets have one natural Ordering (the containment order, if contiguous)
|
||||||
|
def compare(x: AddressSet) = {
|
||||||
|
val primary = (this.base - x.base).signum // smallest address first
|
||||||
|
val secondary = (x.mask - this.mask).signum // largest mask first
|
||||||
|
if (primary != 0) primary else secondary
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always want to see things in hex
|
||||||
|
override def toString() = {
|
||||||
|
if (mask >= 0) {
|
||||||
|
"AddressSet(0x%x, 0x%x)".format(base, mask)
|
||||||
|
} else {
|
||||||
|
"AddressSet(0x%x, ~0x%x)".format(base, ~mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AddressSet
|
||||||
|
{
|
||||||
|
def misaligned(base: BigInt, size: BigInt): Seq[AddressSet] = {
|
||||||
|
val largestPow2 = BigInt(1) << log2Floor(size)
|
||||||
|
val mostZeros = (base + size - 1) & ~(largestPow2 - 1)
|
||||||
|
def splitLo(low: BigInt, high: BigInt, tail: Seq[AddressSet]): Seq[AddressSet] = {
|
||||||
|
if (low == high) tail else {
|
||||||
|
val toggleBits = low ^ high
|
||||||
|
val misalignment = toggleBits & (-toggleBits)
|
||||||
|
splitLo(low+misalignment, high, AddressSet(low, misalignment-1) +: tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def splitHi(low: BigInt, high: BigInt, tail: Seq[AddressSet]): Seq[AddressSet] = {
|
||||||
|
if (low == high) tail else {
|
||||||
|
val toggleBits = low ^ high
|
||||||
|
val misalignment = toggleBits & (-toggleBits)
|
||||||
|
splitHi(low, high-misalignment, AddressSet(high-misalignment, misalignment-1) +: tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
splitLo(base, mostZeros, splitHi(mostZeros, base+size, Seq())).sorted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
10
src/main/scala/diplomacy/package.scala
Normal file
10
src/main/scala/diplomacy/package.scala
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Chisel._
|
||||||
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
||||||
|
|
||||||
|
package object diplomacy
|
||||||
|
{
|
||||||
|
def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match {
|
||||||
|
case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
|
||||||
|
case _ => ""
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package groundtest
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import rocket._
|
import rocket._
|
||||||
|
import diplomacy._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.coherence._
|
import uncore.coherence._
|
||||||
import uncore.agents._
|
import uncore.agents._
|
||||||
@ -72,7 +73,7 @@ class Edge32BitMemtestConfig extends Config(
|
|||||||
class WithGroundTest extends Config(
|
class WithGroundTest extends Config(
|
||||||
(pname, site, here) => pname match {
|
(pname, site, here) => pname match {
|
||||||
case BuildCoreplex =>
|
case BuildCoreplex =>
|
||||||
(c: CoreplexConfig, p: Parameters) => uncore.tilelink2.LazyModule(new GroundTestCoreplex(c)(p)).module
|
(c: CoreplexConfig, p: Parameters) => LazyModule(new GroundTestCoreplex(c)(p)).module
|
||||||
case TLKey("L1toL2") => {
|
case TLKey("L1toL2") => {
|
||||||
val useMEI = site(NTiles) <= 1 && site(NCachedTileLinkPorts) <= 1
|
val useMEI = site(NTiles) <= 1 && site(NCachedTileLinkPorts) <= 1
|
||||||
val dataBeats = (8 * site(CacheBlockBytes)) / site(XLen)
|
val dataBeats = (8 * site(CacheBlockBytes)) / site(XLen)
|
||||||
@ -105,7 +106,7 @@ class WithGroundTest extends Config(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case BuildExampleTop =>
|
case BuildExampleTop =>
|
||||||
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTopWithTestRAM(p))
|
(p: Parameters) => LazyModule(new ExampleTopWithTestRAM(p))
|
||||||
case FPUKey => None
|
case FPUKey => None
|
||||||
case UseAtomics => false
|
case UseAtomics => false
|
||||||
case UseCompressed => false
|
case UseCompressed => false
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package regmapper
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{ReadyValidIO}
|
import chisel3.util.{ReadyValidIO}
|
@ -1,8 +1,10 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package regmapper
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
import util.{GenericParameterizedBundle}
|
||||||
|
|
||||||
// A bus agnostic register interface to a register-based device
|
// A bus agnostic register interface to a register-based device
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
// See LICENSE for license details.
|
// See LICENSE for license details.
|
||||||
|
|
||||||
package uncore.tilelink2
|
package regmapper
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{Irrevocable}
|
import chisel3.util.{Irrevocable}
|
||||||
import util.{AsyncResetRegVec, AsyncQueue, AsyncScope}
|
import util.{AsyncQueue,AsyncScope,AsyncResetRegVec}
|
||||||
|
|
||||||
// A very simple flow control state machine, run in the specified clock domain
|
// A very simple flow control state machine, run in the specified clock domain
|
||||||
class BusyRegisterCrossing(clock: Clock, reset: Bool)
|
class BusyRegisterCrossing(clock: Clock, reset: Bool)
|
@ -5,6 +5,7 @@ package rocketchip
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
import junctions._
|
import junctions._
|
||||||
|
import diplomacy._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
|
@ -5,9 +5,9 @@ package rocketchip
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import junctions._
|
import junctions._
|
||||||
import rocket._
|
import rocket._
|
||||||
|
import diplomacy._
|
||||||
import uncore.agents._
|
import uncore.agents._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2.{LazyModule}
|
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import uncore.converters._
|
import uncore.converters._
|
||||||
import util._
|
import util._
|
||||||
@ -40,7 +40,7 @@ class BasePlatformConfig extends Config(
|
|||||||
case TLKey("MMIOtoEdge") =>
|
case TLKey("MMIOtoEdge") =>
|
||||||
site(TLKey("L2toMMIO")).copy(dataBeats = edgeDataBeats)
|
site(TLKey("L2toMMIO")).copy(dataBeats = edgeDataBeats)
|
||||||
case BuildCoreplex =>
|
case BuildCoreplex =>
|
||||||
(c: CoreplexConfig, p: Parameters) => uncore.tilelink2.LazyModule(new DefaultCoreplex(c)(p)).module
|
(c: CoreplexConfig, p: Parameters) => LazyModule(new DefaultCoreplex(c)(p)).module
|
||||||
case NExtTopInterrupts => 2
|
case NExtTopInterrupts => 2
|
||||||
case PeripheryBusKey => PeripheryBusConfig(arithAMO = true, beatBytes = 4)
|
case PeripheryBusKey => PeripheryBusConfig(arithAMO = true, beatBytes = 4)
|
||||||
// Note that PLIC asserts that this is > 0.
|
// Note that PLIC asserts that this is > 0.
|
||||||
@ -68,7 +68,7 @@ class BasePlatformConfig extends Config(
|
|||||||
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
||||||
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
||||||
case BuildExampleTop =>
|
case BuildExampleTop =>
|
||||||
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTop(p))
|
(p: Parameters) => LazyModule(new ExampleTop(p))
|
||||||
case SimMemLatency => 0
|
case SimMemLatency => 0
|
||||||
case _ => throw new CDEMatchError
|
case _ => throw new CDEMatchError
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import Chisel._
|
|||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
import junctions._
|
import junctions._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
|
import diplomacy._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.converters._
|
import uncore.converters._
|
||||||
|
@ -4,6 +4,7 @@ package rocketchip
|
|||||||
|
|
||||||
import cde.{Parameters, Dump}
|
import cde.{Parameters, Dump}
|
||||||
import junctions._
|
import junctions._
|
||||||
|
import diplomacy._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import rocket._
|
import rocket._
|
||||||
import coreplex._
|
import coreplex._
|
||||||
|
@ -5,6 +5,7 @@ package uncore.devices
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import junctions._
|
import junctions._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
|
import regmapper._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
import util._
|
import util._
|
||||||
|
@ -3,6 +3,7 @@ package uncore.devices
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import unittest.UnitTest
|
import unittest.UnitTest
|
||||||
import junctions._
|
import junctions._
|
||||||
|
import diplomacy._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2._
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.IrrevocableIO
|
import chisel3.util.IrrevocableIO
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
object TLArbiter
|
object TLArbiter
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
// Ensures that all downstream RW managers support Atomic operationss.
|
// Ensures that all downstream RW managers support Atomic operationss.
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
// pipe is only used if a queue has depth = 1
|
// pipe is only used if a queue has depth = 1
|
||||||
|
@ -4,22 +4,8 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.{Irrevocable, IrrevocableIO, ReadyValidIO}
|
import chisel3.util.{Irrevocable, IrrevocableIO, ReadyValidIO}
|
||||||
import util.{AsyncQueueSource, AsyncQueueSink}
|
import diplomacy._
|
||||||
|
import util.{AsyncQueueSource, AsyncQueueSink, GenericParameterizedBundle}
|
||||||
abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle
|
|
||||||
{
|
|
||||||
override def cloneType = {
|
|
||||||
try {
|
|
||||||
this.getClass.getConstructors.head.newInstance(params).asInstanceOf[this.type]
|
|
||||||
} catch {
|
|
||||||
case e: java.lang.IllegalArgumentException =>
|
|
||||||
throw new Exception("Unable to use GenericParameterizedBundle.cloneType on " +
|
|
||||||
this.getClass + ", probably because " + this.getClass +
|
|
||||||
"() takes more than one argument. Consider overriding " +
|
|
||||||
"cloneType() on " + this.getClass, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class TLBundleBase(params: TLBundleParameters) extends GenericParameterizedBundle(params)
|
abstract class TLBundleBase(params: TLBundleParameters) extends GenericParameterizedBundle(params)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
import util._
|
import util._
|
||||||
|
|
||||||
class TLAsyncCrossingSource(sync: Int = 3) extends LazyModule
|
class TLAsyncCrossingSource(sync: Int = 3) extends LazyModule
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class TLEdge(
|
class TLEdge(
|
||||||
client: TLClientPortParameters,
|
client: TLClientPortParameters,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import regmapper._
|
||||||
|
|
||||||
case class ExampleParams(num: Int, address: BigInt)
|
case class ExampleParams(num: Int, address: BigInt)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
// minSize: minimum size of transfers supported by all outward managers
|
// minSize: minimum size of transfers supported by all outward managers
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class IDMapGenerator(numIds: Int) extends Module {
|
class IDMapGenerator(numIds: Int) extends Module {
|
||||||
val w = log2Up(numIds)
|
val w = log2Up(numIds)
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
// Acks Hints for managers that don't support them or Acks all Hints if !passthrough
|
// Acks Hints for managers that don't support them or Acks all Hints if !passthrough
|
||||||
class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule
|
class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true) extends LazyModule
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
|
||||||
|
|
||||||
// A potentially empty half-open range; [start, end)
|
// A potentially empty half-open range; [start, end)
|
||||||
case class IntRange(start: Int, end: Int)
|
case class IntRange(start: Int, end: Int)
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class TLIsolation(f: (Bool, UInt) => UInt) extends LazyModule
|
class TLIsolation(f: (Bool, UInt) => UInt) extends LazyModule
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
import cde.Parameters
|
import cde.Parameters
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.constants._
|
import uncore.constants._
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine}
|
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine}
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: SourceInfo) extends LazyModule
|
class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: SourceInfo) extends LazyModule
|
||||||
{
|
{
|
||||||
|
@ -3,191 +3,124 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
|
import diplomacy._
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
// DI = Downwards flowing Parameters received on the inner side of the node
|
object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
||||||
// UI = Upwards flowing Parameters generated by the inner side of the node
|
|
||||||
// EI = Edge Parameters describing a connection on the inner side of the node
|
|
||||||
// BI = Bundle type used when connecting to the inner side of the node
|
|
||||||
trait InwardNodeImp[DI, UI, EI, BI <: Data]
|
|
||||||
{
|
{
|
||||||
def edgeI(pd: DI, pu: UI): EI
|
def edgeO(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(pd, pu)
|
||||||
def bundleI(ei: Seq[EI]): Vec[BI]
|
def edgeI(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(pd, pu)
|
||||||
def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu
|
def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = {
|
||||||
def colour: String
|
require (!eo.isEmpty)
|
||||||
def connect(bo: => BI, bi: => BI, e: => EI)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit)
|
Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_))))
|
||||||
|
}
|
||||||
|
def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = {
|
||||||
|
require (!ei.isEmpty)
|
||||||
|
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip
|
||||||
}
|
}
|
||||||
|
|
||||||
// DO = Downwards flowing Parameters generated by the outner side of the node
|
def colour = "#000000" // black
|
||||||
// UO = Upwards flowing Parameters received on the outner side of the node
|
def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||||
// EO = Edge Parameters describing a connection on the outer side of the node
|
val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => ei, sourceInfo))
|
||||||
// BO = Bundle type used when connecting to the outer side of the node
|
(Some(monitor), () => {
|
||||||
trait OutwardNodeImp[DO, UO, EO, BO <: Data]
|
bi <> bo
|
||||||
|
monitor.module.io.in := TLBundleSnoop(bo)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters =
|
||||||
|
pd.copy(clients = pd.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
|
||||||
|
override def mixI(pu: TLManagerPortParameters, node: InwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLManagerPortParameters =
|
||||||
|
pu.copy(managers = pu.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
|
||||||
|
}
|
||||||
|
|
||||||
|
case class TLIdentityNode() extends IdentityNode(TLImp)
|
||||||
|
case class TLOutputNode() extends OutputNode(TLImp)
|
||||||
|
case class TLInputNode() extends InputNode(TLImp)
|
||||||
|
|
||||||
|
case class TLClientNode(portParams: TLClientPortParameters, numPorts: Range.Inclusive = 1 to 1)
|
||||||
|
extends SourceNode(TLImp)(portParams, numPorts)
|
||||||
|
case class TLManagerNode(portParams: TLManagerPortParameters, numPorts: Range.Inclusive = 1 to 1)
|
||||||
|
extends SinkNode(TLImp)(portParams, numPorts)
|
||||||
|
|
||||||
|
object TLClientNode
|
||||||
{
|
{
|
||||||
def edgeO(pd: DO, pu: UO): EO
|
def apply(params: TLClientParameters) =
|
||||||
def bundleO(eo: Seq[EO]): Vec[BO]
|
new TLClientNode(TLClientPortParameters(Seq(params)), 1 to 1)
|
||||||
def mixO(pd: DO, node: OutwardNode[DO, UO, BO]): DO = pd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class NodeImp[D, U, EO, EI, B <: Data]
|
object TLManagerNode
|
||||||
extends Object with InwardNodeImp[D, U, EI, B] with OutwardNodeImp[D, U, EO, B]
|
|
||||||
|
|
||||||
abstract class BaseNode
|
|
||||||
{
|
{
|
||||||
// You cannot create a Node outside a LazyModule!
|
def apply(beatBytes: Int, params: TLManagerParameters) =
|
||||||
require (!LazyModule.stack.isEmpty)
|
new TLManagerNode(TLManagerPortParameters(Seq(params), beatBytes, 0), 1 to 1)
|
||||||
|
|
||||||
val lazyModule = LazyModule.stack.head
|
|
||||||
val index = lazyModule.nodes.size
|
|
||||||
lazyModule.nodes = this :: lazyModule.nodes
|
|
||||||
|
|
||||||
def name = lazyModule.name + "." + getClass.getName.split('.').last
|
|
||||||
def omitGraphML = outputs.isEmpty && inputs.isEmpty
|
|
||||||
|
|
||||||
protected[tilelink2] def outputs: Seq[BaseNode]
|
|
||||||
protected[tilelink2] def inputs: Seq[BaseNode]
|
|
||||||
protected[tilelink2] def colour: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait InwardNode[DI, UI, BI <: Data] extends BaseNode
|
case class TLAdapterNode(
|
||||||
|
clientFn: Seq[TLClientPortParameters] => TLClientPortParameters,
|
||||||
|
managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters,
|
||||||
|
numClientPorts: Range.Inclusive = 1 to 1,
|
||||||
|
numManagerPorts: Range.Inclusive = 1 to 1)
|
||||||
|
extends InteriorNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
|
||||||
|
|
||||||
|
/** Synthesizeable unit tests */
|
||||||
|
import unittest._
|
||||||
|
|
||||||
|
class TLInputNodeTest extends UnitTest(500000) {
|
||||||
|
class Acceptor extends LazyModule {
|
||||||
|
val node = TLInputNode()
|
||||||
|
val tlram = LazyModule(new TLRAM(AddressSet(0x54321000, 0xfff)))
|
||||||
|
tlram.node := node
|
||||||
|
|
||||||
|
lazy val module = new LazyModuleImp(this) {
|
||||||
|
val io = new Bundle {
|
||||||
|
val in = node.bundleIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val fuzzer = LazyModule(new TLFuzzer(5000))
|
||||||
|
LazyModule(new Acceptor).node := TLFragmenter(4, 64)(fuzzer.node)
|
||||||
|
|
||||||
|
io.finished := Module(fuzzer.module).io.finished
|
||||||
|
}
|
||||||
|
|
||||||
|
object TLAsyncImp extends NodeImp[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncEdgeParameters, TLAsyncEdgeParameters, TLAsyncBundle]
|
||||||
{
|
{
|
||||||
protected[tilelink2] val numPI: Range.Inclusive
|
def edgeO(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
||||||
require (!numPI.isEmpty, s"No number of inputs would be acceptable to ${name}${lazyModule.line}")
|
def edgeI(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
||||||
require (numPI.start >= 0, s"${name} accepts a negative number of inputs${lazyModule.line}")
|
def bundleO(eo: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
||||||
|
require (eo.size == 1)
|
||||||
private val accPI = ListBuffer[(Int, OutwardNode[DI, UI, BI])]()
|
Vec(eo.size, new TLAsyncBundle(eo(0).bundle))
|
||||||
private var iRealized = false
|
}
|
||||||
|
def bundleI(ei: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
||||||
protected[tilelink2] def iPushed = accPI.size
|
require (ei.size == 1)
|
||||||
protected[tilelink2] def iPush(index: Int, node: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo) {
|
Vec(ei.size, new TLAsyncBundle(ei(0).bundle)).flip
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
|
||||||
val noIs = numPI.size == 1 && numPI.contains(0)
|
|
||||||
require (!noIs, s"${name}${lazyModule.line} was incorrectly connected as a sink" + info)
|
|
||||||
require (!iRealized, s"${name}${lazyModule.line} was incorrectly connected as a sink after it's .module was used" + info)
|
|
||||||
accPI += ((index, node))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def reqI() = require(numPI.contains(accPI.size), s"${name} has ${accPI.size} inputs, expected ${numPI}${lazyModule.line}")
|
def colour = "#ff0000" // red
|
||||||
protected[tilelink2] lazy val iPorts = { iRealized = true; reqI(); accPI.result() }
|
def connect(bo: => TLAsyncBundle, bi: => TLAsyncBundle, ei: => TLAsyncEdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||||
|
(None, () => { bi <> bo })
|
||||||
protected[tilelink2] val iParams: Seq[UI]
|
|
||||||
protected[tilelink2] def iConnect: Vec[BI]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trait OutwardNode[DO, UO, BO <: Data] extends BaseNode
|
override def mixO(pd: TLAsyncClientPortParameters, node: OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncClientPortParameters =
|
||||||
{
|
pd.copy(base = pd.base.copy(clients = pd.base.clients.map { c => c.copy (nodePath = node +: c.nodePath) }))
|
||||||
protected[tilelink2] val numPO: Range.Inclusive
|
override def mixI(pu: TLAsyncManagerPortParameters, node: InwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncManagerPortParameters =
|
||||||
require (!numPO.isEmpty, s"No number of outputs would be acceptable to ${name}${lazyModule.line}")
|
pu.copy(base = pu.base.copy(managers = pu.base.managers.map { m => m.copy (nodePath = node +: m.nodePath) }))
|
||||||
require (numPO.start >= 0, s"${name} accepts a negative number of outputs${lazyModule.line}")
|
|
||||||
|
|
||||||
private val accPO = ListBuffer[(Int, InwardNode [DO, UO, BO])]()
|
|
||||||
private var oRealized = false
|
|
||||||
|
|
||||||
protected[tilelink2] def oPushed = accPO.size
|
|
||||||
protected[tilelink2] def oPush(index: Int, node: InwardNode [DO, UO, BO])(implicit sourceInfo: SourceInfo) {
|
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
|
||||||
val noOs = numPO.size == 1 && numPO.contains(0)
|
|
||||||
require (!noOs, s"${name}${lazyModule.line} was incorrectly connected as a source" + info)
|
|
||||||
require (!oRealized, s"${name}${lazyModule.line} was incorrectly connected as a source after it's .module was used" + info)
|
|
||||||
accPO += ((index, node))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private def reqO() = require(numPO.contains(accPO.size), s"${name} has ${accPO.size} outputs, expected ${numPO}${lazyModule.line}")
|
case class TLAsyncIdentityNode() extends IdentityNode(TLAsyncImp)
|
||||||
protected[tilelink2] lazy val oPorts = { oRealized = true; reqO(); accPO.result() }
|
case class TLAsyncOutputNode() extends OutputNode(TLAsyncImp)
|
||||||
|
case class TLAsyncInputNode() extends InputNode(TLAsyncImp)
|
||||||
|
|
||||||
protected[tilelink2] val oParams: Seq[DO]
|
case class TLAsyncSourceNode() extends MixedNode(TLImp, TLAsyncImp)(
|
||||||
protected[tilelink2] def oConnect: Vec[BO]
|
dFn = { case (1, s) => s.map(TLAsyncClientPortParameters(_)) },
|
||||||
}
|
uFn = { case (1, s) => s.map(_.base) },
|
||||||
|
numPO = 1 to 1,
|
||||||
|
numPI = 1 to 1)
|
||||||
|
|
||||||
class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data](
|
case class TLAsyncSinkNode(depth: Int) extends MixedNode(TLAsyncImp, TLImp)(
|
||||||
inner: InwardNodeImp [DI, UI, EI, BI],
|
dFn = { case (1, s) => s.map(_.base) },
|
||||||
outer: OutwardNodeImp[DO, UO, EO, BO])(
|
uFn = { case (1, s) => s.map(TLAsyncManagerPortParameters(depth, _)) },
|
||||||
private val dFn: (Int, Seq[DI]) => Seq[DO],
|
numPO = 1 to 1,
|
||||||
private val uFn: (Int, Seq[UO]) => Seq[UI],
|
numPI = 1 to 1)
|
||||||
protected[tilelink2] val numPO: Range.Inclusive,
|
|
||||||
protected[tilelink2] val numPI: Range.Inclusive)
|
|
||||||
extends BaseNode with InwardNode[DI, UI, BI] with OutwardNode[DO, UO, BO]
|
|
||||||
{
|
|
||||||
// meta-data for printing the node graph
|
|
||||||
protected[tilelink2] def colour = inner.colour
|
|
||||||
protected[tilelink2] def outputs = oPorts.map(_._2)
|
|
||||||
protected[tilelink2] def inputs = iPorts.map(_._2)
|
|
||||||
|
|
||||||
private def reqE(o: Int, i: Int) = require(i == o, s"${name} has ${i} inputs and ${o} outputs; they must match${lazyModule.line}")
|
|
||||||
protected[tilelink2] lazy val oParams: Seq[DO] = {
|
|
||||||
val o = dFn(oPorts.size, iPorts.map { case (i, n) => n.oParams(i) })
|
|
||||||
reqE(oPorts.size, o.size)
|
|
||||||
o.map(outer.mixO(_, this))
|
|
||||||
}
|
|
||||||
protected[tilelink2] lazy val iParams: Seq[UI] = {
|
|
||||||
val i = uFn(iPorts.size, oPorts.map { case (o, n) => n.iParams(o) })
|
|
||||||
reqE(i.size, iPorts.size)
|
|
||||||
i.map(inner.mixI(_, this))
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => outer.edgeO(o, n.iParams(i)) }
|
|
||||||
lazy val edgesIn = (iPorts zip iParams).map { case ((o, n), i) => inner.edgeI(n.oParams(o), i) }
|
|
||||||
|
|
||||||
lazy val bundleOut = outer.bundleO(edgesOut)
|
|
||||||
lazy val bundleIn = inner.bundleI(edgesIn)
|
|
||||||
|
|
||||||
def oConnect = bundleOut
|
|
||||||
def iConnect = bundleIn
|
|
||||||
|
|
||||||
// connects the outward part of a node with the inward part of this node
|
|
||||||
def := (y: OutwardNode[DI, UI, BI])(implicit sourceInfo: SourceInfo): Option[LazyModule] = {
|
|
||||||
val x = this // x := y
|
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
|
||||||
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
|
||||||
val i = x.iPushed
|
|
||||||
val o = y.oPushed
|
|
||||||
y.oPush(i, x)
|
|
||||||
x.iPush(o, y)
|
|
||||||
val (out, binding) = inner.connect(y.oConnect(o), x.iConnect(i), x.edgesIn(i))
|
|
||||||
LazyModule.stack.head.bindings = binding :: LazyModule.stack.head.bindings
|
|
||||||
out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimpleNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])(
|
|
||||||
oFn: (Int, Seq[D]) => Seq[D],
|
|
||||||
iFn: (Int, Seq[U]) => Seq[U],
|
|
||||||
numPO: Range.Inclusive,
|
|
||||||
numPI: Range.Inclusive)
|
|
||||||
extends MixedNode[D, U, EI, B, D, U, EO, B](imp, imp)(oFn, iFn, numPO, numPI)
|
|
||||||
|
|
||||||
class IdentityNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
|
||||||
extends SimpleNode(imp)({case (_, s) => s}, {case (_, s) => s}, 0 to 999, 0 to 999)
|
|
||||||
|
|
||||||
class OutputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
|
||||||
{
|
|
||||||
override def oConnect = bundleOut
|
|
||||||
override def iConnect = bundleOut
|
|
||||||
}
|
|
||||||
|
|
||||||
class InputNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B]) extends IdentityNode(imp)
|
|
||||||
{
|
|
||||||
override def oConnect = bundleIn
|
|
||||||
override def iConnect = bundleIn
|
|
||||||
}
|
|
||||||
|
|
||||||
class SourceNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(po: PO, num: Range.Inclusive = 1 to 1)
|
|
||||||
extends SimpleNode(imp)({case (n, Seq()) => Seq.fill(n)(po)}, {case (0, _) => Seq()}, num, 0 to 0)
|
|
||||||
{
|
|
||||||
require (num.end >= 1, s"${name} is a source which does not accept outputs${lazyModule.line}")
|
|
||||||
}
|
|
||||||
|
|
||||||
class SinkNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(pi: PI, num: Range.Inclusive = 1 to 1)
|
|
||||||
extends SimpleNode(imp)({case (0, _) => Seq()}, {case (n, Seq()) => Seq.fill(n)(pi)}, 0 to 0, num)
|
|
||||||
{
|
|
||||||
require (num.end >= 1, s"${name} is a sink which does not accept inputs${lazyModule.line}")
|
|
||||||
}
|
|
||||||
|
|
||||||
class InteriorNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])
|
|
||||||
(oFn: Seq[PO] => PO, iFn: Seq[PI] => PI, numPO: Range.Inclusive, numPI: Range.Inclusive)
|
|
||||||
extends SimpleNode(imp)({case (n,s) => Seq.fill(n)(oFn(s))}, {case (n,s) => Seq.fill(n)(iFn(s))}, numPO, numPI)
|
|
||||||
{
|
|
||||||
require (numPO.end >= 1, s"${name} is an adapter which does not accept outputs${lazyModule.line}")
|
|
||||||
require (numPI.end >= 1, s"${name} is an adapter which does not accept inputs${lazyModule.line}")
|
|
||||||
}
|
|
||||||
|
@ -3,147 +3,9 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
import scala.math.max
|
import scala.math.max
|
||||||
|
|
||||||
/** Options for memory regions */
|
|
||||||
object RegionType {
|
|
||||||
sealed trait T
|
|
||||||
case object CACHED extends T
|
|
||||||
case object TRACKED extends T
|
|
||||||
case object UNCACHED extends T
|
|
||||||
case object PUT_EFFECTS extends T
|
|
||||||
case object GET_EFFECTS extends T // GET_EFFECTS => PUT_EFFECTS
|
|
||||||
val cases = Seq(CACHED, TRACKED, UNCACHED, PUT_EFFECTS, GET_EFFECTS)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A non-empty half-open range; [start, end)
|
|
||||||
case class IdRange(start: Int, end: Int)
|
|
||||||
{
|
|
||||||
require (start >= 0)
|
|
||||||
require (start < end) // not empty
|
|
||||||
|
|
||||||
// This is a strict partial ordering
|
|
||||||
def <(x: IdRange) = end <= x.start
|
|
||||||
def >(x: IdRange) = x < this
|
|
||||||
|
|
||||||
def overlaps(x: IdRange) = start < x.end && x.start < end
|
|
||||||
def contains(x: IdRange) = start <= x.start && x.end <= end
|
|
||||||
// contains => overlaps (because empty is forbidden)
|
|
||||||
|
|
||||||
def contains(x: Int) = start <= x && x < end
|
|
||||||
def contains(x: UInt) =
|
|
||||||
if (start+1 == end) { UInt(start) === x }
|
|
||||||
else if (isPow2(end-start) && ((end | start) & (end-start-1)) == 0)
|
|
||||||
{ ~(~(UInt(start) ^ x) | UInt(end-start-1)) === UInt(0) }
|
|
||||||
else { UInt(start) <= x && x < UInt(end) }
|
|
||||||
|
|
||||||
def shift(x: Int) = IdRange(start+x, end+x)
|
|
||||||
def size = end - start
|
|
||||||
}
|
|
||||||
|
|
||||||
// An potentially empty inclusive range of 2-powers [min, max] (in bytes)
|
|
||||||
case class TransferSizes(min: Int, max: Int)
|
|
||||||
{
|
|
||||||
def this(x: Int) = this(x, x)
|
|
||||||
|
|
||||||
require (min <= max)
|
|
||||||
require (min >= 0 && max >= 0)
|
|
||||||
require (max == 0 || isPow2(max))
|
|
||||||
require (min == 0 || isPow2(min))
|
|
||||||
require (max == 0 || min != 0) // 0 is forbidden unless (0,0)
|
|
||||||
|
|
||||||
def none = min == 0
|
|
||||||
def contains(x: Int) = isPow2(x) && min <= x && x <= max
|
|
||||||
def containsLg(x: Int) = contains(1 << x)
|
|
||||||
def containsLg(x: UInt) =
|
|
||||||
if (none) Bool(false)
|
|
||||||
else if (min == max) { UInt(log2Ceil(min)) === x }
|
|
||||||
else { UInt(log2Ceil(min)) <= x && x <= UInt(log2Ceil(max)) }
|
|
||||||
|
|
||||||
def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
|
||||||
|
|
||||||
def intersect(x: TransferSizes) =
|
|
||||||
if (x.max < min || max < x.min) TransferSizes.none
|
|
||||||
else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max))
|
|
||||||
}
|
|
||||||
|
|
||||||
object TransferSizes {
|
|
||||||
def apply(x: Int) = new TransferSizes(x)
|
|
||||||
val none = new TransferSizes(0)
|
|
||||||
|
|
||||||
implicit def asBool(x: TransferSizes) = !x.none
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
|
||||||
case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
|
||||||
{
|
|
||||||
// Forbid misaligned base address (and empty sets)
|
|
||||||
require ((base & mask) == 0)
|
|
||||||
require (base >= 0) // TL2 address widths are not fixed => negative is ambiguous
|
|
||||||
// We do allow negative mask (=> ignore all high bits)
|
|
||||||
|
|
||||||
def contains(x: BigInt) = ((x ^ base) & ~mask) == 0
|
|
||||||
def contains(x: UInt) = ((x ^ UInt(base)).zext() & SInt(~mask)) === SInt(0)
|
|
||||||
|
|
||||||
// overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1)
|
|
||||||
def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0
|
|
||||||
// contains iff bitwise: x.mask => mask && contains(x.base)
|
|
||||||
def contains(x: AddressSet) = ((x.mask | (base ^ x.base)) & ~mask) == 0
|
|
||||||
|
|
||||||
// The number of bytes to which the manager must be aligned
|
|
||||||
def alignment = ((mask + 1) & ~mask)
|
|
||||||
// Is this a contiguous memory range
|
|
||||||
def contiguous = alignment == mask+1
|
|
||||||
|
|
||||||
def finite = mask >= 0
|
|
||||||
def max = { require (finite); base | mask }
|
|
||||||
|
|
||||||
// Widen the match function to ignore all bits in imask
|
|
||||||
def widen(imask: BigInt) = AddressSet(base & ~imask, mask | imask)
|
|
||||||
|
|
||||||
// AddressSets have one natural Ordering (the containment order, if contiguous)
|
|
||||||
def compare(x: AddressSet) = {
|
|
||||||
val primary = (this.base - x.base).signum // smallest address first
|
|
||||||
val secondary = (x.mask - this.mask).signum // largest mask first
|
|
||||||
if (primary != 0) primary else secondary
|
|
||||||
}
|
|
||||||
|
|
||||||
// We always want to see things in hex
|
|
||||||
override def toString() = {
|
|
||||||
if (mask >= 0) {
|
|
||||||
"AddressSet(0x%x, 0x%x)".format(base, mask)
|
|
||||||
} else {
|
|
||||||
"AddressSet(0x%x, ~0x%x)".format(base, ~mask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object AddressSet
|
|
||||||
{
|
|
||||||
def misaligned(base: BigInt, size: BigInt): Seq[AddressSet] = {
|
|
||||||
val largestPow2 = BigInt(1) << log2Floor(size)
|
|
||||||
val mostZeros = (base + size - 1) & ~(largestPow2 - 1)
|
|
||||||
def splitLo(low: BigInt, high: BigInt, tail: Seq[AddressSet]): Seq[AddressSet] = {
|
|
||||||
if (low == high) tail else {
|
|
||||||
val toggleBits = low ^ high
|
|
||||||
val misalignment = toggleBits & (-toggleBits)
|
|
||||||
splitLo(low+misalignment, high, AddressSet(low, misalignment-1) +: tail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def splitHi(low: BigInt, high: BigInt, tail: Seq[AddressSet]): Seq[AddressSet] = {
|
|
||||||
if (low == high) tail else {
|
|
||||||
val toggleBits = low ^ high
|
|
||||||
val misalignment = toggleBits & (-toggleBits)
|
|
||||||
splitHi(low, high-misalignment, AddressSet(high-misalignment, misalignment-1) +: tail)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
splitLo(base, mostZeros, splitHi(mostZeros, base+size, Seq())).sorted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case class TLManagerParameters(
|
case class TLManagerParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
sinkId: IdRange = IdRange(0, 1),
|
sinkId: IdRange = IdRange(0, 1),
|
||||||
@ -391,6 +253,7 @@ case class TLBundleParameters(
|
|||||||
require (isPow2(dataBits))
|
require (isPow2(dataBits))
|
||||||
|
|
||||||
val addrLoBits = log2Up(dataBits/8)
|
val addrLoBits = log2Up(dataBits/8)
|
||||||
|
val addressBits = addrHiBits + log2Ceil(dataBits/8)
|
||||||
|
|
||||||
def union(x: TLBundleParameters) =
|
def union(x: TLBundleParameters) =
|
||||||
TLBundleParameters(
|
TLBundleParameters(
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
// We detect concurrent puts that put memory into an undefined state.
|
// We detect concurrent puts that put memory into an undefined state.
|
||||||
// put0, put0Ack, put1, put1Ack => ok: defined
|
// put0, put0Ack, put1, put1Ack => ok: defined
|
||||||
|
@ -3,16 +3,20 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
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)
|
class TLRegisterNode(address: AddressSet, concurrency: Int = 0, beatBytes: Int = 4, undefZero: Boolean = true)
|
||||||
extends TLManagerNode(beatBytes, TLManagerParameters(
|
extends TLManagerNode(TLManagerPortParameters(
|
||||||
|
Seq(TLManagerParameters(
|
||||||
address = Seq(address),
|
address = Seq(address),
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
supportsPutFull = TransferSizes(1, beatBytes),
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
fifoId = Some(0)), // requests are handled in order
|
fifoId = Some(0))), // requests are handled in order
|
||||||
minLatency = min(concurrency, 1)) // the Queue adds at least one cycle
|
beatBytes = beatBytes,
|
||||||
|
minLatency = min(concurrency, 1))) // the Queue adds at least one cycle
|
||||||
{
|
{
|
||||||
require (address.contiguous)
|
require (address.contiguous)
|
||||||
|
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
import regmapper._
|
||||||
import unittest._
|
import unittest._
|
||||||
import util.Pow2ClockDivider
|
import util.{Pow2ClockDivider}
|
||||||
|
|
||||||
object LFSR16Seed
|
object LFSR16Seed
|
||||||
{
|
{
|
||||||
|
@ -3,18 +3,21 @@
|
|||||||
package uncore.tilelink2
|
package uncore.tilelink2
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4) extends LazyModule
|
class TLRAM(address: AddressSet, executable: Boolean = true, beatBytes: Int = 4) extends LazyModule
|
||||||
{
|
{
|
||||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
val node = TLManagerNode(TLManagerPortParameters(
|
||||||
|
Seq(TLManagerParameters(
|
||||||
address = List(address),
|
address = List(address),
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
executable = executable,
|
executable = executable,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
supportsPutFull = TransferSizes(1, beatBytes),
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
fifoId = Some(0)), // requests are handled in order
|
fifoId = Some(0))), // requests are handled in order
|
||||||
minLatency = 1) // no bypass needed for this device
|
beatBytes = beatBytes,
|
||||||
|
minLatency = 1)) // no bypass needed for this device
|
||||||
|
|
||||||
// We require the address range to include an entire beat (for the write mask)
|
// We require the address range to include an entire beat (for the write mask)
|
||||||
require ((address.mask & (beatBytes-1)) == beatBytes-1)
|
require ((address.mask & (beatBytes-1)) == beatBytes-1)
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
// See LICENSE for license details.
|
|
||||||
|
|
||||||
package uncore.tilelink2
|
|
||||||
|
|
||||||
import Chisel._
|
|
||||||
import scala.collection.mutable.ListBuffer
|
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
|
||||||
|
|
||||||
object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
|
|
||||||
{
|
|
||||||
def edgeO(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeOut = new TLEdgeOut(pd, pu)
|
|
||||||
def edgeI(pd: TLClientPortParameters, pu: TLManagerPortParameters): TLEdgeIn = new TLEdgeIn(pd, pu)
|
|
||||||
def bundleO(eo: Seq[TLEdgeOut]): Vec[TLBundle] = {
|
|
||||||
require (!eo.isEmpty)
|
|
||||||
Vec(eo.size, TLBundle(eo.map(_.bundle).reduce(_.union(_))))
|
|
||||||
}
|
|
||||||
def bundleI(ei: Seq[TLEdgeIn]): Vec[TLBundle] = {
|
|
||||||
require (!ei.isEmpty)
|
|
||||||
Vec(ei.size, TLBundle(ei.map(_.bundle).reduce(_.union(_)))).flip
|
|
||||||
}
|
|
||||||
|
|
||||||
def colour = "#000000" // black
|
|
||||||
def connect(bo: => TLBundle, bi: => TLBundle, ei: => TLEdgeIn)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
|
||||||
val monitor = LazyModule(new TLMonitor(() => new TLBundleSnoop(bo.params), () => ei, sourceInfo))
|
|
||||||
(Some(monitor), () => {
|
|
||||||
bi <> bo
|
|
||||||
monitor.module.io.in := TLBundleSnoop(bo)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters =
|
|
||||||
pd.copy(clients = pd.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
|
|
||||||
override def mixI(pu: TLManagerPortParameters, node: InwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLManagerPortParameters =
|
|
||||||
pu.copy(managers = pu.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
|
|
||||||
}
|
|
||||||
|
|
||||||
case class TLIdentityNode() extends IdentityNode(TLImp)
|
|
||||||
case class TLOutputNode() extends OutputNode(TLImp)
|
|
||||||
case class TLInputNode() extends InputNode(TLImp)
|
|
||||||
|
|
||||||
case class TLClientNode(params: TLClientParameters, numPorts: Range.Inclusive = 1 to 1)
|
|
||||||
extends SourceNode(TLImp)(TLClientPortParameters(Seq(params)), numPorts)
|
|
||||||
|
|
||||||
case class TLManagerNode(beatBytes: Int, params: TLManagerParameters, numPorts: Range.Inclusive = 1 to 1, minLatency: Int = 0)
|
|
||||||
extends SinkNode(TLImp)(TLManagerPortParameters(Seq(params), beatBytes, minLatency), numPorts)
|
|
||||||
|
|
||||||
case class TLAdapterNode(
|
|
||||||
clientFn: Seq[TLClientPortParameters] => TLClientPortParameters,
|
|
||||||
managerFn: Seq[TLManagerPortParameters] => TLManagerPortParameters,
|
|
||||||
numClientPorts: Range.Inclusive = 1 to 1,
|
|
||||||
numManagerPorts: Range.Inclusive = 1 to 1)
|
|
||||||
extends InteriorNode(TLImp)(clientFn, managerFn, numClientPorts, numManagerPorts)
|
|
||||||
|
|
||||||
/** Synthesizeable unit tests */
|
|
||||||
import unittest._
|
|
||||||
|
|
||||||
class TLInputNodeTest extends UnitTest(500000) {
|
|
||||||
class Acceptor extends LazyModule {
|
|
||||||
val node = TLInputNode()
|
|
||||||
val tlram = LazyModule(new TLRAM(AddressSet(0x54321000, 0xfff)))
|
|
||||||
tlram.node := node
|
|
||||||
|
|
||||||
lazy val module = new LazyModuleImp(this) {
|
|
||||||
val io = new Bundle {
|
|
||||||
val in = node.bundleIn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val fuzzer = LazyModule(new TLFuzzer(5000))
|
|
||||||
LazyModule(new Acceptor).node := TLFragmenter(4, 64)(fuzzer.node)
|
|
||||||
|
|
||||||
io.finished := Module(fuzzer.module).io.finished
|
|
||||||
}
|
|
||||||
|
|
||||||
object TLAsyncImp extends NodeImp[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncEdgeParameters, TLAsyncEdgeParameters, TLAsyncBundle]
|
|
||||||
{
|
|
||||||
def edgeO(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
|
||||||
def edgeI(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters): TLAsyncEdgeParameters = TLAsyncEdgeParameters(pd, pu)
|
|
||||||
def bundleO(eo: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
|
||||||
require (eo.size == 1)
|
|
||||||
Vec(eo.size, new TLAsyncBundle(eo(0).bundle))
|
|
||||||
}
|
|
||||||
def bundleI(ei: Seq[TLAsyncEdgeParameters]): Vec[TLAsyncBundle] = {
|
|
||||||
require (ei.size == 1)
|
|
||||||
Vec(ei.size, new TLAsyncBundle(ei(0).bundle)).flip
|
|
||||||
}
|
|
||||||
|
|
||||||
def colour = "#ff0000" // red
|
|
||||||
def connect(bo: => TLAsyncBundle, bi: => TLAsyncBundle, ei: => TLAsyncEdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
|
||||||
(None, () => { bi <> bo })
|
|
||||||
}
|
|
||||||
|
|
||||||
override def mixO(pd: TLAsyncClientPortParameters, node: OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncClientPortParameters =
|
|
||||||
pd.copy(base = pd.base.copy(clients = pd.base.clients.map { c => c.copy (nodePath = node +: c.nodePath) }))
|
|
||||||
override def mixI(pu: TLAsyncManagerPortParameters, node: InwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncManagerPortParameters =
|
|
||||||
pu.copy(base = pu.base.copy(managers = pu.base.managers.map { m => m.copy (nodePath = node +: m.nodePath) }))
|
|
||||||
}
|
|
||||||
|
|
||||||
case class TLAsyncIdentityNode() extends IdentityNode(TLAsyncImp)
|
|
||||||
case class TLAsyncOutputNode() extends OutputNode(TLAsyncImp)
|
|
||||||
case class TLAsyncInputNode() extends InputNode(TLAsyncImp)
|
|
||||||
|
|
||||||
case class TLAsyncSourceNode() extends MixedNode(TLImp, TLAsyncImp)(
|
|
||||||
dFn = { case (1, s) => s.map(TLAsyncClientPortParameters(_)) },
|
|
||||||
uFn = { case (1, s) => s.map(_.base) },
|
|
||||||
numPO = 1 to 1,
|
|
||||||
numPI = 1 to 1)
|
|
||||||
|
|
||||||
case class TLAsyncSinkNode(depth: Int) extends MixedNode(TLAsyncImp, TLImp)(
|
|
||||||
dFn = { case (1, s) => s.map(_.base) },
|
|
||||||
uFn = { case (1, s) => s.map(TLAsyncManagerPortParameters(depth, _)) },
|
|
||||||
numPO = 1 to 1,
|
|
||||||
numPI = 1 to 1)
|
|
@ -5,6 +5,7 @@ package uncore.tilelink2
|
|||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.SourceInfo
|
import chisel3.internal.sourceinfo.SourceInfo
|
||||||
import chisel3.util.{Irrevocable, IrrevocableIO}
|
import chisel3.util.{Irrevocable, IrrevocableIO}
|
||||||
|
import diplomacy._
|
||||||
import scala.math.{min,max}
|
import scala.math.{min,max}
|
||||||
|
|
||||||
// innBeatBytes => the new client-facing bus width
|
// innBeatBytes => the new client-facing bus width
|
||||||
|
@ -4,6 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.util.IrrevocableIO
|
import chisel3.util.IrrevocableIO
|
||||||
|
import diplomacy._
|
||||||
|
|
||||||
class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends LazyModule
|
class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends LazyModule
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package uncore
|
package uncore
|
||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import chisel3.internal.sourceinfo.{SourceInfo, SourceLine, UnlocatableSourceInfo}
|
import diplomacy._
|
||||||
|
|
||||||
package object tilelink2
|
package object tilelink2
|
||||||
{
|
{
|
||||||
@ -17,9 +17,4 @@ package object tilelink2
|
|||||||
if (s >= w) x else helper(s+s, x | (x << s)(w-1,0))
|
if (s >= w) x else helper(s+s, x | (x << s)(w-1,0))
|
||||||
helper(1, x)
|
helper(1, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
def sourceLine(sourceInfo: SourceInfo, prefix: String = " (", suffix: String = ")") = sourceInfo match {
|
|
||||||
case SourceLine(filename, line, col) => s"$prefix$filename:$line:$col$suffix"
|
|
||||||
case _ => ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ package util
|
|||||||
|
|
||||||
import Chisel._
|
import Chisel._
|
||||||
import cde._
|
import cde._
|
||||||
|
import diplomacy.LazyModule
|
||||||
import java.io.{File, FileWriter}
|
import java.io.{File, FileWriter}
|
||||||
import uncore.tilelink2.LazyModule
|
|
||||||
|
|
||||||
/** Representation of the information this Generator needs to collect from external sources. */
|
/** Representation of the information this Generator needs to collect from external sources. */
|
||||||
case class ParsedInputNames(
|
case class ParsedInputNames(
|
||||||
|
21
src/main/scala/util/GenericParameterizedBundle.scala
Normal file
21
src/main/scala/util/GenericParameterizedBundle.scala
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// See LICENSE for license details.
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import Chisel._
|
||||||
|
|
||||||
|
abstract class GenericParameterizedBundle[T <: Object](val params: T) extends Bundle
|
||||||
|
{
|
||||||
|
override def cloneType = {
|
||||||
|
try {
|
||||||
|
this.getClass.getConstructors.head.newInstance(params).asInstanceOf[this.type]
|
||||||
|
} catch {
|
||||||
|
case e: java.lang.IllegalArgumentException =>
|
||||||
|
throw new Exception("Unable to use GenericParameterizedBundle.cloneType on " +
|
||||||
|
this.getClass + ", probably because " + this.getClass +
|
||||||
|
"() takes more than one argument. Consider overriding " +
|
||||||
|
"cloneType() on " + this.getClass, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user