diff --git a/src/main/scala/uncore/axi4/Bundles.scala b/src/main/scala/uncore/axi4/Bundles.scala new file mode 100644 index 00000000..89fdbc9f --- /dev/null +++ b/src/main/scala/uncore/axi4/Bundles.scala @@ -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) +} diff --git a/src/main/scala/uncore/axi4/Nodes.scala b/src/main/scala/uncore/axi4/Nodes.scala new file mode 100644 index 00000000..cafac4f1 --- /dev/null +++ b/src/main/scala/uncore/axi4/Nodes.scala @@ -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) diff --git a/src/main/scala/uncore/axi4/Parameters.scala b/src/main/scala/uncore/axi4/Parameters.scala new file mode 100644 index 00000000..dacc80ee --- /dev/null +++ b/src/main/scala/uncore/axi4/Parameters.scala @@ -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) +} diff --git a/src/main/scala/uncore/axi4/Protocol.scala b/src/main/scala/uncore/axi4/Protocol.scala new file mode 100644 index 00000000..90403b46 --- /dev/null +++ b/src/main/scala/uncore/axi4/Protocol.scala @@ -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) +} diff --git a/src/main/scala/uncore/axi4/package.scala b/src/main/scala/uncore/axi4/package.scala new file mode 100644 index 00000000..4ea7c9ab --- /dev/null +++ b/src/main/scala/uncore/axi4/package.scala @@ -0,0 +1,9 @@ +package uncore + +import Chisel._ +import diplomacy._ + +package object axi4 +{ + type AXI4OutwardNode = OutwardNode[AXI4MasterPortParameters, AXI4SlavePortParameters, AXI4Bundle] +}