1
0

tilelink2 ToAXI4: we need a Queue on B to guarantee deadlock freedom

This commit is contained in:
Wesley W. Terpstra 2016-10-11 22:26:04 -07:00
parent 38b6c1c820
commit 8e92ac32b7

View File

@ -53,6 +53,13 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule
require (slaves(0).interleavedId.isDefined)
slaves.foreach { s => require (s.interleavedId == slaves(0).interleavedId) }
// We need to ensure that a slave does not stall trying to send B while we need to receive R
// Since R&W have independent flow control, it is possible for a W to cut in-line and get into
// a slave's buffers, preventing us from getting all the R responses we need to release D for B.
// This risk is compounded by an AXI fragmentation. Even a slave which responds completely to
// AR before working on AW might have an AW slipped between two AR fragments.
val out_b = Queue.irrevocable(out.b, entries=edgeIn.client.endSourceId, flow=combinational)
// We need to keep the following state from A => D: (addr_lo, size, sink, source)
// All of those fields could potentially require 0 bits (argh. Chisel.)
// We will pack as many of the lowest bits of state as fit into the AXI ID.
@ -113,7 +120,7 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule
val r_last = out.r.bits.last
val r_id = out.r.bits.id
val b_id = out.b.bits.id
val b_id = out_b.bits.id
if (stateBits <= idBits) { // No need for any state tracking
r_state := r_id
@ -148,7 +155,7 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule
q.io.enq.bits.data := a_state >> implicitBits
q.io.enq.bits.way := Mux(a_isPut, UInt(0), UInt(1))
// Pop the bank's ways
q.io.deq(0).ready := out.b.fire() && b_bankSelect(i)
q.io.deq(0).ready := out_b.fire() && b_bankSelect(i)
q.io.deq(1).ready := out.r.fire() && r_bankSelect(i) && r_last
// The FIFOs must be valid when we're ready to pop them...
assert (q.io.deq(0).valid || !q.io.deq(0).ready)
@ -169,8 +176,8 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule
val depth = if (combinational) 1 else 2
val out_arw = Wire(Decoupled(new AXI4BundleARW(out.params)))
val out_w = Wire(out.w)
out.w <> Queue.irrevocable(out_w, entries=depth, pipe=combinational, flow=combinational)
val queue_arw = Queue.irrevocable(out_arw, entries=depth, pipe=combinational, flow=combinational)
out.w <> Queue.irrevocable(out_w, entries=depth, flow=combinational)
val queue_arw = Queue.irrevocable(out_arw, entries=depth, flow=combinational)
// Fan out the ARW channel to AR and AW
out.ar.bits := queue_arw.bits
@ -211,11 +218,11 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule
val r_wins = out.r.valid || r_holds_d
out.r.ready := in.d.ready
out.b.ready := in.d.ready && !r_wins
in.d.valid := Mux(r_wins, out.r.valid, out.b.valid)
out_b.ready := in.d.ready && !r_wins
in.d.valid := Mux(r_wins, out.r.valid, out_b.valid)
val r_error = out.r.bits.resp =/= AXI4Parameters.RESP_OKAY
val b_error = out.b.bits.resp =/= AXI4Parameters.RESP_OKAY
val b_error = out_b.bits.resp =/= AXI4Parameters.RESP_OKAY
val r_d = edgeIn.AccessAck(r_addr_lo, r_sink, r_source, r_size, UInt(0), r_error)
val b_d = edgeIn.AccessAck(b_addr_lo, b_sink, b_source, b_size, b_error)