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