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.ReservationStationNew 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 40 fmacExeUnits.foreach(_.frm := jmpExeUnit.frm) 41 fmiscExeUnits.foreach(_.frm := jmpExeUnit.frm) 42 43 val wbIntExus = exeUnits.filter(e => e.config.writeIntRf) 44 val wbFpExus = exeUnits.filter(e => e.config.writeFpRf) 45 // wb int exu + wb fp exu + ldu / stu + brq 46 val wbSize = wbIntExus.length + wbFpExus.length + exuParameters.LduCnt + exuParameters.StuCnt + 1 47 48 val ldExeUnitCfg = ExuConfig("LoadExu", Seq(lduCfg), wbIntPriority = 0, wbFpPriority = 0) 49 val stExeUnitCfg = ExuConfig("StoreExu", Seq(stuCfg, mouCfg), wbIntPriority = Int.MaxValue, wbFpPriority = Int.MaxValue) 50 51 val ldIntOut = io.mem.ldout.map(x => { 52 val raw = WireInit(x) 53 raw.valid := x.valid && x.bits.uop.ctrl.rfWen 54 raw 55 }) 56 57 val ldFpOut = io.mem.ldout.map(x => { 58 val raw = WireInit(x) 59 raw.valid := x.valid && x.bits.uop.ctrl.fpWen 60 raw 61 }) 62 63 64 val decode = Module(new DecodeStage) 65 val brq = Module(new Brq) 66 val decBuf = Module(new DecodeBuffer) 67 val rename = Module(new Rename) 68 val dispatch = Module(new Dispatch( 69 jmpExeUnit.config, aluExeUnits(0).config, mduExeUnits(0).config, 70 fmacExeUnits(0).config, fmiscExeUnits(0).config, 71 ldExeUnitCfg, stExeUnitCfg 72 )) 73 val roq = Module(new Roq(wbSize)) 74 val intRf = Module(new Regfile( 75 numReadPorts = NRIntReadPorts, 76 numWirtePorts = NRIntWritePorts, 77 hasZero = true, 78 len = XLEN 79 )) 80 val fpRf = Module(new Regfile( 81 numReadPorts = NRFpReadPorts, 82 numWirtePorts = NRFpWritePorts, 83 hasZero = false, 84 len = XLEN + 1 85 )) 86 87 // backend redirect, flush pipeline 88 val redirect = Mux( 89 roq.io.redirect.valid, 90 roq.io.redirect, 91 Mux( 92 brq.io.redirect.valid, 93 brq.io.redirect, 94 io.mem.replayAll 95 ) 96 ) 97 98 io.frontend.redirect := redirect 99 io.frontend.redirect.valid := redirect.valid && !redirect.bits.isReplay 100 101 102 val ldConfigs = Seq.fill(exuParameters.LduCnt)(ldExeUnitCfg) 103 val stConfigs = Seq.fill(exuParameters.StuCnt)(stExeUnitCfg) 104 val memConfigs = ldConfigs ++ stConfigs 105 106 val exuConfigs = exeUnits.map(_.config) ++ memConfigs 107 108 109 def needWakeup(cfg: ExuConfig): Boolean = 110 (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf) 111 112 def needData(a: ExuConfig, b: ExuConfig): Boolean = 113 (a.readIntRf && b.writeIntRf) || (a.readFpRf && b.writeFpRf) 114 115 val reservedStations = exuConfigs.zipWithIndex.map({ case (cfg, i) => 116 117 // NOTE: exu could have certern and uncertaion latency 118 // but could not have multiple certern latency 119 var certainLatency = -1 120 if (cfg.hasCertainLatency) { 121 certainLatency = cfg.latency.latencyVal.get 122 } 123 124 val readIntRf = cfg.readIntRf 125 val readFpRf = cfg.readFpRf 126 127 val writeBackIntData = wbIntExus.filter(e => e.config.hasCertainLatency && readIntRf).map(_.io.toInt.bits.data) 128 val writeBackFpData = wbFpExus.filter(e => e.config.hasCertainLatency && readFpRf).map(_.io.toFp.bits.data) 129 val writeBackedData = writeBackIntData ++ writeBackFpData 130 val wakeupCnt = writeBackedData.length 131 132 val extraListenInt = wbIntExus.filter(e => e.config.hasUncertainlatency && readIntRf).map(_.io.toInt) 133 val extraListenFp = wbFpExus.filter(e => e.config.hasUncertainlatency && readFpRf).map(_.io.toFp) 134 135 val extraListenPorts = extraListenInt ++ extraListenFp ++ io.mem.ldout 136 val extraListenPortsCnt = extraListenPorts.length 137 138 val feedback = (cfg == ldExeUnitCfg) || (cfg == stExeUnitCfg) 139 140 println(s"${i}: exu:${cfg.name} wakeupCnt: ${wakeupCnt} extraListenPorts: ${extraListenPortsCnt} delay:${certainLatency} feedback:${feedback}") 141 142 val rs = Module(new ReservationStationNew( 143 cfg, wakeupCnt, extraListenPortsCnt, fixedDelay = certainLatency, feedback = feedback 144 )) 145 146 rs.io.redirect <> redirect 147 rs.io.numExist <> dispatch.io.numExist(i) 148 rs.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 149 rs.io.enqData <> dispatch.io.enqIQData(i) 150 151 rs.io.writeBackedData <> writeBackedData 152 for ((x, y) <- rs.io.extraListenPorts.zip(extraListenPorts)) { 153 x.valid := y.fire() 154 x.bits := y.bits 155 } 156 157 cfg match { 158 case `ldExeUnitCfg` => 159 case `stExeUnitCfg` => 160 case otherCfg => 161 if (cfg.readIntRf) { 162 exeUnits(i).io.fromInt <> rs.io.deq 163 } else { 164 exeUnits(i).io.fromFp <> rs.io.deq 165 } 166 exeUnits(i).io.redirect <> redirect 167 rs.io.tlbFeedback := DontCare 168 } 169 170 rs.suggestName(s"rs_${cfg.name}") 171 172 rs 173 }) 174 175 for (rs <- reservedStations) { 176 val wbIntUops = reservedStations.filter(x => 177 x.exuCfg.hasCertainLatency && x.exuCfg.writeIntRf && rs.exuCfg.readIntRf 178 ).map(x => { 179 val raw = WireInit(x.io.selectedUop) 180 raw.valid := x.io.selectedUop.valid && raw.bits.ctrl.rfWen 181 raw 182 }) 183 val wbFpUops = reservedStations.filter(x => 184 x.exuCfg.hasCertainLatency && x.exuCfg.writeFpRf && rs.exuCfg.readFpRf 185 ).map(x => { 186 val raw = WireInit(x.io.selectedUop) 187 raw.valid := x.io.selectedUop.valid && raw.bits.ctrl.fpWen 188 raw 189 }) 190 191 rs.io.broadcastedUops <> wbIntUops ++ wbFpUops 192 } 193 194 io.mem.commits <> roq.io.commits 195 io.mem.roqDeqPtr := roq.io.roqDeqPtr 196 197 io.mem.ldin <> reservedStations.filter(_.exuCfg == ldExeUnitCfg).map(_.io.deq) 198 io.mem.stin <> reservedStations.filter(_.exuCfg == stExeUnitCfg).map(_.io.deq) 199 jmpExeUnit.csrOnly.exception.valid := roq.io.redirect.valid && roq.io.redirect.bits.isException 200 jmpExeUnit.csrOnly.exception.bits := roq.io.exception 201 jmpExeUnit.fflags := roq.io.csr.fflags 202 jmpExeUnit.dirty_fs := roq.io.csr.dirty_fs 203 jmpExeUnit.csrOnly.externalInterrupt := io.externalInterrupt 204 jmpExeUnit.csrOnly.memExceptionVAddr := io.mem.exceptionAddr.vaddr 205 jmpExeUnit.csrOnly.isInterrupt := DontCare // TODO: fix this 206 jmpExeUnit.fenceToSbuffer <> io.mem.fenceToSbuffer 207 io.mem.sfence <> jmpExeUnit.sfence 208 io.mem.csr <> jmpExeUnit.tlbCsrIO 209 210 io.mem.exceptionAddr.lsIdx.lsroqIdx := roq.io.exception.lsroqIdx 211 io.mem.exceptionAddr.lsIdx.lqIdx := roq.io.exception.lqIdx 212 io.mem.exceptionAddr.lsIdx.sqIdx := roq.io.exception.sqIdx 213 io.mem.exceptionAddr.isStore := CommitType.lsInstIsStore(roq.io.exception.ctrl.commitType) 214 215 io.mem.tlbFeedback <> reservedStations.filter( 216 x => x.exuCfg == ldExeUnitCfg || x.exuCfg == stExeUnitCfg 217 ).map(_.io.tlbFeedback) 218 219 io.frontend.outOfOrderBrInfo <> brq.io.outOfOrderBrInfo 220 io.frontend.inOrderBrInfo <> brq.io.inOrderBrInfo 221 io.frontend.sfence <> jmpExeUnit.sfence 222 io.frontend.tlbCsrIO <> jmpExeUnit.tlbCsrIO 223 224 io.fencei := jmpExeUnit.fencei 225 io.tlbCsrIO := jmpExeUnit.tlbCsrIO 226 227 decode.io.in <> io.frontend.cfVec 228 brq.io.roqRedirect <> roq.io.redirect 229 brq.io.memRedirect <> io.mem.replayAll 230 brq.io.bcommit := roq.io.bcommit 231 brq.io.enqReqs <> decode.io.toBrq 232 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 233 x.bits := y.io.toInt.bits 234 x.valid := y.io.toInt.fire() && y.io.toInt.bits.redirectValid 235 } 236 decode.io.brTags <> brq.io.brTags 237 decBuf.io.isWalking := ParallelOR(roq.io.commits.map(c => c.valid && c.bits.isWalk)) // TODO: opt this 238 decBuf.io.redirect <> redirect 239 decBuf.io.in <> decode.io.out 240 241 rename.io.redirect <> redirect 242 rename.io.roqCommits <> roq.io.commits 243 rename.io.in <> decBuf.io.out 244 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) 245 rename.io.intPregRdy <> dispatch.io.intPregRdy 246 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) 247 rename.io.fpPregRdy <> dispatch.io.fpPregRdy 248 rename.io.replayPregReq <> dispatch.io.replayPregReq 249 dispatch.io.redirect <> redirect 250 dispatch.io.fromRename <> rename.io.out 251 252 roq.io.memRedirect <> io.mem.replayAll 253 roq.io.brqRedirect <> brq.io.redirect 254 roq.io.dp1Req <> dispatch.io.toRoq 255 roq.io.csr.intrBitSet := jmpExeUnit.csrOnly.interrupt 256 roq.io.csr.trapTarget := jmpExeUnit.csrOnly.trapTarget 257 dispatch.io.roqIdxs <> roq.io.roqIdxs 258 io.mem.dp1Req <> dispatch.io.toLsroq 259 dispatch.io.lsIdxs <> io.mem.lsIdxs 260 dispatch.io.dequeueRoqIndex.valid := roq.io.commitRoqIndex.valid || io.mem.oldestStore.valid 261 // store writeback must be after commit roqIdx 262 dispatch.io.dequeueRoqIndex.bits := Mux(io.mem.oldestStore.valid, io.mem.oldestStore.bits, roq.io.commitRoqIndex.bits) 263 264 265 intRf.io.readPorts <> dispatch.io.readIntRf 266 fpRf.io.readPorts <> dispatch.io.readFpRf 267 268 io.mem.redirect <> redirect 269 270 271 val wbIntArbiter = Module(new Wb( 272 wbIntExus.map(_.config.wbIntPriority) ++ ldConfigs.map(_.wbIntPriority), 273 NRIntWritePorts, 274 wen = (e: ExuOutput)=>e.uop.ctrl.rfWen 275 )) 276 277 val wbFpArbiter = Module(new Wb( 278 wbFpExus.map(_.config.wbFpPriority) ++ ldConfigs.map(_.wbFpPriority), 279 NRFpWritePorts, 280 wen = (e: ExuOutput) => e.uop.ctrl.fpWen 281 )) 282 283 wbIntArbiter.io.in <> wbIntExus.map(_.io.toInt) ++ ldIntOut 284 wbFpArbiter.io.in <> wbFpExus.map(_.io.toFp) ++ ldFpOut 285 286 def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = { 287 val rfWrite = Wire(new RfWritePort) 288 rfWrite.wen := x.valid 289 rfWrite.addr := x.bits.uop.pdest 290 rfWrite.data := x.bits.data 291 rfWrite 292 } 293 294 intRf.io.writePorts <> wbIntArbiter.io.out.map(exuOutToRfWrite) 295 fpRf.io.writePorts <> wbFpArbiter.io.out.map(exuOutToRfWrite) 296 297 rename.io.wbIntResults <> wbIntArbiter.io.out 298 rename.io.wbFpResults <> wbFpArbiter.io.out 299 300 io.mem.stout.foreach(_.ready := true.B) 301 io.mem.ldout.foreach(_.ready := true.B) 302 roq.io.exeWbResults.take(wbSize - 1).zip( 303 wbIntExus.map(e => { 304 val toInt = WireInit(e.io.toInt) 305 if(e.config.hasRedirect){ 306 toInt.valid := e.io.toInt.valid && !toInt.bits.redirectValid 307 } 308 toInt 309 }) ++ wbFpExus.map(_.io.toFp) ++ io.mem.ldout ++ io.mem.stout 310 ).foreach { 311 case (x, y) => 312 x.bits := y.bits 313 x.valid := y.fire() 314 } 315 roq.io.exeWbResults.last := brq.io.out 316 317 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 318 ExcitingUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG", ExcitingUtils.Debug) 319 ExcitingUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG", ExcitingUtils.Debug) 320 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 321 if (!env.FPGAPlatform) { 322 ExcitingUtils.addSource(debugArchReg, "difftestRegs", ExcitingUtils.Debug) 323 } 324 325} 326