1
0
Fork 0

axi4 Fragmenter: refine sideband FSM for case of last fragment

This commit is contained in:
Wesley W. Terpstra 2016-10-13 14:57:01 -07:00
parent 19064e602b
commit 8005266131
1 changed files with 27 additions and 10 deletions

View File

@ -18,7 +18,7 @@ class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational
def mapSlave(s: AXI4SlaveParameters, beatBytes: Int) = s.copy(
supportsWrite = expandTransfer(s.supportsWrite, beatBytes, s.minAlignment),
supportsRead = expandTransfer(s.supportsRead, beatBytes, s.minAlignment),
interleavedId = if (lite) Some(0) else s.interleavedId) // we preserve interleaving guarantees
interleavedId = if (lite) Some(0) else s.interleavedId) // see AXI4FragmenterSideband for !lite case
def mapMaster(m: AXI4MasterParameters) = m.copy(aligned = true)
val node = AXI4AdapterNode(
@ -238,29 +238,46 @@ class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational
}
}
/* We want to put barriers between the fragments of a fragmented transfer and all other transfers.
* This lets us use very little state to reassemble the fragments (else we need one FIFO per ID).
* Furthermore, because all the fragments share the same AXI ID, they come back contiguously.
* This guarantees that no other R responses might get mixed between fragments, ensuring that the
* interleavedId for the slaves remains unaffected by the fragmentation transformation.
* Of course, if you need to fragment, this means there is a potentially hefty serialization cost.
* However, this design allows full concurrency in the common no-fragmentation-needed scenario.
*/
class AXI4FragmenterSideband(maxInFlight: Int, flow: Boolean = false) extends Module
{
val io = new QueueIO(Bool(), maxInFlight)
io.count := UInt(0)
val state = RegInit(Bool(false))
val count = RegInit(UInt(0, width = log2Up(maxInFlight)))
val idle = count === UInt(0)
val PASS = UInt(2, width = 2) // allow 'last=1' bits to enque, on 'last=0' if count>0 block else accept+FIND
val FIND = UInt(0, width = 2) // allow 'last=0' bits to enque, accept 'last=1' and switch to WAIT
val WAIT = UInt(1, width = 2) // block all access till count=0
io.deq.bits := state
io.deq.valid := !idle
val state = RegInit(PASS)
val count = RegInit(UInt(0, width = log2Up(maxInFlight)))
val empty = count === UInt(0)
val last = count === UInt(1)
io.deq.bits := state(1) || (last && state(0)) // PASS || (last && WAIT)
io.deq.valid := !empty
io.enq.ready := empty || (state === FIND) || (state === PASS && io.enq.bits)
if (flow) {
when (io.enq.valid) {
io.deq.valid := Bool(true)
when (idle) { io.deq.bits := io.enq.bits }
when (empty) { io.deq.bits := io.enq.bits }
}
}
io.enq.ready := idle || (state === io.enq.bits)
when (io.enq.fire()) { state := io.enq.bits }
count := count + io.enq.fire() - io.deq.fire()
switch (state) {
is(PASS) { when (io.enq.valid && !io.enq.bits && empty) { state := FIND } }
is(FIND) { when (io.enq.valid && io.enq.bits) { state := Mux(empty, PASS, WAIT) } }
is(WAIT) { when (last && io.deq.ready) { state := PASS } }
}
}
object AXI4Fragmenter