spinal.lib.graphic.VideoDma.scala Maven / Gradle / Ivy
package spinal.lib.graphic
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi.{Axi4Config, Axi4ReadOnly}
case class VideoDmaMem[T <: Data](g: VideoDmaGeneric[T]) extends Bundle with IMasterSlave{
val cmd = Stream(UInt(g.addressWidth bit))
val rsp = Flow Fragment(Bits(g.dataWidth bit))
override def asMaster(): Unit = {
master(cmd)
slave(rsp)
}
def toAxi4ReadOnly : Axi4ReadOnly = {
val ret = Axi4ReadOnly(g.getAxi4ReadOnlyConfig)
ret.readCmd.valid := this.cmd.valid
ret.readCmd.addr := this.cmd.payload << log2Up(g.dataWidth/8) + log2Up(g.beatPerAccess)
ret.readCmd.prot := "010"
ret.readCmd.cache := "1111"
ret.readCmd.len := g.beatPerAccess-1
ret.readCmd.size := log2Up(g.dataWidth/8)
this.cmd.ready := ret.readCmd.ready
this.rsp.valid := ret.readRsp.valid
this.rsp.last := ret.readRsp.last
this.rsp.fragment := ret.readRsp.data
ret.readRsp.ready := True
ret
}
}
case class VideoDmaGeneric[T <: Data](addressWidth : Int,
dataWidth : Int,
beatPerAccess : Int,
sizeWidth : Int,
frameFragmentType : T,
pendingRequetMax : Int,
fifoSize : Int,
frameClock : ClockDomain = null){
def getAxi4ReadOnlyConfig = Axi4Config(
addressWidth = addressWidth + log2Up(dataWidth/8) + log2Up(beatPerAccess),
dataWidth = dataWidth,
useId = false,
useRegion = false,
useBurst = false,
useLock = false,
useQos = false,
useResp = false
)
}
case class VideoDma[T <: Data](g : VideoDmaGeneric[T]) extends Component{
import g._
require(dataWidth >= widthOf(g.frameFragmentType))
val io = new Bundle{
val start = in Bool()
val busy = out Bool()
val base = in UInt(addressWidth bits) //base and size are in burst count, not in word, nor in byte
val size = in UInt(sizeWidth bits)
val mem = master(VideoDmaMem(g))
val frame = master(Stream(Fragment(frameFragmentType)))
}
val pendingMemCmd = CounterUpDown(
stateCount=pendingRequetMax + 1,
incWhen = io.mem.cmd.fire,
decWhen = io.mem.rsp.fire && io.mem.rsp.last
)
val pendingMemRsp = CounterMultiRequest(
width=log2Up(pendingRequetMax*beatPerAccess + 1),
io.mem.cmd.fire -> (_ + beatPerAccess),
io.mem.rsp.fire -> (_ - 1)
)
val toManyPendingCmd = pendingMemCmd > pendingRequetMax-1
val toManyPendingRsp = Bool()
val isActive = RegInit(False)
val cmdActive = RegInit(False)
io.busy := isActive
val memCmdCounter = Reg(UInt(sizeWidth bits))
val memCmdLast = memCmdCounter === io.size
io.mem.cmd.valid := False
io.mem.cmd.payload := io.base + memCmdCounter
when(!isActive) {
when(io.start) {
memCmdCounter := 0
isActive := True
cmdActive := True
}
} otherwise {
when(cmdActive){
when(!toManyPendingCmd && !toManyPendingRsp){
io.mem.cmd.valid := True
when(memCmdLast && io.mem.cmd.ready){
cmdActive := False
}
}
}elsewhen(pendingMemRsp === 0) {
isActive := False
}
}
when(io.mem.cmd.fire) {
memCmdCounter := memCmdCounter + 1
}
val memRsp = cloneOf(io.mem.rsp)
memRsp.valid := io.mem.rsp.valid
memRsp.last := !cmdActive && pendingMemRsp === 1
memRsp.fragment := io.mem.rsp.fragment
val fifoPop = Stream(Fragment(Bits(dataWidth bits)))
val rspArea = if(this.clockDomain == frameClock) new Area{
fifoPop << memRsp.toStream.queue(fifoSize)
val pendingMemToFifo = CounterMultiRequest(
width=log2Up(fifoSize + 1),
io.mem.cmd.fire -> (_ + beatPerAccess),
fifoPop.fire -> (_ - 1)
)
toManyPendingRsp := pendingMemToFifo > fifoSize-beatPerAccess
} else new Area{
require(isPow2(fifoSize))
val fifo = new StreamFifoCC(Fragment(Bits(dataWidth bit)),fifoSize,pushClock = ClockDomain.current,popClock = frameClock)
fifo.io.push << memRsp.toStream
fifo.io.pop >> fifoPop
val grayWidth = log2Up(fifoSize/beatPerAccess)+1
require(grayWidth >= 3)
val frameClockArea = new ClockingArea(frameClock){
val popBeatCounter = Counter(beatPerAccess)
when(fifo.io.pop.fire){
popBeatCounter.increment()
}
val popCmdGray = GrayCounter(grayWidth, popBeatCounter.willOverflow)
}
val popCmdGray = BufferCC(frameClockArea.popCmdGray)
val pushCmdGray = GrayCounter(grayWidth,io.mem.cmd.fire)
toManyPendingRsp := pushCmdGray(grayWidth - 1 downto grayWidth - 2) === ~popCmdGray(grayWidth - 1 downto grayWidth - 2) && pushCmdGray(grayWidth - 3 downto 0) === popCmdGray(grayWidth - 3 downto 0)
}
val fifoPopArea = new ClockingArea(frameClock){
StreamFragmentWidthAdapter(fifoPop,io.frame)
}
}