From d09f43c32ff2b24c45023a71f2f9d27627d9b44f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 16 Oct 2016 21:59:39 -0700 Subject: [PATCH 1/6] axi4 Bundles: add a size calculation helper The old version was wrong. Inverting before the << has a different width. This means you end up with high bits set. --- src/main/scala/uncore/axi4/Bundles.scala | 7 +++++++ src/main/scala/uncore/axi4/Fragmenter.scala | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/axi4/Bundles.scala b/src/main/scala/uncore/axi4/Bundles.scala index 89fdbc9f..95068cab 100644 --- a/src/main/scala/uncore/axi4/Bundles.scala +++ b/src/main/scala/uncore/axi4/Bundles.scala @@ -20,6 +20,13 @@ abstract class AXI4BundleA(params: AXI4BundleParameters) extends AXI4BundleBase( val prot = UInt(width = params.protBits) val qos = UInt(width = params.qosBits) // 0=no QoS, bigger = higher priority // val region = UInt(width = 4) // optional + + // Number of bytes-1 in this operation + def bytes1(x:Int=0) = { + val maxShift = 1 << params.sizeBits + val tail = UInt((BigInt(1) << maxShift) - 1) + (Cat(len, tail) << size) >> maxShift + } } // A non-standard bundle that can be both AR and AW diff --git a/src/main/scala/uncore/axi4/Fragmenter.scala b/src/main/scala/uncore/axi4/Fragmenter.scala index 57015359..3fd714f7 100644 --- a/src/main/scala/uncore/axi4/Fragmenter.scala +++ b/src/main/scala/uncore/axi4/Fragmenter.scala @@ -103,7 +103,7 @@ class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational val beats = ~(~(beats1 << 1 | UInt(1)) | beats1) // beats1 + 1 val inc_addr = addr + (beats << a.bits.size) // address after adding transfer - val wrapMask = ~(~a.bits.len << a.bits.size) // only these bits may change, if wrapping + val wrapMask = a.bits.bytes1() // only these bits may change, if wrapping val mux_addr = Wire(init = inc_addr) when (a.bits.burst === AXI4Parameters.BURST_WRAP) { mux_addr := (inc_addr & wrapMask) | ~(~a.bits.addr | wrapMask) From 72e5a97d40fc9396234af8ccebdd9d8cfcc5fb57 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 16 Oct 2016 19:57:56 -0700 Subject: [PATCH 2/6] tilelink2: factor out the OH1ToOH function --- src/main/scala/uncore/axi4/Fragmenter.scala | 4 ++-- src/main/scala/uncore/tilelink2/package.scala | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/scala/uncore/axi4/Fragmenter.scala b/src/main/scala/uncore/axi4/Fragmenter.scala index 3fd714f7..05ca2b0d 100644 --- a/src/main/scala/uncore/axi4/Fragmenter.scala +++ b/src/main/scala/uncore/axi4/Fragmenter.scala @@ -7,7 +7,7 @@ import chisel3.internal.sourceinfo.SourceInfo import chisel3.util.IrrevocableIO import diplomacy._ import scala.math.{min,max} -import uncore.tilelink2.{leftOR, rightOR, UIntToOH1} +import uncore.tilelink2.{leftOR, rightOR, UIntToOH1, OH1ToOH} // lite: masters all use only one ID => reads will not be interleaved class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational: Boolean = true) extends LazyModule @@ -100,7 +100,7 @@ class AXI4Fragmenter(lite: Boolean = false, maxInFlight: Int = 32, combinational // The number of beats-1 to execute val beats1 = Mux(bad, UInt(0), maxSupported1) - val beats = ~(~(beats1 << 1 | UInt(1)) | beats1) // beats1 + 1 + val beats = OH1ToOH(beats1) // beats1 + 1 val inc_addr = addr + (beats << a.bits.size) // address after adding transfer val wrapMask = a.bits.bytes1() // only these bits may change, if wrapping diff --git a/src/main/scala/uncore/tilelink2/package.scala b/src/main/scala/uncore/tilelink2/package.scala index 415aa308..55ff6b27 100644 --- a/src/main/scala/uncore/tilelink2/package.scala +++ b/src/main/scala/uncore/tilelink2/package.scala @@ -8,7 +8,8 @@ package object tilelink2 type TLOutwardNode = OutwardNodeHandle[TLClientPortParameters, TLManagerPortParameters, TLBundle] type TLAsyncOutwardNode = OutwardNodeHandle[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle] type IntOutwardNode = OutwardNodeHandle[IntSourcePortParameters, IntSinkPortParameters, Vec[Bool]] - def OH1ToUInt(x: UInt) = OHToUInt((x << 1 | UInt(1)) ^ x) + def OH1ToOH(x: UInt) = (x << 1 | UInt(1)) & ~Cat(UInt(0, width=1), x) + def OH1ToUInt(x: UInt) = OHToUInt(OH1ToOH(x)) def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None // Fill 1s from low bits to high bits From 5a1da63b5a3e22fb95de982e794839e13c38f142 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 16 Oct 2016 19:47:58 -0700 Subject: [PATCH 3/6] axi4: prototype ToTL adapter --- src/main/scala/uncore/axi4/ToTL.scala | 121 ++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/main/scala/uncore/axi4/ToTL.scala diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala new file mode 100644 index 00000000..1ae289fc --- /dev/null +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -0,0 +1,121 @@ +// See LICENSE for license details. + +package uncore.axi4 + +import Chisel._ +import chisel3.internal.sourceinfo.SourceInfo +import diplomacy._ +import uncore.tilelink2._ + +case class AXI4ToTLNode() extends MixedNode(AXI4Imp, TLImp)( + dFn = { case (1, Seq(AXI4MasterPortParameters(masters))) => + Seq(TLClientPortParameters(clients = masters.map { m => + TLClientParameters( + sourceId = IdRange(m.id.start << 1, m.id.end << 1), // R+W ids are distinct + nodePath = m.nodePath) + })) + }, + uFn = { case (1, Seq(TLManagerPortParameters(managers, beatBytes, _))) => + Seq(AXI4SlavePortParameters(beatBytes = beatBytes, slaves = managers.map { m => + AXI4SlaveParameters( + address = m.address, + regionType = m.regionType, + executable = m.executable, + nodePath = m.nodePath, + supportsWrite = m.supportsPutPartial, + supportsRead = m.supportsGet, + interleavedId = Some(0)) // TL2 never interleaves D beats + })) + }, + numPO = 1 to 1, + numPI = 1 to 1) + +class AXI4ToTL extends LazyModule +{ + val node = AXI4ToTLNode() + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val in = io.in(0) + val out = io.out(0) + val edgeIn = node.edgesIn(0) + val edgeOut = node.edgesOut(0) + val numIds = edgeIn.master.endId + val beatBytes = edgeOut.manager.beatBytes + val countBits = AXI4Parameters.lenBits + (1 << AXI4Parameters.sizeBits) - 1 + + require (edgeIn.master.masters(0).aligned) + + val r_out = Wire(out.a) + val r_inflight = RegInit(UInt(0, width = numIds)) + val r_block = r_inflight(in.ar.bits.id) + 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 + + 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 + + val w_out = Wire(out.a) + val w_inflight = RegInit(UInt(0, width = numIds)) + val w_block = w_inflight(in.aw.bits.id) + val w_size1 = in.aw.bits.bytes1() + val w_size = OH1ToUInt(w_size1) + val w_addr = in.aw.bits.addr + val w_ok = edgeOut.manager.supportsPutPartialSafe(w_addr, w_size) + + 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 + + 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) + + 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 + + in.b.valid := out_d.valid && !d_hasData + in.b.bits.id := out_d.bits.source >> 1 + in.b.bits.resp := d_resp + + // Update flight trackers + val r_set = in.ar.fire().asUInt << in.ar.bits.id + val r_clr = (in.r.fire() && in.r.bits.last).asUInt << in.r.bits.id + r_inflight := (r_inflight | r_set) & ~r_clr + val w_set = in.aw.fire().asUInt << in.aw.bits.id + val w_clr = in.b.fire().asUInt << in.b.bits.id + w_inflight := (w_inflight | w_set) & ~w_clr + + // Unused channels + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) + } +} + +object AXI4ToTL +{ + def apply()(x: AXI4OutwardNode)(implicit sourceInfo: SourceInfo): TLOutwardNode = { + val tl = LazyModule(new AXI4ToTL) + tl.node := x + tl.node + } +} From 501d6d689f40af09d87ca54e65c7596d863743c0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Sun, 16 Oct 2016 20:18:49 -0700 Subject: [PATCH 4/6] axi4: Test ToTL --- src/main/scala/uncore/axi4/Test.scala | 50 +++++++++++++++++++++++++++ src/main/scala/unittest/Configs.scala | 3 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/scala/uncore/axi4/Test.scala b/src/main/scala/uncore/axi4/Test.scala index 53620ff3..42ce02bf 100644 --- a/src/main/scala/uncore/axi4/Test.scala +++ b/src/main/scala/uncore/axi4/Test.scala @@ -59,3 +59,53 @@ class AXI4FullFuzzRAMTest extends UnitTest(500000) { val dut = Module(LazyModule(new AXI4FullFuzzRAM).module) io.finished := dut.io.finished } + +class AXI4FuzzMaster extends LazyModule +{ + val node = AXI4OutputNode() + val fuzz = LazyModule(new TLFuzzer(5000)) + val model = LazyModule(new TLRAMModel("AXI4FuzzMaster")) + + model.node := fuzz.node + node := TLToAXI4(4)(model.node) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val out = node.bundleOut + val finished = Bool(OUTPUT) + } + + io.finished := fuzz.module.io.finished + } +} + +class AXI4FuzzSlave extends LazyModule +{ + val node = AXI4InputNode() + val ram = LazyModule(new TLRAM(AddressSet(0x0, 0xfff))) + + ram.node := TLFragmenter(4, 16)(AXI4ToTL()(AXI4Fragmenter()(node))) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + } + } +} + +class AXI4FuzzBridge extends LazyModule +{ + val master = LazyModule(new AXI4FuzzMaster) + val slave = LazyModule(new AXI4FuzzSlave) + + slave.node := master.node + + lazy val module = new LazyModuleImp(this) with HasUnitTestIO { + io.finished := master.module.io.finished + } +} + +class AXI4BridgeTest extends UnitTest(500000) { + val dut = Module(LazyModule(new AXI4FuzzBridge).module) + io.finished := dut.io.finished +} diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index ac0488af..054e47fb 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -27,7 +27,8 @@ class WithUncoreUnitTests extends Config( Module(new uncore.devices.TileLinkRAMTest()(p)), Module(new uncore.tilelink2.TLFuzzRAMTest), Module(new uncore.axi4.AXI4LiteFuzzRAMTest), - Module(new uncore.axi4.AXI4FullFuzzRAMTest)) + Module(new uncore.axi4.AXI4FullFuzzRAMTest), + Module(new uncore.axi4.AXI4BridgeTest)) case _ => throw new CDEMatchError } ) From 73010c79a33d95164b165175114257fc06b8856d Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 17 Oct 2016 00:12:26 -0700 Subject: [PATCH 5/6] axi4 ToTL: handle bad AXI addresses --- src/main/scala/uncore/axi4/ToTL.scala | 107 ++++++++++++++++++++------ 1 file changed, 85 insertions(+), 22 deletions(-) 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 = { From 7c334e3c34ff89ea6a86c7ef08a4babdda44bf45 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 17 Oct 2016 00:56:54 -0700 Subject: [PATCH 6/6] axi4 ToTL: shorter critical path on Q.bits if errors go first --- src/main/scala/uncore/axi4/ToTL.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala index 1d7eb2ac..ea94da6a 100644 --- a/src/main/scala/uncore/axi4/ToTL.scala +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -127,11 +127,11 @@ class AXI4ToTL extends LazyModule when (err_r.fire()) { mux_lock_err := !err_r.bits.last } assert (!mux_lock_ok || !mux_lock_err) - // Prioritize ok over err + // Prioritize err over ok (b/c err_r.valid comes from a register) 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 + mux_r.bits := Mux(!mux_lock_ok && err_r.valid, err_r.bits, ok_r.bits) + ok_r.ready := !mux_lock_err && mux_r.ready && !err_r.valid + err_r.ready := !mux_lock_ok && mux_r.ready // AXI4 needs irrevocable behaviour in.r <> Queue.irrevocable(mux_r, 1, flow=true) @@ -144,11 +144,11 @@ class AXI4ToTL extends LazyModule err_b.bits.id := w_err_out.bits err_b.bits.resp := AXI4Parameters.RESP_DECERR - // Prioritize ok over err + // Prioritize err over ok (b/c err_b.valid comes from a register) 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 + mux_b.bits := Mux(err_b.valid, err_b.bits, ok_b.bits) + ok_b.ready := mux_b.ready && !err_b.valid + err_b.ready := mux_b.ready // AXI4 needs irrevocable behaviour in.b <> Queue.irrevocable(mux_b, 1, flow=true)