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