diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala index 1ae289fc..1d7eb2ac 100644 --- a/src/main/scala/uncore/axi4/ToTL.scala +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -56,12 +56,21 @@ class AXI4ToTL extends LazyModule val r_size1 = in.ar.bits.bytes1() val r_size = OH1ToUInt(r_size1) val r_addr = in.ar.bits.addr - val r_ok = edgeOut.manager.supportsGetSafe(r_addr, r_size) // !!! decode error + val r_ok = edgeOut.manager.supportsGetSafe(r_addr, r_size) + val r_err_in = Wire(Decoupled(new AXI4BundleRError(in.ar.bits.params))) + val r_err_out = Queue(r_err_in, 2) + val r_count = RegInit(UInt(0, width = in.ar.bits.params.lenBits)) + val r_last = r_count === in.ar.bits.len - in.ar.ready := r_out.ready && !r_block - r_out.valid := in.ar.valid && !r_block - r_out.bits := edgeOut.Get(in.ar.bits.id << 1 | UInt(1), r_addr, r_size)._2 assert (!in.ar.valid || r_size1 === UIntToOH1(r_size, countBits)) // because aligned + in.ar.ready := Mux(r_ok, r_out.ready, r_err_in.ready && r_last) && !r_block + r_out.valid := in.ar.valid && !r_block && r_ok + r_out.bits := edgeOut.Get(in.ar.bits.id << 1 | UInt(1), r_addr, r_size)._2 + r_err_in.valid := in.ar.valid && !r_block && !r_ok + r_err_in.bits.last := r_last + r_err_in.bits.id := in.ar.bits.id + + when (r_err_in.fire()) { r_count := Mux(r_last, UInt(0), r_count + UInt(1)) } val w_out = Wire(out.a) val w_inflight = RegInit(UInt(0, width = numIds)) @@ -70,31 +79,79 @@ class AXI4ToTL extends LazyModule val w_size = OH1ToUInt(w_size1) val w_addr = in.aw.bits.addr val w_ok = edgeOut.manager.supportsPutPartialSafe(w_addr, w_size) + val w_err_in = Wire(Decoupled(in.aw.bits.id)) + val w_err_out = Queue(w_err_in, 2) - in.aw.ready := w_out.ready && in.w.valid && in.w.bits.last && !w_block - in.w.ready := w_out.ready && in.aw.valid && !w_block - w_out.valid := in.aw.valid && in.w.valid && !w_block - w_out.bits := edgeOut.Put(in.aw.bits.id << 1, w_addr, w_size, in.w.bits.data, in.w.bits.strb)._2 assert (!in.aw.valid || w_size1 === UIntToOH1(w_size, countBits)) // because aligned + assert (!in.aw.valid || in.aw.bits.len === UInt(0) || in.aw.bits.size === UInt(log2Ceil(beatBytes))) // because aligned + in.aw.ready := Mux(w_ok, w_out.ready, w_err_in.ready) && in.w.valid && in.w.bits.last && !w_block + in.w.ready := Mux(w_ok, w_out.ready, w_err_in.ready || !in.w.bits.last) && in.aw.valid && !w_block + w_out.valid := in.aw.valid && in.w.valid && !w_block && w_ok + w_out.bits := edgeOut.Put(in.aw.bits.id << 1, w_addr, w_size, in.w.bits.data, in.w.bits.strb)._2 + w_err_in.valid := in.aw.valid && in.w.valid && !w_block && !w_ok && in.w.bits.last + w_err_in.bits := in.aw.bits.id TLArbiter(TLArbiter.lowestIndexFirst)(out.a, (UInt(0), r_out), (in.aw.bits.len, w_out)) - assert (!in.aw.valid || in.aw.bits.len === UInt(0) || in.aw.bits.size === UInt(log2Ceil(beatBytes))) // because aligned - val out_d = Queue.irrevocable(out.d, 1, flow=true) // AXI4 requires irrevocable - val d_resp = Mux(out_d.bits.error, AXI4Parameters.RESP_SLVERR, AXI4Parameters.RESP_OKAY) - val d_hasData = edgeOut.hasData(out_d.bits) - val (_, d_last, _) = edgeOut.firstlast(out_d.bits, out_d.fire()) - out_d.ready := Mux(d_hasData, in.r.ready, in.b.ready) + val ok_b = Wire(in.b) + val err_b = Wire(in.b) + val mux_b = Wire(in.b) + val ok_r = Wire(in.r) + val err_r = Wire(in.r) + val mux_r = Wire(in.r) - in.r.valid := out_d.valid && d_hasData - in.r.bits.id := out_d.bits.source >> 1 - in.r.bits.data := out_d.bits.data - in.r.bits.resp := d_resp - in.r.bits.last := d_last + val d_resp = Mux(out.d.bits.error, AXI4Parameters.RESP_SLVERR, AXI4Parameters.RESP_OKAY) + val d_hasData = edgeOut.hasData(out.d.bits) + val (_, d_last, _) = edgeOut.firstlast(out.d.bits, out.d.fire()) - in.b.valid := out_d.valid && !d_hasData - in.b.bits.id := out_d.bits.source >> 1 - in.b.bits.resp := d_resp + out.d.ready := Mux(d_hasData, ok_r.ready, ok_b.ready) + ok_r.valid := out.d.valid && d_hasData + ok_b.valid := out.d.valid && !d_hasData + + ok_r.bits.id := out.d.bits.source >> 1 + ok_r.bits.data := out.d.bits.data + ok_r.bits.resp := d_resp + ok_r.bits.last := d_last + + r_err_out.ready := err_r.ready + err_r.valid := r_err_out.valid + err_r.bits.id := r_err_out.bits.id + err_r.bits.data := out.d.bits.data // don't care + err_r.bits.resp := AXI4Parameters.RESP_DECERR + err_r.bits.last := r_err_out.bits.last + + // AXI4 must hold R to one source until last + val mux_lock_ok = RegInit(Bool(false)) + val mux_lock_err = RegInit(Bool(false)) + when (ok_r .fire()) { mux_lock_ok := !ok_r .bits.last } + when (err_r.fire()) { mux_lock_err := !err_r.bits.last } + assert (!mux_lock_ok || !mux_lock_err) + + // Prioritize ok over err + mux_r.valid := (!mux_lock_err && ok_r.valid) || (!mux_lock_ok && err_r.valid) + mux_r.bits := Mux(mux_lock_ok || (!mux_lock_err && ok_r.valid), ok_r.bits, err_r.bits) + ok_r.ready := !mux_lock_err && mux_r.ready + err_r.ready := !mux_lock_ok && mux_r.ready && !ok_r.valid + + // AXI4 needs irrevocable behaviour + in.r <> Queue.irrevocable(mux_r, 1, flow=true) + + ok_b.bits.id := out.d.bits.source >> 1 + ok_b.bits.resp := d_resp + + w_err_out.ready := err_b.ready + err_b.valid := w_err_out.valid + err_b.bits.id := w_err_out.bits + err_b.bits.resp := AXI4Parameters.RESP_DECERR + + // Prioritize ok over err + mux_b.valid := ok_b.valid || err_b.valid + mux_b.bits := Mux(ok_b.valid, ok_b.bits, err_b.bits) + ok_b.ready := mux_b.ready + err_b.ready := mux_b.ready && !ok_b.ready + + // AXI4 needs irrevocable behaviour + in.b <> Queue.irrevocable(mux_b, 1, flow=true) // Update flight trackers val r_set = in.ar.fire().asUInt << in.ar.bits.id @@ -111,6 +168,12 @@ class AXI4ToTL extends LazyModule } } +class AXI4BundleRError(params: AXI4BundleParameters) extends AXI4BundleBase(params) +{ + val id = UInt(width = params.idBits) + val last = Bool() +} + object AXI4ToTL { def apply()(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): TLOutwardNode = {