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