tilelink2 ToAXI4: we need a Queue on B to guarantee deadlock freedom
This commit is contained in:
		| @@ -53,6 +53,13 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule | |||||||
|     require (slaves(0).interleavedId.isDefined) |     require (slaves(0).interleavedId.isDefined) | ||||||
|     slaves.foreach { s => require (s.interleavedId == slaves(0).interleavedId) } |     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) |     // 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.) |     // 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. |     // 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_last = out.r.bits.last | ||||||
|     val r_id = out.r.bits.id |     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 |     if (stateBits <= idBits) { // No need for any state tracking | ||||||
|       r_state := r_id |       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.data := a_state >> implicitBits | ||||||
|         q.io.enq.bits.way  := Mux(a_isPut, UInt(0), UInt(1)) |         q.io.enq.bits.way  := Mux(a_isPut, UInt(0), UInt(1)) | ||||||
|         // Pop the bank's ways |         // 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 |         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... |         // The FIFOs must be valid when we're ready to pop them... | ||||||
|         assert (q.io.deq(0).valid || !q.io.deq(0).ready) |         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 depth = if (combinational) 1 else 2 | ||||||
|     val out_arw = Wire(Decoupled(new AXI4BundleARW(out.params))) |     val out_arw = Wire(Decoupled(new AXI4BundleARW(out.params))) | ||||||
|     val out_w = Wire(out.w) |     val out_w = Wire(out.w) | ||||||
|     out.w <> Queue.irrevocable(out_w, 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, pipe=combinational, flow=combinational) |     val queue_arw = Queue.irrevocable(out_arw, entries=depth, flow=combinational) | ||||||
|  |  | ||||||
|     // Fan out the ARW channel to AR and AW |     // Fan out the ARW channel to AR and AW | ||||||
|     out.ar.bits := queue_arw.bits |     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 |     val r_wins = out.r.valid || r_holds_d | ||||||
|  |  | ||||||
|     out.r.ready := in.d.ready |     out.r.ready := in.d.ready | ||||||
|     out.b.ready := in.d.ready && !r_wins |     out_b.ready := in.d.ready && !r_wins | ||||||
|     in.d.valid := Mux(r_wins, out.r.valid, out.b.valid) |     in.d.valid := Mux(r_wins, out.r.valid, out_b.valid) | ||||||
|  |  | ||||||
|     val r_error = out.r.bits.resp =/= AXI4Parameters.RESP_OKAY |     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 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) |     val b_d = edgeIn.AccessAck(b_addr_lo, b_sink, b_source, b_size, b_error) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user