axi4: diplomacy capable AXI4
This commit is contained in:
parent
dcb9383568
commit
b29d34038e
68
src/main/scala/uncore/axi4/Bundles.scala
Normal file
68
src/main/scala/uncore/axi4/Bundles.scala
Normal file
@ -0,0 +1,68 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.axi4
|
||||
|
||||
import Chisel._
|
||||
import chisel3.util.Irrevocable
|
||||
import util.GenericParameterizedBundle
|
||||
|
||||
abstract class AXI4BundleBase(params: AXI4BundleParameters) extends GenericParameterizedBundle(params)
|
||||
|
||||
abstract class AXI4BundleA(params: AXI4BundleParameters) extends AXI4BundleBase(params)
|
||||
{
|
||||
val id = UInt(width = params.idBits)
|
||||
val addr = UInt(width = params.addrBits)
|
||||
val len = UInt(width = params.lenBits) // number of beats - 1
|
||||
val size = UInt(width = params.sizeBits) // bytes in beat = 2^size
|
||||
val burst = UInt(width = params.burstBits)
|
||||
val lock = UInt(width = params.lockBits)
|
||||
val cache = UInt(width = params.cacheBits)
|
||||
val prot = UInt(width = params.protBits)
|
||||
val qos = UInt(width = params.qosBits) // 0=no QoS, bigger = higher priority
|
||||
// val region = UInt(width = 4) // optional
|
||||
}
|
||||
|
||||
// A non-standard bundle that can be both AR and AW
|
||||
class AXI4BundleARW(params: AXI4BundleParameters) extends AXI4BundleA(params)
|
||||
{
|
||||
val wen = Bool()
|
||||
}
|
||||
|
||||
class AXI4BundleAW(params: AXI4BundleParameters) extends AXI4BundleA(params)
|
||||
class AXI4BundleAR(params: AXI4BundleParameters) extends AXI4BundleA(params)
|
||||
|
||||
class AXI4BundleW(params: AXI4BundleParameters) extends AXI4BundleBase(params)
|
||||
{
|
||||
// id ... removed in AXI4
|
||||
val data = UInt(width = params.dataBits)
|
||||
val strb = UInt(width = params.dataBits/8)
|
||||
val last = Bool()
|
||||
}
|
||||
|
||||
class AXI4BundleR(params: AXI4BundleParameters) extends AXI4BundleBase(params)
|
||||
{
|
||||
val id = UInt(width = params.idBits)
|
||||
val data = UInt(width = params.dataBits)
|
||||
val resp = UInt(width = params.respBits)
|
||||
val last = Bool()
|
||||
}
|
||||
|
||||
class AXI4BundleB(params: AXI4BundleParameters) extends AXI4BundleBase(params)
|
||||
{
|
||||
val id = UInt(width = params.idBits)
|
||||
val resp = UInt(width = params.respBits)
|
||||
}
|
||||
|
||||
class AXI4Bundle(params: AXI4BundleParameters) extends AXI4BundleBase(params)
|
||||
{
|
||||
val aw = Irrevocable(new AXI4BundleAW(params))
|
||||
val w = Irrevocable(new AXI4BundleW (params))
|
||||
val b = Irrevocable(new AXI4BundleB (params)).flip
|
||||
val ar = Irrevocable(new AXI4BundleAR(params))
|
||||
val r = Irrevocable(new AXI4BundleR (params)).flip
|
||||
}
|
||||
|
||||
object AXI4Bundle
|
||||
{
|
||||
def apply(params: AXI4BundleParameters) = new AXI4Bundle(params)
|
||||
}
|
47
src/main/scala/uncore/axi4/Nodes.scala
Normal file
47
src/main/scala/uncore/axi4/Nodes.scala
Normal file
@ -0,0 +1,47 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.axi4
|
||||
|
||||
import Chisel._
|
||||
import chisel3.internal.sourceinfo.SourceInfo
|
||||
import diplomacy._
|
||||
|
||||
object AXI4Imp extends NodeImp[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4EdgeParameters, AXI4EdgeParameters, AXI4Bundle]
|
||||
{
|
||||
def edgeO(pd: AXI4MasterPortParameters, pu: AXI4SlavePortParameters): AXI4EdgeParameters = AXI4EdgeParameters(pd, pu)
|
||||
def edgeI(pd: AXI4MasterPortParameters, pu: AXI4SlavePortParameters): AXI4EdgeParameters = AXI4EdgeParameters(pd, pu)
|
||||
def bundleO(eo: Seq[AXI4EdgeParameters]): Vec[AXI4Bundle] = {
|
||||
require (!eo.isEmpty)
|
||||
Vec(eo.size, AXI4Bundle(eo.map(_.bundle).reduce(_.union(_))))
|
||||
}
|
||||
def bundleI(ei: Seq[AXI4EdgeParameters]): Vec[AXI4Bundle] = {
|
||||
require (!ei.isEmpty)
|
||||
Vec(ei.size, AXI4Bundle(ei.map(_.bundle).reduce(_.union(_)))).flip
|
||||
}
|
||||
|
||||
def colour = "#00ccff" // bluish
|
||||
def connect(bo: => AXI4Bundle, bi: => AXI4Bundle, ei: => AXI4EdgeParameters)(implicit sourceInfo: SourceInfo): (Option[LazyModule], () => Unit) = {
|
||||
(None, () => { bi <> bo })
|
||||
}
|
||||
|
||||
override def mixO(pd: AXI4MasterPortParameters, node: OutwardNode[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]): AXI4MasterPortParameters =
|
||||
pd.copy(masters = pd.masters.map { c => c.copy (nodePath = node +: c.nodePath) })
|
||||
override def mixI(pu: AXI4SlavePortParameters, node: InwardNode[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]): AXI4SlavePortParameters =
|
||||
pu.copy(slaves = pu.slaves.map { m => m.copy (nodePath = node +: m.nodePath) })
|
||||
}
|
||||
|
||||
case class AXI4IdentityNode() extends IdentityNode(AXI4Imp)
|
||||
case class AXI4OutputNode() extends OutputNode(AXI4Imp)
|
||||
case class AXI4InputNode() extends InputNode(AXI4Imp)
|
||||
|
||||
case class AXI4MasterNode(portParams: AXI4MasterPortParameters, numPorts: Range.Inclusive = 1 to 1)
|
||||
extends SourceNode(AXI4Imp)(portParams, numPorts)
|
||||
case class AXI4SlaveNode(portParams: AXI4SlavePortParameters, numPorts: Range.Inclusive = 1 to 1)
|
||||
extends SinkNode(AXI4Imp)(portParams, numPorts)
|
||||
|
||||
case class AXI4AdapterNode(
|
||||
clientFn: Seq[AXI4MasterPortParameters] => AXI4MasterPortParameters,
|
||||
managerFn: Seq[AXI4SlavePortParameters] => AXI4SlavePortParameters,
|
||||
numMasterPorts: Range.Inclusive = 1 to 1,
|
||||
numSlavePorts: Range.Inclusive = 1 to 1)
|
||||
extends InteriorNode(AXI4Imp)(clientFn, managerFn, numMasterPorts, numSlavePorts)
|
109
src/main/scala/uncore/axi4/Parameters.scala
Normal file
109
src/main/scala/uncore/axi4/Parameters.scala
Normal file
@ -0,0 +1,109 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.axi4
|
||||
|
||||
import Chisel._
|
||||
import diplomacy._
|
||||
import scala.math.max
|
||||
|
||||
case class AXI4SlaveParameters(
|
||||
address: Seq[AddressSet],
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
nodePath: Seq[BaseNode] = Seq(),
|
||||
supportsWrite: TransferSizes = TransferSizes.none,
|
||||
supportsRead: TransferSizes = TransferSizes.none,
|
||||
interleavedId: Option[Int] = None) // The device will not interleave read responses
|
||||
{
|
||||
address.foreach { a => require (a.finite) }
|
||||
address.combinations(2).foreach { case Seq(x,y) => require (!x.overlaps(y)) }
|
||||
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
val maxTransfer = max(supportsWrite.max, supportsRead.max)
|
||||
val maxAddress = address.map(_.max).max
|
||||
|
||||
// The device had better not support a transfer larger than it's alignment
|
||||
address.foreach { case a => require (a.alignment >= maxTransfer) }
|
||||
}
|
||||
|
||||
case class AXI4SlavePortParameters(
|
||||
slaves: Seq[AXI4SlaveParameters],
|
||||
beatBytes: Int)
|
||||
{
|
||||
require (!slaves.isEmpty)
|
||||
require (isPow2(beatBytes))
|
||||
|
||||
val maxTransfer = slaves.map(_.maxTransfer).max
|
||||
val maxAddress = slaves.map(_.maxAddress).max
|
||||
|
||||
// Check the link is not pointlessly wide
|
||||
require (maxTransfer >= beatBytes)
|
||||
// Check that the link can be implemented in AXI4
|
||||
require (maxTransfer <= beatBytes * (1 << AXI4Parameters.lenBits))
|
||||
|
||||
// Require disjoint ranges for addresses
|
||||
slaves.combinations(2).foreach { case Seq(x,y) =>
|
||||
x.address.foreach { a => y.address.foreach { b =>
|
||||
require (!a.overlaps(b))
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
case class AXI4MasterParameters(
|
||||
id: IdRange = IdRange(0, 1),
|
||||
nodePath: Seq[BaseNode] = Seq())
|
||||
{
|
||||
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
|
||||
}
|
||||
|
||||
case class AXI4MasterPortParameters(
|
||||
masters: Seq[AXI4MasterParameters])
|
||||
{
|
||||
val endId = masters.map(_.id.end).max
|
||||
|
||||
// Require disjoint ranges for ids
|
||||
masters.combinations(2).foreach { case Seq(x,y) => require (!x.id.overlaps(y.id)) }
|
||||
}
|
||||
|
||||
case class AXI4BundleParameters(
|
||||
addrBits: Int,
|
||||
dataBits: Int,
|
||||
idBits: Int)
|
||||
{
|
||||
require (dataBits >= 8)
|
||||
require (addrBits >= 1)
|
||||
require (idBits >= 1)
|
||||
require (isPow2(dataBits))
|
||||
|
||||
// Bring the globals into scope
|
||||
val lenBits = AXI4Parameters.lenBits
|
||||
val sizeBits = AXI4Parameters.sizeBits
|
||||
val burstBits = AXI4Parameters.burstBits
|
||||
val lockBits = AXI4Parameters.lockBits
|
||||
val cacheBits = AXI4Parameters.cacheBits
|
||||
val protBits = AXI4Parameters.protBits
|
||||
val qosBits = AXI4Parameters.qosBits
|
||||
val respBits = AXI4Parameters.respBits
|
||||
|
||||
def union(x: AXI4BundleParameters) =
|
||||
AXI4BundleParameters(
|
||||
max(addrBits, x.addrBits),
|
||||
max(dataBits, x.dataBits),
|
||||
max(idBits, x.idBits))
|
||||
}
|
||||
|
||||
object AXI4BundleParameters
|
||||
{
|
||||
def apply(master: AXI4MasterPortParameters, slave: AXI4SlavePortParameters) =
|
||||
new AXI4BundleParameters(
|
||||
addrBits = log2Up(slave.maxAddress+1),
|
||||
dataBits = slave.beatBytes * 8,
|
||||
idBits = log2Up(master.endId))
|
||||
}
|
||||
|
||||
case class AXI4EdgeParameters(
|
||||
master: AXI4MasterPortParameters,
|
||||
slave: AXI4SlavePortParameters)
|
||||
{
|
||||
val bundle = AXI4BundleParameters(master, slave)
|
||||
}
|
37
src/main/scala/uncore/axi4/Protocol.scala
Normal file
37
src/main/scala/uncore/axi4/Protocol.scala
Normal file
@ -0,0 +1,37 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.axi4
|
||||
|
||||
import Chisel._
|
||||
import chisel3.util.{Irrevocable, IrrevocableIO}
|
||||
|
||||
object AXI4Parameters
|
||||
{
|
||||
// These are all fixed by the AXI4 standard:
|
||||
val lenBits = 8
|
||||
val sizeBits = 3
|
||||
val burstBits = 2
|
||||
val lockBits = 1
|
||||
val cacheBits = 4
|
||||
val protBits = 3
|
||||
val qosBits = 4
|
||||
val respBits = 2
|
||||
|
||||
val CACHE_RALLOCATE = UInt(8, width = cacheBits)
|
||||
val CACHE_WALLOCATE = UInt(4, width = cacheBits)
|
||||
val CACHE_MODIFIABLE = UInt(2, width = cacheBits)
|
||||
val CACHE_BUFFERABLE = UInt(1, width = cacheBits)
|
||||
|
||||
val PROT_PRIVILEDGED = UInt(1, width = protBits)
|
||||
val PROT_INSECURE = UInt(2, width = protBits)
|
||||
val PROT_INSTRUCTION = UInt(4, width = protBits)
|
||||
|
||||
val BURST_FIXED = UInt(0, width = burstBits)
|
||||
val BURST_INCR = UInt(1, width = burstBits)
|
||||
val BURST_WRAP = UInt(2, width = burstBits)
|
||||
|
||||
val RESP_OKAY = UInt(0, width = respBits)
|
||||
val RESP_EXOKAY = UInt(1, width = respBits)
|
||||
val RESP_SLVERR = UInt(2, width = respBits)
|
||||
val RESP_DECERR = UInt(3, width = respBits)
|
||||
}
|
9
src/main/scala/uncore/axi4/package.scala
Normal file
9
src/main/scala/uncore/axi4/package.scala
Normal file
@ -0,0 +1,9 @@
|
||||
package uncore
|
||||
|
||||
import Chisel._
|
||||
import diplomacy._
|
||||
|
||||
package object axi4
|
||||
{
|
||||
type AXI4OutwardNode = OutwardNode[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle]
|
||||
}
|
Loading…
Reference in New Issue
Block a user