From 99d1e45a49baea628580c8349b04a0bdd0c74d68 Mon Sep 17 00:00:00 2001 From: Vamber Yang Date: Mon, 8 May 2023 00:05:16 -0700 Subject: [PATCH] CoalArbiter RTL outgoing side implementation --- src/main/scala/tilelink/Coalescing.scala | 148 ++++++++++++++++++++++- 1 file changed, 147 insertions(+), 1 deletion(-) diff --git a/src/main/scala/tilelink/Coalescing.scala b/src/main/scala/tilelink/Coalescing.scala index b1cd865..84e1641 100644 --- a/src/main/scala/tilelink/Coalescing.scala +++ b/src/main/scala/tilelink/Coalescing.scala @@ -1814,5 +1814,151 @@ class CoalArbiterImpl(outer: CoalArbiter, } ) + //Helper Class & Method Section + + //Provide an decoupled interface between bundle of 2 different type + class ConverterTunnel[T <: Data, U <: Data]( + genA: T, + genB: U, + conversionFn: T => U + ) extends Module { + val io = IO(new Bundle { + val in = Flipped(Decoupled(genA.cloneType)) + val out = Decoupled(genB.cloneType) + }) + io.in.ready := io.out.ready + io.out.valid := io.in.valid + io.out.bits := conversionFn(io.in.bits) + } + + + def canHitBank(addr: UInt, bankNum: UInt) : Bool = { + val byteOffset = 3 + val bankBase = log2Ceil(config.bankStrideInBytes) + val bankOffset = log2Ceil(config.numArbiterOutputPorts) + (addr(bankBase+bankOffset-byteOffset, bankBase - byteOffset) === bankNum) + } + + //This Operation Could be Expensive + def toGlobalSourceId(isCoalReq : Bool, laneIndex : UInt, sourceID : UInt) : UInt = { + val res = Mux(isCoalReq, + config.numNewSrcIds.U * laneIndex + sourceID, + config.numOldSrcIds.U * laneIndex + sourceID + config.numNewSrcIds.U * config.numCoalReqs.U + ) + res + } + + // + val fullSourceIdRange = config.numOldSrcIds * config.numLanes + config.numNewSrcIds * config.numCoalReqs + + + val nonCoalGiDEntryT = new ReqQueueEntry( + log2Ceil(fullSourceIdRange), + config.wordWidth, + config.addressWidth, + log2Ceil(config.wordSizeInBytes) + ) + // Before a nonCoalesced request enter RR arbiter + // It needs to turn its source into global source id + // Unfortunately this involves extending the width of sourceid field, and a new bundle must be created + // This is a higher order function + def nonCoal2gidReqFn(laneIndex : UInt) + : ReqQueueEntry => ReqQueueEntry = { + def func(lid_req : ReqQueueEntry) : ReqQueueEntry = { + val gid_req = nonCoalGiDEntryT.cloneType + gid_req <> lid_req + gid_req.source := toGlobalSourceId(false.B, laneIndex, lid_req.source) + gid_req + } + func + } + + def nonCoal2TLAFn(edgeOut: TLEdgeOut) : ReqQueueEntry => TLBundleA = { + def func(gid_req : ReqQueueEntry) : TLBundleA = { + gid_req.toTLA(edgeOut) + } + func + } + + ///////////////////////////////////////////////////// + //HDL Implementation Section + ///////////////////////////////////////////////////// + + //Stage 1: Create Queue for nonCoalReqs and CoalReqs + val nonCoalReqsQueues = Seq.tabulate(config.numLanes){_=> + Module(new Queue(nonCoalEntryT.cloneType, 1, true, false)) + } + val coalReqsQueues = Seq.tabulate(config.numCoalReqs){_=> + Module(new Queue(coalEntryT.cloneType, 1, true, false)) + } + //Stage 1a: connect two Queue groups to the input + (io.nonCoalReqs zip nonCoalReqsQueues).foreach{ + case (req, q) => q.io.enq <> req + } + (io.coalReqs zip coalReqsQueues).foreach{ + case (req, q) => q.io.enq <> req + } + //Stage 1b: connect output of Queues to the RR arbiters (each arbiter is for a unique bank) + val nonCoalRRArbiters = Seq.tabulate(config.numArbiterOutputPorts){_=> + Module(new RRArbiter(nonCoalGiDEntryT.cloneType, config.numLanes)) + } + nonCoalReqsQueues.zipWithIndex.foreach{ case(q, q_idx) => + nonCoalRRArbiters.zipWithIndex.foreach{ case(arb, arb_idx) => + val nonCoal2gidFunc = nonCoal2gidReqFn(q_idx.U) + val nonCoalRRArbTunnel = Module(new ConverterTunnel( + coalEntryT.cloneType, + nonCoalGiDEntryT.cloneType, + nonCoal2gidFunc) + ) + nonCoalRRArbTunnel.io.in <> q.io.deq + arb.io.in(q_idx) <> nonCoalRRArbTunnel.io.out + //OverWrite Valid base on if we can actually hit this bank + arb.io.in(q_idx).valid := canHitBank(nonCoalRRArbTunnel.io.out.bits.address, arb_idx.U) + } + } + + //Stage 2, Connect the output of Arbiters to respective nonCoal node + + //Stage 2a, the K Arbiters for Coalesced + (outer.nonCoalNarrowNodes zip nonCoalRRArbiters).foreach{ + case (node, arb) => + val (tlOut, edgeOut) = node.out(0) + val coal2TLAFunc = nonCoal2TLAFn(edgeOut) + val nonCoalTLATunnel = Module(new ConverterTunnel( + arb.io.out.bits.cloneType, + tlOut.a.bits.cloneType, + coal2TLAFunc + ) + ) + nonCoalTLATunnel.io.in <> arb.io.out + tlOut.a <> nonCoalTLATunnel.io.out + } + + //Stage 3, Connect the K edges Identity Node to PO arbiter + // noncoalesced to port 1, coalesced to por1 + + val priorityArbs = Seq.tabulate(config.numArbiterOutputPorts){_=> + Module(new Arbiter(outer.outputNode.out(0)._1.a.bits.cloneType, 2)) + } + ((outer.nonCoalNode.out zip outer.coalNode.out) zip priorityArbs).foreach{ + case (((nonCoalOut, _),(coalOut, _)), arb) => + arb.io.in(1) <> nonCoalOut.a + arb.io.in(0) <> coalOut.a + } + + + //Stage 4, Connect PO arbiter to each edge of output Node + //And make idenitity node passs through the inputs + ((outer.outputNode.in zip outer.outputNode.out) zip priorityArbs).foreach{ + case (((tlIn, _), (tlOut, _)), arb) => + tlOut <> tlIn + tlIn.a <> arb.io.out + } + + } + + + + + -}