1package xiangshan.backend 2 3import chisel3._ 4import chisel3.util._ 5import chisel3.util.experimental.BoringUtils 6import xiangshan._ 7import xiangshan.backend.decode.{DecodeBuffer, DecodeStage} 8import xiangshan.backend.rename.Rename 9import xiangshan.backend.brq.Brq 10import xiangshan.backend.dispatch.Dispatch 11import xiangshan.backend.exu._ 12import xiangshan.backend.fu.FunctionUnit 13import xiangshan.backend.issue.{IssueQueue, ReservationStation} 14import xiangshan.backend.regfile.{Regfile, RfWritePort} 15import xiangshan.backend.roq.Roq 16import xiangshan.mem._ 17import utils._ 18 19/** Backend Pipeline: 20 * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe 21 */ 22class Backend extends XSModule 23 with NeedImpl { 24 val io = IO(new Bundle { 25 val frontend = Flipped(new FrontendToBackendIO) 26 val mem = Flipped(new MemToBackendIO) 27 }) 28 val timer = GTimer() 29 30 val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit)) 31 val jmpExeUnit = Module(new JmpExeUnit) 32 val mulExeUnits = Array.tabulate(exuParameters.MulCnt)(_ => Module(new MulExeUnit)) 33 val mduExeUnits = Array.tabulate(exuParameters.MduCnt)(_ => Module(new MulDivExeUnit)) 34 // val fmacExeUnits = Array.tabulate(exuParameters.FmacCnt)(_ => Module(new Fmac)) 35 // val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc)) 36 // val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt)) 37 val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits) 38 exeUnits.foreach(exe => { 39 exe.io.exception := DontCare 40 exe.io.dmem := DontCare 41 exe.io.mcommit := DontCare 42 exe.io.in.bits.uop.debugInfo.issueTime := timer 43 }) 44 45 val decode = Module(new DecodeStage) 46 val brq = Module(new Brq) 47 val decBuf = Module(new DecodeBuffer) 48 val rename = Module(new Rename) 49 val dispatch = Module(new Dispatch) 50 val roq = Module(new Roq) 51 val intRf = Module(new Regfile( 52 numReadPorts = NRIntReadPorts, 53 numWirtePorts = NRIntWritePorts, 54 hasZero = true 55 )) 56 val fpRf = Module(new Regfile( 57 numReadPorts = NRFpReadPorts, 58 numWirtePorts = NRFpWritePorts, 59 hasZero = false 60 )) 61 val memRf = Module(new Regfile( 62 numReadPorts = 2*exuParameters.StuCnt + exuParameters.LduCnt, 63 numWirtePorts = NRIntWritePorts, 64 hasZero = true, 65 isMemRf = true 66 )) 67 68 // backend redirect, flush pipeline 69 val redirect = Mux( 70 roq.io.redirect.valid, 71 roq.io.redirect, 72 Mux( 73 brq.io.redirect.valid, 74 brq.io.redirect, 75 io.mem.replayAll 76 ) 77 ) 78 79 io.frontend.redirect := redirect 80 io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay 81 82 val memConfigs = 83 Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++ 84 Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg) 85 86 val exuConfigs = exeUnits.map(_.config) ++ memConfigs 87 88 val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout 89 90 def needWakeup(cfg: ExuConfig): Boolean = 91 (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf) 92 93 def needData(a: ExuConfig, b: ExuConfig): Boolean = 94 (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf) 95 96 val reservedStations = exeUnits. 97 zipWithIndex. 98 map({ case (exu, i) => 99 100 val cfg = exu.config 101 102 val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2) 103 val bypassCnt = exuConfigs.count(c => c.enableBypass && needData(cfg, c)) 104 105 println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:$bypassCnt") 106 107 val rs = Module(new ReservationStation( 108 cfg, wakeUpDateVec.length, bypassCnt, cfg.enableBypass, false 109 )) 110 rs.io.redirect <> redirect 111 rs.io.numExist <> dispatch.io.numExist(i) 112 rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 113 rs.io.enqData <> dispatch.io.enqIQData(i) 114 for( 115 (wakeUpPort, exuOut) <- 116 rs.io.wakeUpPorts.zip(wakeUpDateVec) 117 ){ 118 wakeUpPort.bits := exuOut.bits 119 wakeUpPort.valid := exuOut.valid 120 } 121 122 exu.io.in <> rs.io.deq 123 exu.io.redirect <> redirect 124 rs 125 }) 126 127 for( rs <- reservedStations){ 128 rs.io.bypassUops <> reservedStations. 129 filter(x => x.enableBypass && needData(rs.exuCfg, x.exuCfg)). 130 map(_.io.selectedUop) 131 132 val bypassDataVec = exuConfigs.zip(exeWbReqs). 133 filter(x => x._1.enableBypass && needData(rs.exuCfg, x._1)).map(_._2) 134 135 for(i <- bypassDataVec.indices){ 136 rs.io.bypassData(i).valid := bypassDataVec(i).valid 137 rs.io.bypassData(i).bits := bypassDataVec(i).bits 138 } 139 } 140 141 val issueQueues = exuConfigs. 142 zipWithIndex. 143 takeRight(exuParameters.LduCnt + exuParameters.StuCnt). 144 map({case (cfg, i) => 145 val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2) 146 val bypassUopVec = reservedStations. 147 filter(r => r.exuCfg.enableBypass && needData(cfg, r.exuCfg)).map(_.io.selectedUop) 148 val bypassDataVec = exuConfigs.zip(exeWbReqs). 149 filter(x => x._1.enableBypass && needData(cfg, x._1)).map(_._2) 150 151 val iq = Module(new IssueQueue( 152 cfg, wakeUpDateVec.length, bypassUopVec.length 153 )) 154 println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:${bypassUopVec.length}") 155 iq.io.redirect <> redirect 156 iq.io.tlbFeedback := io.mem.tlbFeedback(i - exuParameters.ExuCnt + exuParameters.LduCnt + exuParameters.StuCnt) 157 iq.io.enq <> dispatch.io.enqIQCtrl(i) 158 dispatch.io.numExist(i) := iq.io.numExist 159 for( 160 (wakeUpPort, exuOut) <- 161 iq.io.wakeUpPorts.zip(wakeUpDateVec) 162 ){ 163 wakeUpPort.bits := exuOut.bits 164 wakeUpPort.valid := exuOut.fire() // data after arbit 165 } 166 iq.io.bypassUops <> bypassUopVec 167 for(i <- bypassDataVec.indices){ 168 iq.io.bypassData(i).valid := bypassDataVec(i).valid 169 iq.io.bypassData(i).bits := bypassDataVec(i).bits 170 } 171 iq 172 }) 173 174 io.mem.commits <> roq.io.commits 175 io.mem.roqDeqPtr := roq.io.roqDeqPtr 176 io.mem.ldin <> issueQueues.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq) 177 io.mem.stin <> issueQueues.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq) 178 jmpExeUnit.io.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException 179 jmpExeUnit.io.exception.bits := roq.io.exception 180 181 io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo 182 io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo 183 184 decode.io.in <> io.frontend.cfVec 185 brq.io.roqRedirect <> roq.io.redirect 186 brq.io.memRedirect <> io.mem.replayAll 187 brq.io.bcommit := roq.io.bcommit 188 brq.io.enqReqs <> decode.io.toBrq 189 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 190 x.bits := y.io.out.bits 191 x.valid := y.io.out.fire() && y.io.out.bits.redirectValid 192 } 193 decode.io.brTags <> brq.io.brTags 194 decBuf.io.isWalking := Cat(roq.io.commits.map(c => c.valid && c.bits.isWalk)).orR // TODO: opt this 195 decBuf.io.redirect <> redirect 196 decBuf.io.in <> decode.io.out 197 198 rename.io.redirect <> redirect 199 rename.io.roqCommits <> roq.io.commits 200 rename.io.in <> decBuf.io.out 201 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.intMemRegAddr 202 rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy 203 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.fpMemRegAddr 204 rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy 205 rename.io.replayPregReq <> dispatch.io.replayPregReq 206 dispatch.io.redirect <> redirect 207 dispatch.io.fromRename <> rename.io.out 208 dispatch.io.fromRename.foreach(_.bits.debugInfo.renameTime := timer) 209 210 roq.io.memRedirect <> io.mem.replayAll 211 roq.io.brqRedirect <> brq.io.redirect 212 roq.io.dp1Req <> dispatch.io.toRoq 213 roq.io.dp1Req.foreach(_.bits.debugInfo.dispatchTime := timer) 214 dispatch.io.roqIdxs <> roq.io.roqIdxs 215 io.mem.dp1Req <> dispatch.io.toLsroq 216 dispatch.io.commits <> roq.io.commits 217 dispatch.io.lsIdxs <> io.mem.lsIdxs 218 219 intRf.io.readPorts <> dispatch.io.readIntRf 220 fpRf.io.readPorts <> dispatch.io.readFpRf ++ issueQueues.flatMap(_.io.readFpRf) 221 memRf.io.readPorts <> issueQueues.flatMap(_.io.readIntRf) 222 223 io.mem.redirect <> redirect 224 225 val wbu = Module(new Wbu(exuConfigs)) 226 wbu.io.in <> exeWbReqs 227 228 val wbIntResults = wbu.io.toIntRf 229 val wbFpResults = wbu.io.toFpRf 230 231 def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = { 232 val rfWrite = Wire(new RfWritePort) 233 rfWrite.wen := x.valid 234 rfWrite.addr := x.bits.uop.pdest 235 rfWrite.data := x.bits.data 236 rfWrite 237 } 238 val intRfWrite = wbIntResults.map(exuOutToRfWrite) 239 intRf.io.writePorts <> intRfWrite 240 memRf.io.writePorts <> intRfWrite 241 fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite) 242 243 rename.io.wbIntResults <> wbIntResults 244 rename.io.wbFpResults <> wbFpResults 245 246 roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2) 247 roq.io.exeWbResults.last := brq.io.out 248 roq.io.exeWbResults.foreach(_.bits.uop.debugInfo.writebackTime := timer) 249 250 val commitTime = timer 251 val renameToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk, timer - c.bits.uop.debugInfo.renameTime, 0.U)).reduce(_ + _) 252 val dispatchToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk, timer - c.bits.uop.debugInfo.dispatchTime, 0.U)).reduce(_ + _) 253 val issueToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk, timer - c.bits.uop.debugInfo.issueTime, 0.U)).reduce(_ + _) 254 val writebackToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk, timer - c.bits.uop.debugInfo.writebackTime, 0.U)).reduce(_ + _) 255 val loadDispatchToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk && c.bits.uop.ctrl.commitType === CommitType.LOAD, timer - c.bits.uop.debugInfo.renameTime, 0.U)).reduce(_ + _) 256 val storeDispatchToCommit = roq.io.commits.map(c => Mux(c.valid && !c.bits.isWalk && c.bits.uop.ctrl.commitType === CommitType.STORE, timer - c.bits.uop.debugInfo.renameTime, 0.U)).reduce(_ + _) 257 258 XSPerf("renameToCommit", renameToCommit) 259 XSPerf("dispatchToCommit", dispatchToCommit) 260 XSPerf("issueToCommit", issueToCommit) 261 XSPerf("writebackToCommit", writebackToCommit) 262 XSPerf("loadDispatchToCommit", loadDispatchToCommit) 263 XSPerf("storeDispatchToCommit", storeDispatchToCommit) 264 265 // TODO: Remove sink and source 266 val tmp = WireInit(0.U) 267 val sinks = Array[String]( 268 "DTLBFINISH", 269 "DTLBPF", 270 "DTLBENABLE", 271 "perfCntCondMdcacheLoss", 272 "perfCntCondMl2cacheLoss", 273 "perfCntCondMdcacheHit", 274 "lsuMMIO", 275 "perfCntCondMl2cacheHit", 276 "perfCntCondMl2cacheReq", 277 "mtip", 278 "perfCntCondMdcacheReq", 279 "meip" 280 ) 281 for (s <- sinks) { 282 BoringUtils.addSink(tmp, s) 283 } 284 285 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 286 BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG") 287 BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG") 288 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 289 if (!env.FPGAPlatform) { 290 BoringUtils.addSource(debugArchReg, "difftestRegs") 291 } 292 293} 294