spinal.lib.experimental.bus.neutral.NeutralStreamDma.scala Maven / Gradle / Ivy
package spinal.lib.experimental.bus.neutral
import spinal.core._
import spinal.lib._
import spinal.lib.bus.avalon._
/**
* Created by PIC32F_USER on 23/04/2016.
*/
object NeutralStreamDma {
case class Config( addressWidth: Int,
dataWidth : Int,
memCmdCountMax : BigInt,
burstLengthMax : Int,
fifoSize : Int,
pendingRequetMax : Int,
ctrlRspClock : ClockDomain = null){
val burstWidth = log2Up(burstLengthMax+1)
val memCmdCountWidth = log2Up(memCmdCountMax+1)
def getAvalonConfig = AvalonMMConfig.bursted(
addressWidth = addressWidth,
dataWidth = dataWidth,
burstCountWidth = burstWidth
).getReadOnlyConfig.copy(
addressUnits = WORDS,
maximumPendingReadTransactions = pendingRequetMax
)
}
case class CtrlCmd(c: Config) extends Bundle {
val startAt = UInt(c.addressWidth bit)
val memCmdCount = UInt(c.memCmdCountWidth bit)
val burstLength = UInt(c.burstWidth bit)
}
case class Ctrl(c : Config) extends Bundle with IMasterSlave{
val cmd = Stream(CtrlCmd(c))
val rsp = Stream Fragment(Bits(c.dataWidth bit))
override def asMaster(): Unit = {
master(cmd)
slave(rsp)
}
}
case class MemCmd(c:Config) extends Bundle{
val address = UInt(c.addressWidth bit)
val length = UInt(c.burstWidth bit)
}
case class Mem(c: Config) extends Bundle with IMasterSlave{
val cmd = Stream(MemCmd(c))
val rsp = Flow Fragment(Bits(c.dataWidth bit))
override def asMaster(): Unit = {
master(cmd)
slave(rsp)
}
def toAvalon = {
val ret = AvalonMM(c.getAvalonConfig)
ret.read := cmd.valid
ret.address := cmd.address
ret.burstCount := cmd.length
cmd.ready := ret.waitRequestn
rsp.valid := ret.readDataValid
rsp.last := False
rsp.fragment := ret.readData
val rspCounter = Reg(UInt(c.burstWidth bits)) init(1)
when(rsp.valid){
rspCounter := rspCounter + 1
when(rspCounter === cmd.length){
rspCounter := 1
rsp.last := True
}
}
ret
}
}
class Block(c: Config) extends Component {
val io = new Bundle {
val ctrl = slave(Ctrl(c))
val mem = master(Mem(c))
}
val pendingMemCmd = CounterMultiRequest(
width=log2Up(c.pendingRequetMax + 1),
io.mem.cmd.fire -> (_ + 1),
(io.mem.rsp.fire && io.mem.rsp.last) -> (_ - 1)
)
val pendingMemRsp = CounterMultiRequest(
width=log2Up(c.pendingRequetMax*c.burstLengthMax + 1),
io.mem.cmd.fire -> (_ + io.mem.cmd.length),
io.mem.rsp.fire -> (_ - 1)
)
val isActive = RegInit(False)
val addressCounter = Reg(UInt(c.addressWidth bit))
val memCmdCounter = Reg(UInt(c.memCmdCountWidth bit))
io.ctrl.cmd.ready := False
io.mem.cmd.valid := False
when(!isActive) {
when(io.ctrl.cmd.valid) {
addressCounter := io.ctrl.cmd.startAt
memCmdCounter := io.ctrl.cmd.memCmdCount
isActive := True
}
} otherwise {
when(memCmdCounter =/= 0){
io.mem.cmd.valid := True
} otherwise {
when(pendingMemRsp <= 1 && io.mem.rsp.fire) {
isActive := False
io.ctrl.cmd.ready := True
}
}
}
when(io.mem.cmd.fire) {
addressCounter := addressCounter + io.ctrl.cmd.burstLength
memCmdCounter := memCmdCounter - 1
}
val memRsp = cloneOf(io.mem.rsp)
memRsp.valid := io.mem.rsp.valid
memRsp.last := io.ctrl.cmd.ready
memRsp.fragment := io.mem.rsp.fragment
val toManyPendingCmd = pendingMemCmd > c.pendingRequetMax-1
val toManyPendingRsp = Bool()
val rspArea = if(c.ctrlRspClock == null || this.clockDomain == c.ctrlRspClock) new Area{
val pendingMemToFifo = CounterMultiRequest(
width=log2Up(c.fifoSize + 1),
io.mem.cmd.fire -> (_ + io.mem.cmd.length),
io.ctrl.rsp.fire -> (_ - 1)
)
toManyPendingRsp := pendingMemToFifo > c.fifoSize-io.ctrl.cmd.burstLength
io.ctrl.rsp << memRsp.toStream.queue(c.fifoSize)
} else new Area{
val fifo = new StreamFifoCC(Fragment(Bits(c.dataWidth bit)),c.fifoSize,pushClock = ClockDomain.current,popClock = c.ctrlRspClock)
fifo.io.push << memRsp.toStream
fifo.io.pop >> io.ctrl.rsp
toManyPendingRsp := RegNext(fifo.io.pushOccupancy) + pendingMemRsp > c.fifoSize-io.ctrl.cmd.burstLength-1 //-1 because of regnext fifo occupancy
}
when(toManyPendingCmd || toManyPendingRsp) {
io.mem.cmd.valid := False
}
io.mem.cmd.address := addressCounter
io.mem.cmd.length := io.ctrl.cmd.burstLength
}
def main(args: Array[String]) {
SpinalVhdl({
val rspClock = null //ClockDomain.external("rspClock")
new Block(Config(
addressWidth = 32,
dataWidth = 32,
memCmdCountMax = 1<<24,
burstLengthMax = 8,
fifoSize = 128,
pendingRequetMax = 4,
ctrlRspClock = rspClock
)).setDefinitionName("TopLevel")
})
}
}