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, ReservationStation} 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 FmacExeUnit)) 37 val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new FmiscExeUnit)) 38 // val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrtExeUnit)) 39 val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits) 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 val memRf = Module(new Regfile( 61 numReadPorts = 2*exuParameters.StuCnt + exuParameters.LduCnt, 62 numWirtePorts = NRIntWritePorts, 63 hasZero = true, 64 isMemRf = true 65 )) 66 67 // backend redirect, flush pipeline 68 val redirect = Mux( 69 roq.io.redirect.valid, 70 roq.io.redirect, 71 Mux( 72 brq.io.redirect.valid, 73 brq.io.redirect, 74 io.mem.replayAll 75 ) 76 ) 77 78 io.frontend.redirect := redirect 79 io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay 80 81 val memConfigs = 82 Seq.fill(exuParameters.LduCnt)(Exu.ldExeUnitCfg) ++ 83 Seq.fill(exuParameters.StuCnt)(Exu.stExeUnitCfg) 84 85 val exuConfigs = exeUnits.map(_.config) ++ memConfigs 86 87 val exeWbReqs = exeUnits.map(_.io.out) ++ io.mem.ldout ++ io.mem.stout 88 89 def needWakeup(cfg: ExuConfig): Boolean = 90 (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf) 91 92 def needData(a: ExuConfig, b: ExuConfig): Boolean = 93 (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf) 94 95 val reservedStations = exeUnits. 96 zipWithIndex. 97 map({ case (exu, i) => 98 99 val cfg = exu.config 100 101 val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2) 102 val bypassCnt = exuConfigs.count(c => c.enableBypass && needData(cfg, c)) 103 104 println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:$bypassCnt") 105 106 val rs = Module(new ReservationStation( 107 cfg, wakeUpDateVec.length, bypassCnt, cfg.enableBypass, false 108 )) 109 rs.io.redirect <> redirect 110 rs.io.numExist <> dispatch.io.numExist(i) 111 rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 112 rs.io.enqData <> dispatch.io.enqIQData(i) 113 for( 114 (wakeUpPort, exuOut) <- 115 rs.io.wakeUpPorts.zip(wakeUpDateVec) 116 ){ 117 wakeUpPort.bits := exuOut.bits 118 wakeUpPort.valid := exuOut.valid 119 } 120 121 exu.io.in <> rs.io.deq 122 exu.io.redirect <> redirect 123 rs 124 }) 125 126 for( rs <- reservedStations){ 127 val bypassDataVec = exuConfigs.zip(exeWbReqs). 128 filter(x => x._1.enableBypass && needData(rs.exuCfg, x._1)).map(_._2) 129 130 rs.io.bypassUops <> reservedStations. 131 filter(x => x.enableBypass && needData(rs.exuCfg, x.exuCfg)). 132 map(_.io.selectedUop) 133 134 for(i <- bypassDataVec.indices){ 135 rs.io.bypassData(i).valid := bypassDataVec(i).valid 136 rs.io.bypassData(i).bits := bypassDataVec(i).bits 137 } 138 } 139 140 val issueQueues = exuConfigs. 141 zipWithIndex. 142 takeRight(exuParameters.LduCnt + exuParameters.StuCnt). 143 map({case (cfg, i) => 144 val wakeUpDateVec = exuConfigs.zip(exeWbReqs).filter(x => needData(cfg, x._1)).map(_._2) 145 val bypassUopVec = reservedStations. 146 filter(r => r.exuCfg.enableBypass && needData(cfg, r.exuCfg)).map(_.io.selectedUop) 147 val bypassDataVec = exuConfigs.zip(exeWbReqs). 148 filter(x => x._1.enableBypass && needData(cfg, x._1)).map(_._2) 149 150 val iq = Module(new IssueQueue( 151 cfg, wakeUpDateVec.length, bypassUopVec.length 152 )) 153 println(s"exu:${cfg.name} wakeupCnt:${wakeUpDateVec.length} bypassCnt:${bypassUopVec.length}") 154 iq.io.redirect <> redirect 155 iq.io.tlbFeedback := io.mem.tlbFeedback(i - exuParameters.ExuCnt + exuParameters.LduCnt + exuParameters.StuCnt) 156 iq.io.enq <> dispatch.io.enqIQCtrl(i) 157 dispatch.io.numExist(i) := iq.io.numExist 158 for( 159 (wakeUpPort, exuOut) <- 160 iq.io.wakeUpPorts.zip(wakeUpDateVec) 161 ){ 162 wakeUpPort.bits := exuOut.bits 163 wakeUpPort.valid := exuOut.fire() // data after arbit 164 } 165 iq.io.bypassUops <> bypassUopVec 166 for(i <- bypassDataVec.indices){ 167 iq.io.bypassData(i).valid := bypassDataVec(i).valid 168 iq.io.bypassData(i).bits := bypassDataVec(i).bits 169 } 170 iq 171 }) 172 173 io.mem.commits <> roq.io.commits 174 io.mem.roqDeqPtr := roq.io.roqDeqPtr 175 io.mem.ldin <> issueQueues.filter(_.exuCfg == Exu.ldExeUnitCfg).map(_.io.deq) 176 io.mem.stin <> issueQueues.filter(_.exuCfg == Exu.stExeUnitCfg).map(_.io.deq) 177 jmpExeUnit.io.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException 178 jmpExeUnit.io.exception.bits := roq.io.exception 179 180 io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo 181 io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo 182 183 decode.io.in <> io.frontend.cfVec 184 brq.io.roqRedirect <> roq.io.redirect 185 brq.io.memRedirect <> io.mem.replayAll 186 brq.io.bcommit := roq.io.bcommit 187 brq.io.enqReqs <> decode.io.toBrq 188 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 189 x.bits := y.io.out.bits 190 x.valid := y.io.out.fire() && y.io.out.bits.redirectValid 191 } 192 decode.io.brTags <> brq.io.brTags 193 decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this 194 decBuf.io.redirect <> redirect 195 decBuf.io.in <> decode.io.out 196 197 rename.io.redirect <> redirect 198 rename.io.roqCommits <> roq.io.commits 199 rename.io.in <> decBuf.io.out 200 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.intMemRegAddr 201 rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy 202 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.fpMemRegAddr 203 rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy 204 rename.io.replayPregReq <> dispatch.io.replayPregReq 205 dispatch.io.redirect <> redirect 206 dispatch.io.fromRename <> rename.io.out 207 208 roq.io.memRedirect <> io.mem.replayAll 209 roq.io.brqRedirect <> brq.io.redirect 210 roq.io.dp1Req <> dispatch.io.toRoq 211 dispatch.io.roqIdxs <> roq.io.roqIdxs 212 io.mem.dp1Req <> dispatch.io.toLsroq 213 dispatch.io.lsIdxs <> io.mem.lsIdxs 214 dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid 215 // store writeback must be after commit roqIdx 216 dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits) 217 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 249 250 // TODO: Remove sink and source 251 val tmp = WireInit(0.U) 252 val sinks = Array[String]( 253 "DTLBFINISH", 254 "DTLBPF", 255 "DTLBENABLE", 256 "perfCntCondMdcacheLoss", 257 "perfCntCondMl2cacheLoss", 258 "perfCntCondMdcacheHit", 259 "lsuMMIO", 260 "perfCntCondMl2cacheHit", 261 "perfCntCondMl2cacheReq", 262 "mtip", 263 "perfCntCondMdcacheReq", 264 "meip" 265 ) 266 for (s <- sinks) { 267 BoringUtils.addSink(tmp, s) 268 } 269 270 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 271 BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG") 272 BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG") 273 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 274 if (!env.FPGAPlatform) { 275 BoringUtils.addSource(debugArchReg, "difftestRegs") 276 } 277 278} 279