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