1package xiangshan.backend 2 3import bus.simplebus.SimpleBusUC 4import chisel3._ 5import chisel3.util._ 6import chisel3.util.experimental.BoringUtils 7import noop.MemMMUIO 8import xiangshan._ 9import xiangshan.backend.decode.{DecodeBuffer, DecodeStage} 10import xiangshan.backend.rename.Rename 11import xiangshan.backend.brq.Brq 12import xiangshan.backend.dispatch.Dispatch 13import xiangshan.backend.exu._ 14import xiangshan.backend.fu.FunctionUnit 15import xiangshan.backend.issue.{IssueQueue, ReservationStationNew} 16import xiangshan.backend.regfile.{Regfile, RfWritePort} 17import xiangshan.backend.roq.Roq 18import xiangshan.mem._ 19import utils.ParallelOR 20 21/** Backend Pipeline: 22 * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe 23 */ 24class Backend extends XSModule 25 with NeedImpl { 26 val io = IO(new Bundle { 27 val frontend = Flipped(new FrontendToBackendIO) 28 val mem = Flipped(new MemToBackendIO) 29 }) 30 31 32 val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit)) 33 val jmpExeUnit = Module(new JmpExeUnit) 34 val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit)) 35 val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit)) 36 // val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac)) 37 // val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc)) 38 // val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt)) 39 val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits) 40 exeUnits.foreach(_.io.exception := DontCare) 41 exeUnits.foreach(_.io.dmem := DontCare) 42 exeUnits.foreach(_.io.mcommit := DontCare) 43 44 val decode = Module(new DecodeStage) 45 val brq = Module(new Brq) 46 val decBuf = Module(new DecodeBuffer) 47 val rename = Module(new Rename) 48 val dispatch = Module(new Dispatch) 49 val roq = Module(new Roq) 50 val intRf = Module(new Regfile( 51 numReadPorts = NRIntReadPorts, 52 numWirtePorts = NRIntWritePorts, 53 hasZero = true 54 )) 55 val fpRf = Module(new Regfile( 56 numReadPorts = NRFpReadPorts, 57 numWirtePorts = NRFpWritePorts, 58 hasZero = false 59 )) 60 61 // backend redirect, flush pipeline 62 val redirect = Mux( 63 roq.io.redirect.valid, 64 roq.io.redirect, 65 Mux( 66 brq.io.redirect.valid, 67 brq.io.redirect, 68 io.mem.replayAll 69 ) 70 ) 71 72 io.frontend.redirect := redirect 73 io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay 74 75 val memConfigs = 76 Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++ 77 Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg) 78 79 val exuConfigs = exeUnits.map(_.config) ++ memConfigs 80 81 val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout 82 83 def needWakeup(cfg: ExuConfig): Boolean = 84 (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf) 85 86 def needData(a: ExuConfig, b: ExuConfig): Boolean = 87 (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf) 88 89 90 val reservedStations = exuConfigs.zipWithIndex.map({ case (cfg, i) => 91 92 // NOTE: exu could have certern and uncertaion latency 93 // but could not have multiple certern latency 94 var certainLatency = -1 95 if(cfg.hasCertainLatency) { certainLatency = cfg.latency.latencyVal.get } 96 97 val writeBackedData = exuConfigs.zip(exeWbReqs).filter(x => x._1.hasCertainLatency && needData(cfg, x._1)).map(_._2.bits.data) 98 val wakeupCnt = writeBackedData.length 99 100 val extraListenPorts = exuConfigs 101 .zip(exeWbReqs) 102 .filter(x => x._1.hasUncertainlatency && needData(cfg, x._1)) 103 .map(_._2) 104 val extraListenPortsCnt = extraListenPorts.length 105 106 val feedback = (cfg == Exu.ldExeUnitCfg) || (cfg == Exu.stExeUnitCfg) 107 108 println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}") 109 110 val rs = Module(new ReservationStationNew(cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback)) 111 112 rs.io.redirect <> redirect 113 rs.io.numExist <> dispatch.io.numExist(i) 114 rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 115 rs.io.enqData <> dispatch.io.enqIQData(i) 116 117 rs.io.writeBackedData <> writeBackedData 118 for((x, y) <- rs.io.extraListenPorts.zip(extraListenPorts)){ 119 x.valid := y.fire() 120 x.bits := y.bits 121 } 122 123 cfg match { 124 case Exu.ldExeUnitCfg => 125 case Exu.stExeUnitCfg => 126 case otherCfg => 127 exeUnits(i).io.in <> rs.io.deq 128 exeUnits(i).io.redirect <> redirect 129 rs.io.tlbFeedback := DontCare 130 } 131 132 rs 133 }) 134 135 for(rs <- reservedStations){ 136 rs.io.broadcastedUops <> reservedStations. 137 filter(x => x.exuCfg.hasCertainLatency && needData(rs.exuCfg, x.exuCfg)). 138 map(_.io.selectedUop) 139 } 140 141 io.mem.commits <> roq.io.commits 142 io.mem.roqDeqPtr := roq.io.roqDeqPtr 143 io.mem.ldin <> reservedStations.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq) 144 io.mem.stin <> reservedStations.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq) 145 io.mem.tlbFeedback <> reservedStations.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.tlbFeedback) ++ reservedStations.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.tlbFeedback) 146 jmpExeUnit.io.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException 147 jmpExeUnit.io.exception.bits := roq.io.exception 148 149 io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo 150 io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo 151 152 decode.io.in <> io.frontend.cfVec 153 brq.io.roqRedirect <> roq.io.redirect 154 brq.io.memRedirect <> io.mem.replayAll 155 brq.io.bcommit := roq.io.bcommit 156 brq.io.enqReqs <> decode.io.toBrq 157 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 158 x.bits := y.io.out.bits 159 x.valid := y.io.out.fire() && y.io.out.bits.redirectValid 160 } 161 decode.io.brTags <> brq.io.brTags 162 decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this 163 decBuf.io.redirect <> redirect 164 decBuf.io.in <> decode.io.out 165 166 rename.io.redirect <> redirect 167 rename.io.roqCommits <> roq.io.commits 168 rename.io.in <> decBuf.io.out 169 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.memIntRf.map(_.addr) 170 rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy 171 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.memFpRf.map(_.addr) 172 rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy 173 rename.io.replayPregReq <> dispatch.io.replayPregReq 174 dispatch.io.redirect <> redirect 175 dispatch.io.fromRename <> rename.io.out 176 177 roq.io.memRedirect <> io.mem.replayAll 178 roq.io.brqRedirect <> brq.io.redirect 179 roq.io.dp1Req <> dispatch.io.toRoq 180 dispatch.io.roqIdxs <> roq.io.roqIdxs 181 io.mem.dp1Req <> dispatch.io.toLsroq 182 dispatch.io.lsIdxs <> io.mem.lsIdxs 183 dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid 184 // store writeback must be after commit roqIdx 185 dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits) 186 187 188 intRf.io.readPorts <> dispatch.io.readIntRf ++ dispatch.io.memIntRf 189 fpRf.io.readPorts <> dispatch.io.readFpRf ++ dispatch.io.memFpRf 190 191 io.mem.redirect <> redirect 192 193 val wbu = Module(new Wbu(exuConfigs)) 194 wbu.io.in <> exeWbReqs 195 196 val wbIntResults = wbu.io.toIntRf 197 val wbFpResults = wbu.io.toFpRf 198 199 def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = { 200 val rfWrite = Wire(new RfWritePort) 201 rfWrite.wen := x.valid 202 rfWrite.addr := x.bits.uop.pdest 203 rfWrite.data := x.bits.data 204 rfWrite 205 } 206 intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite) 207 fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite) 208 209 rename.io.wbIntResults <> wbIntResults 210 rename.io.wbFpResults <> wbFpResults 211 212 roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2) 213 roq.io.exeWbResults.last := brq.io.out 214 215 216 // TODO: Remove sink and source 217 val tmp = WireInit(0.U) 218 val sinks = Array[String]( 219 "DTLBFINISH", 220 "DTLBPF", 221 "DTLBENABLE", 222 "perfCntCondMdcacheLoss", 223 "perfCntCondMl2cacheLoss", 224 "perfCntCondMdcacheHit", 225 "lsuMMIO", 226 "perfCntCondMl2cacheHit", 227 "perfCntCondMl2cacheReq", 228 "mtip", 229 "perfCntCondMdcacheReq", 230 "meip" 231 ) 232 for (s <- sinks) { 233 BoringUtils.addSink(tmp, s) 234 } 235 236 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 237 BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG") 238 BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG") 239 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 240 if (!env.FPGAPlatform) { 241 BoringUtils.addSource(debugArchReg, "difftestRegs") 242 } 243 244} 245