axi4 ToTL: handle bad AXI addresses
This commit is contained in:
parent
501d6d689f
commit
73010c79a3
@ -56,12 +56,21 @@ class AXI4ToTL extends LazyModule
|
|||||||
val r_size1 = in.ar.bits.bytes1()
|
val r_size1 = in.ar.bits.bytes1()
|
||||||
val r_size = OH1ToUInt(r_size1)
|
val r_size = OH1ToUInt(r_size1)
|
||||||
val r_addr = in.ar.bits.addr
|
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
|
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_out = Wire(out.a)
|
||||||
val w_inflight = RegInit(UInt(0, width = numIds))
|
val w_inflight = RegInit(UInt(0, width = numIds))
|
||||||
@ -70,31 +79,79 @@ class AXI4ToTL extends LazyModule
|
|||||||
val w_size = OH1ToUInt(w_size1)
|
val w_size = OH1ToUInt(w_size1)
|
||||||
val w_addr = in.aw.bits.addr
|
val w_addr = in.aw.bits.addr
|
||||||
val w_ok = edgeOut.manager.supportsPutPartialSafe(w_addr, w_size)
|
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 || 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))
|
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 ok_b = Wire(in.b)
|
||||||
val d_resp = Mux(out_d.bits.error, AXI4Parameters.RESP_SLVERR, AXI4Parameters.RESP_OKAY)
|
val err_b = Wire(in.b)
|
||||||
val d_hasData = edgeOut.hasData(out_d.bits)
|
val mux_b = Wire(in.b)
|
||||||
val (_, d_last, _) = edgeOut.firstlast(out_d.bits, out_d.fire())
|
val ok_r = Wire(in.r)
|
||||||
out_d.ready := Mux(d_hasData, in.r.ready, in.b.ready)
|
val err_r = Wire(in.r)
|
||||||
|
val mux_r = Wire(in.r)
|
||||||
|
|
||||||
in.r.valid := out_d.valid && d_hasData
|
val d_resp = Mux(out.d.bits.error, AXI4Parameters.RESP_SLVERR, AXI4Parameters.RESP_OKAY)
|
||||||
in.r.bits.id := out_d.bits.source >> 1
|
val d_hasData = edgeOut.hasData(out.d.bits)
|
||||||
in.r.bits.data := out_d.bits.data
|
val (_, d_last, _) = edgeOut.firstlast(out.d.bits, out.d.fire())
|
||||||
in.r.bits.resp := d_resp
|
|
||||||
in.r.bits.last := d_last
|
|
||||||
|
|
||||||
in.b.valid := out_d.valid && !d_hasData
|
out.d.ready := Mux(d_hasData, ok_r.ready, ok_b.ready)
|
||||||
in.b.bits.id := out_d.bits.source >> 1
|
ok_r.valid := out.d.valid && d_hasData
|
||||||
in.b.bits.resp := d_resp
|
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
|
// Update flight trackers
|
||||||
val r_set = in.ar.fire().asUInt << in.ar.bits.id
|
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
|
object AXI4ToTL
|
||||||
{
|
{
|
||||||
def apply()(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): TLOutwardNode = {
|
def apply()(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): TLOutwardNode = {
|
||||||
|
Loading…
Reference in New Issue
Block a user