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