diff --git a/src/main/scala/tilelink/HintHandler.scala b/src/main/scala/tilelink/HintHandler.scala index ba0ae383..31d3169d 100644 --- a/src/main/scala/tilelink/HintHandler.scala +++ b/src/main/scala/tilelink/HintHandler.scala @@ -2,88 +2,80 @@ package freechips.rocketchip.tilelink -import Chisel._ +import chisel3._ +import chisel3.util._ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.util.Repeater import scala.math.min // Acks Hints for managers that don't support them or Acks all Hints if !passthrough -class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit p: Parameters) extends LazyModule +class TLHintHandler(passthrough: Boolean = true)(implicit p: Parameters) extends LazyModule { val node = TLAdapterNode( - clientFn = { c => if (!supportClients) c else c.copy(minLatency = min(1, c.minLatency), clients = c.clients .map(_.copy(supportsHint = TransferSizes(1, c.maxTransfer)))) }, - managerFn = { m => if (!supportManagers) m else m.copy(minLatency = min(1, m.minLatency), managers = m.managers.map(_.copy(supportsHint = TransferSizes(1, m.maxTransfer)))) }) + clientFn = { cp => + cp.copy(clients = cp.clients.map { c => c.copy( + sourceId = IdRange(c.sourceId.start*2, c.sourceId.end*2))})}, + managerFn = { mp => + mp.copy(managers = mp.managers.map { m => m.copy( + supportsHint = if (m.supportsHint && passthrough) m.supportsHint else m.supportsPutPartial)})}) lazy val module = new LazyModuleImp(this) { (node.in zip node.out) foreach { case ((in, edgeIn), (out, edgeOut)) => - // Don't add support for clients if there is no BCE channel - val bce = edgeOut.manager.anySupportAcquireB && edgeIn.client.anySupportProbe - require (!supportClients || bce) + out <> in - // Does it even make sense to add the HintHandler? - val smartClients = edgeIn.client.clients.map(_.supportsHint.max == edgeIn.client.maxTransfer).reduce(_&&_) - val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_) + // Does the HintHandler help with this message? + val help = in.a.bits.opcode === TLMessages.Hint && (!passthrough.B || + edgeOut.manager.fastProperty(in.a.bits.address, _.supportsHint.none, (b:Boolean) => b.B)) + val mapPP = WireInit(help) - if (supportManagers && !(passthrough && smartManagers)) { - val address = edgeIn.address(in.a.bits) - val handleA = if (passthrough) !edgeOut.manager.supportsHintFast(address, edgeIn.size(in.a.bits)) else Bool(true) - val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint - val hint = Wire(out.d) - - hint.valid := in.a.valid && hintBitsAtA - out.a.valid := in.a.valid && !hintBitsAtA - in.a.ready := Mux(hintBitsAtA, hint.ready, out.a.ready) - - hint.bits := edgeIn.HintAck(in.a.bits) - out.a.bits := in.a.bits - - TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats1(out.d.bits), out.d), (UInt(0), Queue(hint, 1))) - } else { - out.a.valid := in.a.valid - in.a.ready := out.a.ready - out.a.bits := in.a.bits - - in.d.valid := out.d.valid - out.d.ready := in.d.ready - in.d.bits := out.d.bits + // To handle multi-beat Hints, we need to extend the Hint when creating a PutPartial + // However, when used between a device (SRAM/RegisterRouter/etc) and a Fragmenter, this is not needed + val needRepeater = (edgeIn.manager.managers zip edgeOut.manager.managers) exists { case (in, out) => + !(out.supportsHint && passthrough) && out.supportsPutPartial.max > edgeOut.manager.beatBytes } - if (supportClients && !(passthrough && smartClients)) { - val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true) - val hintBitsAtB = handleB && out.b.bits.opcode === TLMessages.Hint - val hint = Wire(in.c) + val a = if (!needRepeater) in.a else { + val repeater = Module(new Repeater(in.a.bits)) + val mux = Wire(chiselTypeOf(in.a)) - hint.valid := out.b.valid && hintBitsAtB - in.b.valid := out.b.valid && !hintBitsAtB - out.b.ready := Mux(hintBitsAtB, hint.ready, in.b.ready) + repeater.io.repeat := mapPP && !edgeIn.last(out.a) + repeater.io.enq <> in.a + // Work-around broken chisel3 <> + out.a.bits := mux.bits + out.a.valid := mux.valid + mux.ready := out.a.ready - hint.bits := edgeOut.HintAck(out.b.bits) - in.b.bits := out.b.bits + // Only some signals need to be repeated + mux.bits.opcode := in.a.bits.opcode // ignored when full + mux.bits.param := in.a.bits.param // ignored when full + mux.bits.size := repeater.io.deq.bits.size + mux.bits.source := repeater.io.deq.bits.source + mux.bits.address := repeater.io.deq.bits.address + mux.bits.data := in.a.bits.data // irrelevant when full (mask = 0) + mux.bits.mask := in.a.bits.mask // ignored when full + mux.bits.corrupt := in.a.bits.corrupt // irrelevant when full (mask = 0) - TLArbiter(TLArbiter.lowestIndexFirst)(out.c, (edgeIn.numBeats1(in.c.bits), in.c), (UInt(0), Queue(hint, 1))) - } else if (bce) { - in.b.valid := out.b.valid - out.b.ready := in.b.ready - in.b.bits := out.b.bits + mux.valid := repeater.io.deq.valid + repeater.io.deq.ready := mux.ready - out.c.valid := in.c.valid - in.c.ready := out.c.ready - out.c.bits := in.c.bits - } else { - in.b.valid := Bool(false) - in.c.ready := Bool(true) - out.b.ready := Bool(true) - out.c.valid := Bool(false) + mapPP := repeater.io.full || help + mux } - if (bce) { - // Pass E through unchanged - out.e.valid := in.e.valid - in.e.ready := out.e.ready - out.e.bits := in.e.bits - } else { - in.e.ready := Bool(true) - out.e.valid := Bool(false) + // Transform Hint to PutPartialData + out.a.bits.opcode := Mux(mapPP, TLMessages.PutPartialData, a.bits.opcode) + out.a.bits.param := Mux(mapPP, 0.U, a.bits.param) + out.a.bits.mask := Mux(mapPP, 0.U, a.bits.mask) + out.a.bits.source := a.bits.source << 1 | mapPP + + // Transform AccessAck to HintAck + in.d.bits.source := out.d.bits.source >> 1 + in.d.bits.opcode := Mux(out.d.bits.source(0), TLMessages.HintAck, out.d.bits.opcode) + + if (edgeOut.manager.anySupportAcquireB && edgeIn.client.anySupportProbe) { + in.b.bits.source := out.b.bits.source >> 1 + out.c.bits.source := in.c.bits.source << 1 } } } @@ -91,9 +83,9 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f object TLHintHandler { - def apply(supportManagers: Boolean = true, supportClients: Boolean = false, passthrough: Boolean = true)(implicit p: Parameters): TLNode = + def apply(passthrough: Boolean = true)(implicit p: Parameters): TLNode = { - val hints = LazyModule(new TLHintHandler(supportManagers, supportClients, passthrough)) + val hints = LazyModule(new TLHintHandler(passthrough)) hints.node } } @@ -123,5 +115,5 @@ class TLRAMHintHandler(txns: Int)(implicit p: Parameters) extends LazyModule { class TLRAMHintHandlerTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) { val dut = Module(LazyModule(new TLRAMHintHandler(txns)).module) - io.finished := dut.io.finished + io <> dut.io } diff --git a/src/main/scala/unittest/Configs.scala b/src/main/scala/unittest/Configs.scala index 942c42c0..4bb7d26c 100644 --- a/src/main/scala/unittest/Configs.scala +++ b/src/main/scala/unittest/Configs.scala @@ -46,6 +46,7 @@ class WithTLSimpleUnitTests extends Config((site, here, up) => { Module(new TLRAMSimpleTest(4, txns=15*txns, timeout=timeout)), Module(new TLRAMSimpleTest(16, txns=15*txns, timeout=timeout)), Module(new TLRAMZeroDelayTest(4, txns=15*txns, timeout=timeout)), + Module(new TLRAMHintHandlerTest( txns=15*txns, timeout=timeout)), Module(new TLFuzzRAMTest( txns= 3*txns, timeout=timeout)), Module(new TLRR0Test( txns= 3*txns, timeout=timeout)), Module(new TLRR1Test( txns= 3*txns, timeout=timeout)),