Commit 5f640c4e authored by Jens Korinth's avatar Jens Korinth
Browse files

FifoAxiAdapter: rewrite to use ASAP bursts

* now has single FIFO of configurable size
* burst size is configurable separately
* burst is started as soon as burstSize is exceeded in buffer
* decided against even more aggressive mode of starting immediately,
  since that would likely be detrimental to system performance
* adapted and verified all unit tests
parent 3447f7f1
packaging @ d2df30ff
Subproject commit a95601ddc899569152337384095bde59694352aa
Subproject commit d2df30ff7306dfc58971b7f4ba6f22bf259d83a7
package chisel.axiutils
import chisel.packaging.CoreDefinition
import chisel.packaging.{CoreDefinition, ModuleBuilder}
import chisel.miscutils.DecoupledDataSource
import scala.sys.process._
import java.nio.file.Paths
......@@ -15,19 +15,20 @@ class FifoAxiAdapterTest1(dataWidth : Int, size: Int) extends Module {
val datasrc = Module (new DecoupledDataSource(UInt(width = dataWidth),
size = 256, n => UInt(n), false))
val fad = Module (new FifoAxiAdapter(addrWidth = addrWidth,
dataWidth = dataWidth, idWidth = 1, size = size))
val fad = Module (new FifoAxiAdapter(fifoDepth = size,
addrWidth = addrWidth,
dataWidth = dataWidth,
burstSize = Some(16)))
io.maxi.renameSignals()
io.base.setName("base")
fad.io.base := io.base
fad.io.inq <> datasrc.io.out
fad.io.enq <> datasrc.io.out
fad.io.maxi <> io.maxi
}
object ModuleBuilder {
val chiselArgs = Array("--backend", "v", "--compile")
object AxiModuleBuilder extends ModuleBuilder {
val modules: List[(() => Module, CoreDefinition)] = List(
( // test module with fixed data
() => Module(new FifoAxiAdapterTest1(dataWidth = 32, 256)),
......@@ -40,10 +41,9 @@ object ModuleBuilder {
)
),
( // generic adapter module FIFO -> AXI
() => Module(new FifoAxiAdapter(addrWidth = 32,
dataWidth = 64,
idWidth = 1,
size = scala.math.pow(2, 24).toInt)),
() => Module(new FifoAxiAdapter(fifoDepth = 8,
addrWidth = 32,
dataWidth = 64)),
CoreDefinition(
name = "FifoAxiAdapter",
vendor = "esa.cs.tu-darmstadt.de",
......@@ -55,8 +55,7 @@ object ModuleBuilder {
( // generic adapter module AXI -> FIFO
() => Module(new AxiFifoAdapter(fifoDepth = 4,
addrWidth = 32,
dataWidth = 32,
idWidth = 1)),
dataWidth = 32)),
CoreDefinition(
name = "AxiFifoAdapter",
vendor = "esa.cs.tu-darmstadt.de",
......@@ -66,13 +65,4 @@ object ModuleBuilder {
)
)
)
def main(args: Array[String]) {
modules foreach { m =>
chiselMain(chiselArgs ++ Array("--targetDir", m._2.root), m._1)
val json = "%s/%s.json".format(m._2.root, m._2.name)
m._2.write(json)
"packaging/package.py %s".format(json) !
}
}
}
......@@ -4,70 +4,85 @@ import AXIDefs._
class FifoAxiAdapterIO(addrWidth: Int, dataWidth: Int, idWidth: Int) extends Bundle {
val maxi = new AXIMasterIF(addrWidth, dataWidth, idWidth)
val inq = Decoupled(UInt(width = dataWidth)).flip()
val enq = Decoupled(UInt(width = dataWidth)).flip()
val base = UInt(INPUT, width = addrWidth)
}
class FifoAxiAdapter(addrWidth: Int,
class FifoAxiAdapter(fifoDepth: Int,
addrWidth: Int,
dataWidth: Int,
idWidth: Int,
size: Int,
stride: Int = 1) extends Module {
require (log2Up(size) <= addrWidth, "addrWidth (%d) must be large enough to address all %d element, at least %d bits".format(addrWidth, size, log2Up(size)))
idWidth: Int = 1,
burstSize: Option[Int] = None,
size: Option[Int] = None) extends Module {
println ("FifoAxiAdapter: size = %d, stride = %d, address bits = %d, data bits = %d"
.format(size, stride, addrWidth, dataWidth))
val bsz = burstSize.getOrElse(fifoDepth)
val io = new FifoAxiAdapterIO(addrWidth, dataWidth, idWidth)
val wdata_valid = /*RegNext(*/io.inq.valid/*)*/
val offs = Reg(UInt(width = log2Up(size * (dataWidth / 8))))
val addr = RegNext(io.base) + offs
val data = io.inq.bits
require (size.map(s => log2Up(s) <= addrWidth).getOrElse(true),
"addrWidth (%d) must be large enough to address all %d element, at least %d bits"
.format(addrWidth, size.get, log2Up(size.get)))
require (size.isEmpty,
"size parameter is not implemented")
require (bsz <= fifoDepth,
"burst size (%d) must be smaller than fifo depth (%d)"
.format(bsz, fifoDepth))
val wa_ready = RegNext(io.maxi.writeAddr.ready)
val wd_ready = RegNext(io.maxi.writeData.ready)
val wr_valid = RegNext(io.maxi.writeResp.valid)
println ("FifoAxiAdapter: fifoDepth = %d, address bits = %d, data bits = %d, id bits = %d%s%s"
.format(fifoDepth, addrWidth, dataWidth, idWidth,
burstSize.map(", burst size = %d".format(_)).getOrElse(""),
size.map(", size = %d".format(_)).getOrElse("")))
val addr_hs = Reg(Bool())
val data_hs = Reg(Bool())
val resp_hs = Reg(Bool())
val io = new FifoAxiAdapterIO(addrWidth, dataWidth, idWidth)
io.maxi.writeAddr.valid := !reset && wdata_valid && !addr_hs
io.maxi.writeAddr.bits.addr := addr
val fifo = Module(new Queue(UInt(width = dataWidth), fifoDepth))
val axi_write :: axi_wait :: Nil = Enum(UInt(), 2)
val state = Reg(init = axi_wait)
val len = Reg(UInt(width = log2Up(bsz)))
val maxi_wlast = len === UInt(0)
val maxi_waddr = Reg(init = io.base)
val maxi_wavalid = state === axi_write && maxi_wlast
val maxi_waready = io.maxi.writeAddr.ready
val maxi_wready = state === axi_write && io.maxi.writeData.ready
val maxi_wvalid = state === axi_write && fifo.io.deq.valid
io.maxi.writeAddr.bits.size := UInt(log2Up(dataWidth / 8)) // full word
io.maxi.writeAddr.bits.len := UInt(0) // single word len
io.maxi.writeAddr.bits.burst := UInt(0) // no burst
io.maxi.writeAddr.bits.id := UInt(0) // id=0
io.maxi.writeAddr.bits.lock := UInt(0) // no lock
io.maxi.writeAddr.bits.cache := UInt(2) // no cache, modifiable
io.maxi.writeAddr.bits.prot := UInt(0) // no prot
io.maxi.writeAddr.bits.qos := UInt(0) // no qos
io.enq <> fifo.io.enq
io.maxi.writeData.bits.last := maxi_wlast
io.maxi.writeData.bits.data := fifo.io.deq.bits
io.maxi.writeData.valid := maxi_wvalid
io.maxi.writeAddr.valid := maxi_wavalid
fifo.io.deq.ready := state === axi_write && io.maxi.writeData.ready
io.maxi.writeData.bits.data := data
io.maxi.writeData.bits.last := Bool(true)
// AXI boilerplate
io.maxi.writeAddr.bits.addr := maxi_waddr
io.maxi.writeAddr.bits.size := UInt(if (dataWidth > 8) log2Up(dataWidth / 8) else 0)
io.maxi.writeAddr.bits.len := UInt(bsz - 1)
io.maxi.writeAddr.bits.burst := UInt("b01") // INCR
io.maxi.writeAddr.bits.id := UInt(0)
io.maxi.writeAddr.bits.lock := UInt(0)
io.maxi.writeAddr.bits.cache := UInt("b1110") // write-through, RW allocate
io.maxi.writeAddr.bits.prot := UInt(0)
io.maxi.writeAddr.bits.qos := UInt(0)
io.maxi.writeData.bits.strb := UInt("b" + ("1" * (dataWidth / 8)))
io.maxi.writeData.valid := !reset && wdata_valid && !data_hs
io.maxi.writeResp.ready := Bool(true)
io.maxi.writeResp.ready := UInt(1) // ignore responses
io.inq.ready := addr_hs && data_hs && resp_hs
// read channel tie-offs
io.maxi.readAddr.valid := Bool(false)
io.maxi.readData.ready := Bool(false)
when (reset) {
offs := UInt(0)
addr_hs := Bool(false)
data_hs := Bool(false)
resp_hs := Bool(false)
state := axi_wait
len := UInt(0)
}
.otherwise {
when (wdata_valid && wa_ready) { addr_hs := Bool(true) }
when (wdata_valid && wd_ready) { data_hs := Bool(true) }
when (wr_valid) { resp_hs := Bool(true) }
when (addr_hs && data_hs && resp_hs) {
offs := offs + UInt(dataWidth / 8 * stride) // stride to bytes
addr_hs := Bool(false)
data_hs := Bool(false)
resp_hs := Bool(false)
when (state === axi_wait && fifo.io.count >= UInt(bsz)) { state := axi_write }
when (state === axi_write) {
when (maxi_wavalid && maxi_waready) {
maxi_waddr := maxi_waddr + UInt(bsz * (dataWidth / 8))
len := UInt(bsz - 1)
}
when (maxi_wready && maxi_wvalid) {
when (maxi_wlast) { state := Mux(fifo.io.count >= UInt(bsz), state, axi_wait) }
.otherwise { len := len - UInt(1) }
}
}
}
}
......@@ -34,10 +34,10 @@ class Axi2AxiModule(val dataWidth: Int,
repeat = false))
val fad = Module(new FifoAxiAdapter(
fifoDepth = sz,
addrWidth = aw,
dataWidth = dataWidth,
idWidth = 1,
size = sz))
burstSize = Some(fifoDepth)))
val saxi = Module(new AxiSlaveModel(
addrWidth = addrWidth,
......@@ -53,7 +53,7 @@ class Axi2AxiModule(val dataWidth: Int,
val base = UInt(0, width = aw)
fad.io.inq <> dsrc.io.out
fad.io.enq <> dsrc.io.out
saxi.io.saxi.writeAddr <> fad.io.maxi.writeAddr
saxi.io.saxi.writeData <> fad.io.maxi.writeData
saxi.io.saxi.writeResp <> fad.io.maxi.writeResp
......
......@@ -4,10 +4,6 @@ import AXIDefs._
class AxiSlaveModelIO(addrWidth: Int, dataWidth: Int, idWidth: Int) extends Bundle {
val saxi = new AXIMasterIF(addrWidth, dataWidth, idWidth).flip()
val mem = new Bundle {
val d = UInt(OUTPUT, width = dataWidth)
val addr = UInt(INPUT, width = addrWidth)
}
}
class AxiSlaveModel(val addrWidth: Option[Int],
......@@ -26,10 +22,10 @@ class AxiSlaveModel(val addrWidth: Option[Int],
/** WRITE PROCESS **/
val wa_valid = RegNext(io.saxi.writeAddr.valid)
val wd_valid = RegNext(io.saxi.writeData.valid)
val wd_valid = (io.saxi.writeData.valid)
val wr_ready = RegNext(io.saxi.writeResp.ready)
val wa_addr = RegNext(io.saxi.writeAddr.bits.addr)
val wd_data = RegNext(io.saxi.writeData.bits.data)
val wd_data = (io.saxi.writeData.bits.data)
val wa_len = RegNext(io.saxi.writeAddr.bits.len)
val wa_size = RegNext(io.saxi.writeAddr.bits.size)
val wa_burst = RegNext(io.saxi.writeAddr.bits.burst)
......@@ -44,15 +40,11 @@ class AxiSlaveModel(val addrWidth: Option[Int],
val wr_hs = Reg(Bool()) // response handshake complete?
val wr_valid = Reg(Bool()) // response valid
val raddr = RegNext(io.mem.addr)
io.saxi.writeAddr.ready := !wa_hs
io.saxi.writeData.ready := wa_hs
io.saxi.writeData.ready := wa_hs && !wr_valid
io.saxi.writeResp.bits.resp := wr
io.saxi.writeResp.bits.id := UInt(0)
io.saxi.writeResp.valid := wr_valid
io.mem.d := mem(raddr)
io.saxi.writeResp.valid := wa_hs && wr_valid
when (reset) {
wa := UInt(0)
......@@ -62,19 +54,19 @@ class AxiSlaveModel(val addrWidth: Option[Int],
wa_hs := Bool(false)
wd_hs := Bool(false)
wr_hs := Bool(false)
raddr := UInt(0)
}
.otherwise {
when (!wa_hs && wa_valid) {
wa := wa_addr
wl := wa_len
wa_hs := Bool(true)
assert (wa_size === UInt(log2Up(dataWidth / 8)), "wa_size is not supported".format(wa_size))
assert (wa_size === UInt(if (dataWidth > 8) log2Up(dataWidth / 8) else 0), "wa_size is not supported".format(wa_size))
assert (wa_burst < UInt(2), "wa_burst type (b%s) not supported".format(wa_burst))
}
when (wa_hs && wd_valid) {
when (wa_hs && wd_valid && !wr_valid) {
mem(if (dataWidth > 8) wa >> UInt(log2Up(dataWidth / 8)) else wa) := wd_data
when (wl === UInt(0)) { wr_valid := Bool(true) }
printf("writing data 0x%x to address 0x%x\n", wd_data, wa)
when (io.saxi.writeData.bits.last || wl === UInt(0)) { wr_valid := Bool(true) }
.otherwise {
wl := wl - UInt(1)
// increase address in INCR bursts
......
......@@ -8,13 +8,15 @@ import org.junit.Assert._
class FifoAxiAdapterModule1(dataWidth : Int, size: Int) extends Module {
val io = new Bundle
val datasrc = Module (new DecoupledDataSource(UInt(width = dataWidth), size = 256, n => UInt(n), false))
val fad = Module (new FifoAxiAdapter(addrWidth = log2Up(size),
dataWidth = dataWidth, idWidth = 1, size = size))
val fad = Module (new FifoAxiAdapter(fifoDepth = size,
addrWidth = log2Up(size),
dataWidth = dataWidth,
burstSize = Some(16)))
val saxi = Module (new AxiSlaveModel(addrWidth = Some(log2Up(size * (dataWidth / 8))),
dataWidth = dataWidth, idWidth = 1))
fad.io.base := UInt(0)
fad.io.inq <> datasrc.io.out
fad.io.enq <> datasrc.io.out
fad.io.maxi <> saxi.io.saxi
}
......@@ -25,7 +27,7 @@ class FifoAxiAdapterSuite extends JUnitSuite {
}
}
class FifoAxiAdapterModule1Test(fad: FifoAxiAdapterModule1) extends Tester(fad, false) {
class FifoAxiAdapterModule1Test(fad: FifoAxiAdapterModule1) extends Tester(fad, isTrace = true) {
import scala.util.Properties.{lineSeparator => NL}
private var cc = 0
......@@ -40,7 +42,7 @@ class FifoAxiAdapterModule1Test(fad: FifoAxiAdapterModule1) extends Tester(fad,
"b%%%ds".format(fad.saxi.dataWidth).format(v.toString(2)).replace(' ', '0')
reset(10)
while (peek(fad.datasrc.io.out.valid) != 0) step(1)
while (peek(fad.datasrc.io.out.valid) != 0 || peek(fad.fad.fifo.io.count) > 0) step(1)
step(10) // settle
// check
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment