1package xiangshan.backend 2 3import chisel3._ 4import chisel3.util._ 5import xiangshan._ 6import xiangshan.backend.decode.{DecodeBuffer, DecodeStage} 7import xiangshan.backend.rename.Rename 8import xiangshan.backend.brq.Brq 9import xiangshan.backend.dispatch.Dispatch 10import xiangshan.backend.exu._ 11import xiangshan.backend.issue.{ReservationStationCtrl, ReservationStationData} 12import xiangshan.backend.regfile.{Regfile, RfWritePort} 13import xiangshan.backend.roq.Roq 14import xiangshan.mem._ 15import utils.ParallelOR 16import xiangshan.backend.fu.FunctionUnit.{lduCfg, mouCfg, stuCfg} 17 18/** Backend Pipeline: 19 * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe 20 */ 21class Backend extends XSModule 22 with NeedImpl { 23 val io = IO(new Bundle { 24 val frontend = Flipped(new FrontendToBackendIO) 25 val mem = Flipped(new MemToBackendIO) 26 val externalInterrupt = new ExternalInterruptIO 27 val sfence = Output(new SfenceBundle) 28 val fencei = Output(Bool()) 29 val tlbCsrIO = Output(new TlbCsrBundle) 30 }) 31 32 33 val aluExeUnits =Array.tabulate(exuParameters.AluCnt)(_ => Module(new AluExeUnit)) 34 val jmpExeUnit = Module(new JumpExeUnit) 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 exeUnits = jmpExeUnit +: (aluExeUnits ++ mduExeUnits ++ fmacExeUnits ++ fmiscExeUnits) 39 exeUnits.foreach(_.io.csrOnly := DontCare) 40 exeUnits.foreach(_.io.mcommit := DontCare) 41 42 fmacExeUnits.foreach(_.frm := jmpExeUnit.frm) 43 fmiscExeUnits.foreach(_.frm := jmpExeUnit.frm) 44 45 val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), wbIntPriority = 0, wbFpPriority = 0) 46 val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), wbIntPriority = Int.MaxValue, wbFpPriority = Int.MaxValue) 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 jmpExeUnit.config, aluExeUnits(0).config, mduExeUnits(0).config, 54 fmacExeUnits(0).config, fmiscExeUnits(0).config, 55 ldExeUnitCfg, stExeUnitCfg 56 )) 57 val roq = Module(new Roq) 58 val intRf = Module(new Regfile( 59 numReadPorts = NRIntReadPorts, 60 numWirtePorts = NRIntWritePorts, 61 hasZero = true 62 )) 63 val fpRf = Module(new Regfile( 64 numReadPorts = NRFpReadPorts, 65 numWirtePorts = NRFpWritePorts, 66 hasZero = false 67 )) 68 69 // backend redirect, flush pipeline 70 val redirect = Mux( 71 roq.io.redirect.valid, 72 roq.io.redirect, 73 Mux( 74 brq.io.redirect.valid, 75 brq.io.redirect, 76 io.mem.replayAll 77 ) 78 ) 79 80 io.frontend.redirect := redirect 81 io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay 82 83 84 85 val memConfigs = 86 Seq.fill(exuParameters.LduCnt)(ldExeUnitCfg) ++ 87 Seq.fill(exuParameters.StuCnt)(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 rs = exuConfigs.zipWithIndex.map({ case (cfg, i) => 100 101 // NOTE: exu could have certern and uncertaion latency 102 // but could not have multiple certern latency 103 var certainLatency = -1 104 if(cfg.hasCertainLatency) { certainLatency = cfg.latency.latencyVal.get } 105 106 val writeBackedData = exuConfigs.zip(exeWbReqs).filter(x => x._1.hasCertainLatency && needData(cfg, x._1)).map(_._2.bits.data) 107 val wakeupCnt = writeBackedData.length 108 109 val extraListenPorts = exuConfigs 110 .zip(exeWbReqs) 111 .filter(x => x._1.hasUncertainlatency && needData(cfg, x._1)) 112 .map(_._2) 113 val extraListenPortsCnt = extraListenPorts.length 114 115 val feedback = (cfg == ldExeUnitCfg) || (cfg == stExeUnitCfg) 116 117 println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}") 118 119 val rs_ctrl = Module(new ReservationStationCtrl(cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback)) 120 val rs_data = Module(new ReservationStationData(cfg, wakeupCnt, extraListenPortsCnt)) 121 122 rs_ctrl.io.toData <> rs_data.io.fromCtrl 123 rs_ctrl.io.redirect <> redirect 124 rs_ctrl.io.numExist <> dispatch.io.numExist(i) 125 rs_ctrl.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 126 rs_data.io.enqData <> dispatch.io.enqIQData(i) 127 128 rs_data.io.writeBackedData <> writeBackedData 129 for(((x, y), z) <- rs_ctrl.io.extraListenPorts.zip(rs_data.io.extraListenPorts).zip(extraListenPorts)){ 130 x.valid := z.fire() 131 x.bits := z.bits 132 y := z.bits.data 133 } 134 135 136 cfg match { 137 case `ldExeUnitCfg` => 138 case `stExeUnitCfg` => 139 case otherCfg => 140 exeUnits(i).io.in <> rs_ctrl.io.deq 141 exeUnits(i).io.in.bits := rs_data.io.deq 142 exeUnits(i).io.redirect <> redirect 143 rs_ctrl.io.tlbFeedback := DontCare 144 } 145 146 rs_ctrl.suggestName(s"rs_ctrl_${cfg.name}") 147 rs_data.suggestName(s"rs_data_${cfg.name}") 148 (rs_ctrl, rs_data) 149 }) 150 val rsCtrls = rs.map(_._1) 151 val rsDatas = rs.map(_._2) 152 153 for(rs_ctrl <- rsCtrls) { 154 rs_ctrl.io.broadcastedUops <> rsCtrls. 155 filter(x => x.exuCfg.hasCertainLatency && needData(rs_ctrl.exuCfg, x.exuCfg)). 156 map(_.io.selectedUop) 157 } 158 159 io.mem.commits <> roq.io.commits 160 io.mem.roqDeqPtr := roq.io.roqDeqPtr 161 162 // io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq) 163 // io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq) 164 io.mem.ldin <> rsCtrls.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq) 165 io.mem.ldin.zip(rsDatas.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq)).map{ 166 case (l,r) => l.bits := r 167 } 168 io.mem.stin <> rsCtrls.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq) 169 io.mem.stin.zip(rsDatas.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq)).map{ 170 case (l,r) => l.bits := r 171 } 172 jmpExeUnit.io.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException 173 jmpExeUnit.io.csrOnly.exception.bits := roq.io.exception 174 jmpExeUnit.fflags := roq.io.fflags 175 jmpExeUnit.dirty_fs := roq.io.dirty_fs 176 jmpExeUnit.io.csrOnly.externalInterrupt := io.externalInterrupt 177 jmpExeUnit.io.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr 178 jmpExeUnit.fenceToSbuffer <> io.mem.fenceToSbuffer 179 io.mem.sfence <> jmpExeUnit.sfence 180 io.mem.csr <> jmpExeUnit.tlbCsrIO 181 182 io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx 183 io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx 184 io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx 185 io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType) 186 187 io.mem.tlbFeedback <> rsCtrls.filter( 188 x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg 189 ).map(_.io.tlbFeedback) 190 191 io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo 192 io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo 193 io.frontend.sfence <> jmpExeUnit.sfence 194 io.frontend.tlbCsrIO <> jmpExeUnit.tlbCsrIO 195 196 io.fencei := jmpExeUnit.fencei 197 io.tlbCsrIO := jmpExeUnit.tlbCsrIO 198 199 decode.io.in <> io.frontend.cfVec 200 brq.io.roqRedirect <> roq.io.redirect 201 brq.io.memRedirect <> io.mem.replayAll 202 brq.io.bcommit := roq.io.bcommit 203 brq.io.enqReqs <> decode.io.toBrq 204 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 205 x.bits := y.io.out.bits 206 x.valid := y.io.out.fire() && y.io.out.bits.redirectValid 207 } 208 decode.io.brTags <> brq.io.brTags 209 decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this 210 decBuf.io.redirect <> redirect 211 decBuf.io.in <> decode.io.out 212 213 rename.io.redirect <> redirect 214 rename.io.roqCommits <> roq.io.commits 215 rename.io.in <> decBuf.io.out 216 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) ++ dispatch.io.memIntRf.map(_.addr) 217 rename.io.intPregRdy <> dispatch.io.intPregRdy ++ dispatch.io.intMemRegRdy 218 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) ++ dispatch.io.memFpRf.map(_.addr) 219 rename.io.fpPregRdy <> dispatch.io.fpPregRdy ++ dispatch.io.fpMemRegRdy 220 rename.io.replayPregReq <> dispatch.io.replayPregReq 221 dispatch.io.redirect <> redirect 222 dispatch.io.fromRename <> rename.io.out 223 224 roq.io.memRedirect <> io.mem.replayAll 225 roq.io.brqRedirect <> brq.io.redirect 226 roq.io.dp1Req <> dispatch.io.toRoq 227 roq.io.intrBitSet := jmpExeUnit.io.csrOnly.interrupt 228 roq.io.trapTarget := jmpExeUnit.io.csrOnly.trapTarget 229 dispatch.io.roqIdxs <> roq.io.roqIdxs 230 io.mem.dp1Req <> dispatch.io.toLsroq 231 dispatch.io.lsIdxs <> io.mem.lsIdxs 232 dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid 233 // store writeback must be after commit roqIdx 234 dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits) 235 236 237 intRf.io.readPorts <> dispatch.io.readIntRf ++ dispatch.io.memIntRf 238 fpRf.io.readPorts <> dispatch.io.readFpRf ++ dispatch.io.memFpRf 239 240 io.mem.redirect <> redirect 241 242 val wbu = Module(new Wbu(exuConfigs)) 243 wbu.io.in <> exeWbReqs 244 245 val wbIntResults = wbu.io.toIntRf 246 val wbFpResults = wbu.io.toFpRf 247 248 def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = { 249 val rfWrite = Wire(new RfWritePort) 250 rfWrite.wen := x.valid 251 rfWrite.addr := x.bits.uop.pdest 252 rfWrite.data := x.bits.data 253 rfWrite 254 } 255 intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite) 256 fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite) 257 258 rename.io.wbIntResults <> wbIntResults 259 rename.io.wbFpResults <> wbFpResults 260 261 roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2) 262 roq.io.exeWbResults.last := brq.io.out 263 264 265 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 266 ExcitingUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG", ExcitingUtils.Debug) 267 ExcitingUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG", ExcitingUtils.Debug) 268 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 269 if (!env.FPGAPlatform) { 270 ExcitingUtils.addSource(debugArchReg, "difftestRegs", ExcitingUtils.Debug) 271 } 272 273} 274