diff --git a/src/main/scala/devices/tilelink/BusBypass.scala b/src/main/scala/devices/tilelink/BusBypass.scala new file mode 100644 index 00000000..4bba4bd5 --- /dev/null +++ b/src/main/scala/devices/tilelink/BusBypass.scala @@ -0,0 +1,152 @@ +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.devices.tilelink + +import Chisel._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.coreplex.HasPeripheryBus +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.util._ +import scala.math.min + +class TLBusBypass(beatBytes: Int)(implicit p: Parameters) extends LazyModule +{ + private val nodeIn = TLInputNode() + private val nodeOut = TLOutputNode() + val node = NodeHandle(nodeIn, nodeOut) + + private val bar = LazyModule(new TLBusBypassBar) + private val everything = Seq(AddressSet(0, BigInt("ffffffffffffffffffffffffffffffff", 16))) // 128-bit + private val error = LazyModule(new TLError(ErrorParams(everything), beatBytes)) + bar.node := nodeIn + error.node := bar.node + nodeOut := bar.node + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = nodeIn.bundleIn + val out = nodeOut.bundleOut + val bypass = Bool(INPUT) + } + bar.module.io.bypass := io.bypass + } +} + +private class TLBusBypassBar(implicit p: Parameters) extends LazyModule +{ + // The client only sees the second slave port + val node = TLNexusNode( + numClientPorts = 2 to 2 , + numManagerPorts = 1 to 1, + clientFn = { seq => seq(0) }, + managerFn = { seq => seq(1) }) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + val bypass = Bool(INPUT) + } + + val in = io.in(0) + val out0 = io.out(0) + val out1 = io.out(1) + + val edge = node.edgesIn(0) + val bce = edge.manager.anySupportAcquireB && edge.client.anySupportProbe + + // We need to be locked to the given bypass direction until all transactions stop + val flight = RegInit(UInt(0, width = log2Ceil(3*edge.client.endSourceId+1))) + val bypass = RegInit(io.bypass) // synchronous reset required + + val (a_first, a_last, _) = edge.firstlast(in.a) + val (b_first, b_last, _) = edge.firstlast(in.b) + val (c_first, c_last, _) = edge.firstlast(in.c) + val (d_first, d_last, _) = edge.firstlast(in.d) + val (e_first, e_last, _) = edge.firstlast(in.e) + + val (a_request, a_response) = (edge.isRequest(in.a.bits), edge.isResponse(in.a.bits)) + val (b_request, b_response) = (edge.isRequest(in.b.bits), edge.isResponse(in.b.bits)) + val (c_request, c_response) = (edge.isRequest(in.c.bits), edge.isResponse(in.c.bits)) + val (d_request, d_response) = (edge.isRequest(in.d.bits), edge.isResponse(in.d.bits)) + val (e_request, e_response) = (edge.isRequest(in.e.bits), edge.isResponse(in.e.bits)) + + val a_inc = in.a.fire() && a_first && a_request + val b_inc = in.b.fire() && b_first && b_request + val c_inc = in.c.fire() && c_first && c_request + val d_inc = in.d.fire() && d_first && d_request + val e_inc = in.e.fire() && e_first && e_request + val inc = Cat(Seq(a_inc, d_inc) ++ (if (bce) Seq(b_inc, c_inc, e_inc) else Nil)) + + val a_dec = in.a.fire() && a_last && a_response + val b_dec = in.b.fire() && b_last && b_response + val c_dec = in.c.fire() && c_last && c_response + val d_dec = in.d.fire() && d_last && d_response + val e_dec = in.e.fire() && e_last && e_response + val dec = Cat(Seq(a_dec, d_dec) ++ (if (bce) Seq(b_dec, c_dec, e_dec) else Nil)) + + val next_flight = flight + PopCount(inc) - PopCount(dec) + flight := next_flight + + when (next_flight === UInt(0)) { bypass := io.bypass } + val stall = bypass != io.bypass + + out0.a.valid := !stall && in.a.valid && bypass + out1.a.valid := !stall && in.a.valid && !bypass + in.a.ready := !stall && Mux(bypass, out0.a.ready, out1.a.ready) + out0.a.bits := in.a.bits + out1.a.bits := in.a.bits + + out0.d.ready := in.d.ready && bypass + out1.d.ready := in.d.ready && !bypass + in.d.valid := Mux(bypass, out0.d.valid, out1.d.valid) + + // Argh. The Bundles are not identical, so Mux on bits does not work + in.d.bits.opcode := Mux(bypass, out0.d.bits.opcode, out1.d.bits.opcode) + in.d.bits.param := Mux(bypass, out0.d.bits.param, out1.d.bits.param) + in.d.bits.size := Mux(bypass, out0.d.bits.size, out1.d.bits.size) + in.d.bits.source := Mux(bypass, out0.d.bits.source, out1.d.bits.source) + in.d.bits.sink := Mux(bypass, out0.d.bits.sink, out1.d.bits.sink) + in.d.bits.data := Mux(bypass, out0.d.bits.data, out1.d.bits.data) + in.d.bits.error := Mux(bypass, out0.d.bits.error, out1.d.bits.error) + + if (bce) { + out0.b.ready := in.b.ready && bypass + out1.b.ready := in.b.ready && !bypass + in.b.valid := Mux(bypass, out0.b.valid, out1.b.valid) + + in.b.bits.opcode := Mux(bypass, out0.b.bits.opcode, out1.b.bits.opcode) + in.b.bits.param := Mux(bypass, out0.b.bits.param, out1.b.bits.param) + in.b.bits.size := Mux(bypass, out0.b.bits.size, out1.b.bits.size) + in.b.bits.source := Mux(bypass, out0.b.bits.source, out1.b.bits.source) + in.b.bits.address:= Mux(bypass, out0.b.bits.address,out1.b.bits.address) + in.b.bits.mask := Mux(bypass, out0.b.bits.mask, out1.b.bits.mask) + in.b.bits.data := Mux(bypass, out0.b.bits.data, out1.b.bits.data) + + out0.c.valid := in.c.valid && bypass + out1.c.valid := in.c.valid && !bypass + in.c.ready := Mux(bypass, out0.c.ready, out1.c.ready) + out0.c.bits := in.c.bits + out1.c.bits := in.c.bits + + out0.e.valid := in.e.valid && bypass + out1.e.valid := in.e.valid && !bypass + in.e.ready := Mux(bypass, out0.e.ready, out1.e.ready) + out0.e.bits := in.e.bits + out1.e.bits := in.e.bits + } else { + in.b.valid := Bool(false) + in.c.ready := Bool(true) + in.e.ready := Bool(true) + + out0.b.ready := Bool(true) + out0.c.valid := Bool(false) + out0.e.valid := Bool(false) + + out1.b.ready := Bool(true) + out1.c.valid := Bool(false) + out1.e.valid := Bool(false) + } + } +} diff --git a/src/main/scala/diplomacy/Parameters.scala b/src/main/scala/diplomacy/Parameters.scala index e0c5cef9..1a8bbaa3 100644 --- a/src/main/scala/diplomacy/Parameters.scala +++ b/src/main/scala/diplomacy/Parameters.scala @@ -227,6 +227,7 @@ object AddressRange object AddressSet { + val everything = AddressSet(0, -1) def misaligned(base: BigInt, size: BigInt, tail: Seq[AddressSet] = Seq()): Seq[AddressSet] = { if (size == 0) tail.reverse else { val maxBaseAlignment = base & (-base) // 0 for infinite (LSB)