
spinal.lib.bus.amba4.axi.Axi4Channel.scala Maven / Gradle / Ivy
package spinal.lib.bus.amba4.axi
import spinal.core._
import spinal.lib._
/**
* Definition of the Write/Read address channel
* @param config Axi4 configuration class
*/
class Axi4Ax(val config: Axi4Config,val userWidth : Int) extends Bundle {
val addr = UInt(config.addressWidth bits)
val id = if(config.useId) UInt(config.idWidth bits) else null
val region = if(config.useRegion) Bits(4 bits) else null
val len = if(config.useLen) UInt(8 bits) else null
val size = if(config.useSize) UInt(3 bits) else null
val burst = if(config.useBurst) Bits(2 bits) else null
val lock = if(config.useLock) Bits(1 bits) else null
val cache = if(config.useCache) Bits(4 bits) else null
val qos = if(config.useQos) Bits(4 bits) else null
val user = if(userWidth >= 0) Bits(userWidth bits) else null
val prot = if(config.useProt) Bits(3 bits) else null
import Axi4.burst._
def setBurstFIXED(): Unit = {assert(config.useBurst); burst := FIXED}
def setBurstWRAP() : Unit = {assert(config.useBurst); burst := WRAP}
def setBurstINCR() : Unit = {assert(config.useBurst); burst := INCR}
def setSize(sizeBurst :UInt) : Unit = if(config.useBurst) size := sizeBurst
def setLock(lockType :Bits) : Unit = if(config.useLock) lock := lockType
def setCache(cacheType : Bits) : Unit = if (config.useCache ) cache := cacheType
override def clone: this.type = new Axi4Ax(config,userWidth).asInstanceOf[this.type]
}
class Axi4Aw(config: Axi4Config) extends Axi4Ax(config, config.awUserWidth){
override def clone: this.type = new Axi4Aw(config).asInstanceOf[this.type]
}
class Axi4Ar(config: Axi4Config) extends Axi4Ax(config, config.arUserWidth){
override def clone: this.type = new Axi4Ar(config).asInstanceOf[this.type]
}
class Axi4Arw(config: Axi4Config) extends Axi4Ax(config, config.arwUserWidth){
val write = Bool
override def clone: this.type = new Axi4Arw(config).asInstanceOf[this.type]
}
/**
* Definition of the Write data channel
* @param config Axi4 configuration class
*/
case class Axi4W(config: Axi4Config) extends Bundle {
val data = Bits(config.dataWidth bits)
val strb = if(config.useStrb) Bits(config.bytePerWord bits) else null
val user = if(config.useWUser) Bits(config.wUserWidth bits) else null
val last = if(config.useLast) Bool else null
def setStrb() : Unit = if(config.useStrb) strb := (1 << widthOf(strb))-1
def setStrb(bytesLane : Bits) : Unit = if(config.useStrb) strb := bytesLane
}
/**
* Definition of the Write response channel
* @param config Axi4 configuration class
*/
case class Axi4B(config: Axi4Config) extends Bundle {
val id = if(config.useId) UInt(config.idWidth bits) else null
val resp = if(config.useResp) Bits(2 bits) else null
val user = if(config.useBUser) Bits(config.bUserWidth bits) else null
import Axi4.resp._
def setOKAY() : Unit = resp := OKAY
def setEXOKAY() : Unit = resp := EXOKAY
def setSLVERR() : Unit = resp := SLVERR
def setDECERR() : Unit = resp := DECERR
def isOKAY() : Bool = resp === OKAY
def isEXOKAY() : Bool = resp === EXOKAY
def isSLVERR() : Bool = resp === SLVERR
def isDECERR() : Bool = resp === DECERR
}
/**
* Definition of the Read Data channel
* @param config Axi4 configuration class
*/
case class Axi4R(config: Axi4Config) extends Bundle {
val data = Bits(config.dataWidth bits)
val id = if(config.useId) UInt(config.idWidth bits) else null
val resp = if(config.useResp) Bits(2 bits) else null
val last = if(config.useLast) Bool else null
val user = if(config.useRUser) Bits(config.rUserWidth bits) else null
import Axi4.resp._
def setOKAY() : Unit = resp := OKAY
def setEXOKAY() : Unit = resp := EXOKAY
def setSLVERR() : Unit = resp := SLVERR
def setDECERR() : Unit = resp := DECERR
def isOKAY() : Bool = resp === OKAY
def isEXOKAY() : Bool = resp === EXOKAY
def isSLVERR() : Bool = resp === SLVERR
def isDECERR() : Bool = resp === DECERR
}
class Axi4AxUnburstified(val config : Axi4Config, userWidth : Int) extends Bundle {
val addr = UInt(config.addressWidth bits)
val id = if(config.useId) UInt(config.idWidth bits) else null
val region = if(config.useRegion) Bits(4 bits) else null
val size = if(config.useSize) UInt(3 bits) else null
val burst = if(config.useBurst) Bits(2 bits) else null
val lock = if(config.useLock) Bits(1 bits) else null
val cache = if(config.useCache) Bits(4 bits) else null
val qos = if(config.useQos) Bits(4 bits) else null
val user = if(userWidth >= 0) Bits(userWidth bits) else null
val prot = if(config.useProt) Bits(3 bits) else null
}
object Axi4AxUnburstified{
def unburstify[X <: Axi4Ax,Y <: Axi4AxUnburstified](stream : Stream[X], outPayloadType : Y) : Stream[Fragment[Y]] = {
case class State() extends Bundle{
val busy = Bool
val len = UInt(8 bits)
val beat = UInt(8 bits)
val transaction = cloneOf(outPayloadType)
override def clone: State.this.type = new State().asInstanceOf[this.type]
}
val area = new Area {
val result = Stream Fragment (cloneOf(outPayloadType))
val doResult = Bool
val addrIncrRange = (Math.min(11, stream.payload.config.addressWidth - 1) downto 0)
val buffer = new Area{
val valid = RegInit(False)
val len = Reg(UInt(8 bits))
val beat = Reg(UInt(8 bits))
val transaction = Reg(cloneOf(outPayloadType))
val last = beat === 1
val address = Axi4.incr(
address = transaction.addr,
burst = transaction.burst,
len = len,
size = transaction.size,
bytePerWord = stream.config.bytePerWord
)
when(result.ready) {
beat := beat - 1
transaction.addr(addrIncrRange) := address(addrIncrRange)
when(last){
valid := False
}
}
}
stream.ready := False
when(buffer.valid){
result.valid := True
result.last := buffer.last
result.fragment := buffer.transaction
result.addr.removeAssignments()
result.addr := buffer.address
}otherwise{
stream.ready := result.ready
result.valid := stream.valid
result.fragment.assignSomeByName(stream.payload)
when(stream.len === 0) {
result.last := True
}otherwise{
result.last := False
when(result.ready){
buffer.valid := stream.valid
buffer.transaction.assignSomeByName(stream.payload)
buffer.beat := stream.len
buffer.len := stream.len
}
}
}
}.setWeakName("unburstify")
area.result
}
}
class Axi4ArUnburstified(axiConfig : Axi4Config) extends Axi4AxUnburstified(axiConfig, axiConfig.arUserWidth){
override def clone: this.type = new Axi4ArUnburstified(axiConfig).asInstanceOf[this.type]
}
class Axi4AwUnburstified(axiConfig : Axi4Config) extends Axi4AxUnburstified(axiConfig, axiConfig.awUserWidth){
override def clone: this.type = new Axi4AwUnburstified(axiConfig).asInstanceOf[this.type]
}
class Axi4ArwUnburstified(axiConfig : Axi4Config) extends Axi4AxUnburstified(axiConfig, axiConfig.arwUserWidth){
val write = Bool
override def clone: this.type = new Axi4ArwUnburstified(axiConfig).asInstanceOf[this.type]
}
object Axi4ArUnburstified{
def apply(axiConfig : Axi4Config) = new Axi4ArUnburstified(axiConfig)
}
object Axi4AwUnburstified{
def apply(axiConfig : Axi4Config) = new Axi4AwUnburstified(axiConfig)
}
object Axi4ArwUnburstified{
def apply(axiConfig : Axi4Config) = new Axi4ArwUnburstified(axiConfig)
}
object Axi4Priv{
def driveWeak[T <: Data](source : Bundle,sink : Bundle, by : T,to : T,defaultValue : () => T,allowResize : Boolean,allowDrop : Boolean) : Unit = {
(to != null,by != null) match {
case (false,false) =>
case (true,false) => if(defaultValue != null) to := defaultValue() else LocatedPendingError(s"$source can't drive $to because this first doesn't has the corresponding pin")
case (false,true) => if(!allowDrop) LocatedPendingError(s"$by can't drive $sink because this last one doesn't has the corresponding pin")
case (true,true) => to := (if(allowResize) by.resized else by)
}
}
def driveAx[T <: Axi4Ax](stream: Stream[T],sink: Stream[T]): Unit = {
sink.arbitrationFrom(stream)
assert(stream.config.idWidth <= sink.config.idWidth, s"$stream idWidth > $sink idWidth")
assert(stream.config.addressWidth >= sink.config.addressWidth, s"$stream addressWidth < $sink addressWidth")
sink.addr := stream.addr.resized
driveWeak(stream,sink,stream.id,sink.id,() => U(sink.id.range -> false),true,false)
driveWeak(stream,sink,stream.region,sink.region,() => B(sink.region.range -> false),false,true)
driveWeak(stream,sink,stream.len,sink.len,() => U(sink.len.range -> false),false,false)
driveWeak(stream,sink,stream.size,sink.size,() => U(log2Up(sink.config.dataWidth/8)),false,false)
driveWeak(stream,sink,stream.burst,sink.burst,() => Axi4.burst.INCR,false,false)
driveWeak(stream,sink,stream.lock,sink.lock,() => Axi4.lock.NORMAL,false,true)
driveWeak(stream,sink,stream.cache,sink.cache,() => B"0000",false,true)
driveWeak(stream,sink,stream.qos,sink.qos,() => B"0000",false,true)
driveWeak(stream,sink,stream.user,sink.user,() => B(sink.user.range -> false),true,true)
driveWeak(stream,sink,stream.prot,sink.prot,() => B"010",false,true)
}
}
object Axi4Aw{
def apply(config: Axi4Config) = new Axi4Aw(config)
implicit class StreamPimper(stream : Stream[Axi4Aw]) {
def drive(sink: Stream[Axi4Aw]): Unit = Axi4Priv.driveAx(stream,sink)
}
}
object Axi4Ar{
def apply(config: Axi4Config) = new Axi4Ar(config)
implicit class StreamPimper(stream : Stream[Axi4Ar]){
def drive(sink : Stream[Axi4Ar]): Unit = Axi4Priv.driveAx(stream,sink)
}
}
object Axi4Arw{
def apply(config: Axi4Config) = new Axi4Arw(config)
implicit class StreamPimper(stream : Stream[Axi4Arw]) {
def unburstify : Stream[Fragment[Axi4ArwUnburstified]] = {
Axi4AxUnburstified.unburstify(stream,Axi4ArwUnburstified(stream.config))
}
def drive(sink : Stream[Axi4Arw]): Unit ={
Axi4Priv.driveAx(stream,sink)
sink.write := stream.write
}
}
}
object Axi4W{
implicit class StreamPimper(stream : Stream[Axi4W]) {
def drive(sink: Stream[Axi4W]): Unit = {
sink.arbitrationFrom(stream)
sink.data := stream.data
Axi4Priv.driveWeak(stream,sink,stream.strb,sink.strb,() => B(sink.strb.range -> true),false,false)
Axi4Priv.driveWeak(stream,sink,stream.user,sink.user,() => B(sink.user.range -> false),false,true)
Axi4Priv.driveWeak(stream,sink,stream.last,sink.last,null,false,true)
}
}
}
object Axi4B{
implicit class StreamPimper(stream : Stream[Axi4B]) {
def drive(sink: Stream[Axi4B]): Unit = {
assert(stream.config.idWidth >= sink.config.idWidth, s"$stream idWidth < $sink idWidth")
sink.arbitrationFrom(stream)
Axi4Priv.driveWeak(stream,sink,stream.id,sink.id,null,true,true)
Axi4Priv.driveWeak(stream,sink,stream.resp,sink.resp,() => Axi4.resp.OKAY,false,true)
Axi4Priv.driveWeak(stream,sink,stream.user,sink.user,() => B(sink.user.range -> false),false,true)
}
}
}
object Axi4R{
implicit class StreamPimper(stream : Stream[Axi4R]) {
def drive(sink: Stream[Axi4R]): Unit = {
assert(stream.config.idWidth >= sink.config.idWidth, s"$stream idWidth < $sink idWidth")
sink.arbitrationFrom(stream)
sink.data := stream.data
Axi4Priv.driveWeak(stream,sink,stream.last,sink.last,null,false,true)
Axi4Priv.driveWeak(stream,sink,stream.id,sink.id,null,true,true)
Axi4Priv.driveWeak(stream,sink,stream.resp,sink.resp,() => Axi4.resp.OKAY,false,true)
Axi4Priv.driveWeak(stream,sink,stream.user,sink.user,() => B(sink.user.range -> false),false,true)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy