1package xiangshan.backend 2 3import bus.simplebus.SimpleBusUC 4import chisel3._ 5import chisel3.util._ 6import chisel3.util.experimental.BoringUtils 7import noop.MemMMUIO 8import xiangshan._ 9import xiangshan.backend.decode.{DecodeBuffer, DecodeStage} 10import xiangshan.backend.rename.Rename 11import xiangshan.backend.brq.Brq 12import xiangshan.backend.dispatch.Dispatch 13import xiangshan.backend.exu._ 14import xiangshan.backend.fu.FunctionUnit 15import xiangshan.backend.issue.IssueQueue 16import xiangshan.backend.regfile.{Regfile, RfWritePort} 17import xiangshan.backend.roq.Roq 18 19 20/** Backend Pipeline: 21 * Decode -> Rename -> Dispatch-1 -> Dispatch-2 -> Issue -> Exe 22 */ 23class Backend(implicit val p: XSConfig) extends XSModule 24 with NeedImpl { 25 val io = IO(new Bundle { 26 val dmem = new SimpleBusUC(addrBits = VAddrBits) 27 val memMMU = Flipped(new MemMMUIO) 28 val frontend = Flipped(new FrontendToBackendIO) 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 Fmac)) 37 // val fmiscExeUnits = Array.tabulate(exuParameters.FmiscCnt)(_ => Module(new Fmisc)) 38 // val fmiscDivSqrtExeUnits = Array.tabulate(exuParameters.FmiscDivSqrtCnt)(_ => Module(new FmiscDivSqrt)) 39 val lsuExeUnits = Array.tabulate(exuParameters.StuCnt)(_ => Module(new LsExeUnit)) 40 val exeUnits = jmpExeUnit +: (aluExeUnits ++ mulExeUnits ++ mduExeUnits ++ lsuExeUnits) 41 exeUnits.foreach(_.io.dmem := DontCare) 42 exeUnits.foreach(_.io.scommit := DontCare) 43 44 val decode = Module(new DecodeStage) 45 val brq = Module(new Brq) 46 val decBuf = Module(new DecodeBuffer) 47 val rename = Module(new Rename) 48 val dispatch = Module(new Dispatch(exeUnits.map(_.config))) 49 val roq = Module(new Roq) 50 val intRf = Module(new Regfile( 51 numReadPorts = NRReadPorts, 52 numWirtePorts = NRWritePorts, 53 hasZero = true 54 )) 55 val fpRf = Module(new Regfile( 56 numReadPorts = NRReadPorts, 57 numWirtePorts = NRWritePorts, 58 hasZero = false 59 )) 60 61 // backend redirect, flush pipeline 62 val redirect = Mux(roq.io.redirect.valid, roq.io.redirect, brq.io.redirect) 63 64 val redirectInfo = Wire(new RedirectInfo) 65 // exception or misprediction 66 redirectInfo.valid := roq.io.redirect.valid || brq.io.out.valid 67 redirectInfo.misPred := !roq.io.redirect.valid && brq.io.redirect.valid 68 redirectInfo.redirect := redirect.bits 69 70 val issueQueues = exeUnits.zipWithIndex.map({ case (eu, i) => 71 def needBypass(cfg: ExuConfig): Boolean = cfg.enableBypass 72 73 val bypassCnt = exeUnits.map(_.config).count(needBypass) 74 def needWakeup(cfg: ExuConfig): Boolean = 75 (cfg.readIntRf && cfg.writeIntRf) || (cfg.readFpRf && cfg.writeFpRf) 76 77 val wakeupCnt = exeUnits.map(_.config).count(needWakeup) 78 assert(!(needBypass(eu.config) && !needWakeup(eu.config))) // needBypass but dont needWakeup is not allowed 79 val iq = Module(new IssueQueue( 80 eu.config, 81 wakeupCnt, 82 bypassCnt, 83 eu.config.enableBypass, 84 fifo = eu.config.supportedFuncUnits.contains(FunctionUnit.lsuCfg) 85 )) 86 iq.io.redirect <> redirect 87 iq.io.numExist <> dispatch.io.numExist(i) 88 iq.io.enqCtrl <> dispatch.io.enqIQCtrl(i) 89 iq.io.enqData <> dispatch.io.enqIQData(i) 90 val wuUnitsOut = exeUnits.filter(e => needWakeup(e.config)).map(_.io.out) 91 for (i <- iq.io.wakeUpPorts.indices) { 92 iq.io.wakeUpPorts(i).bits <> wuUnitsOut(i).bits 93 iq.io.wakeUpPorts(i).valid := wuUnitsOut(i).valid 94 } 95 println( 96 s"[$i] ${eu.name} Queue wakeupCnt:$wakeupCnt bypassCnt:$bypassCnt" + 97 s" Supported Function:[" + 98 s"${ 99 eu.config.supportedFuncUnits.map( 100 fu => FuType.functionNameMap(fu.fuType.litValue())).mkString(", " 101 ) 102 }]" 103 ) 104 eu.io.in <> iq.io.deq 105 eu.io.redirect <> redirect 106 iq 107 }) 108 109 val bypassQueues = issueQueues.filter(_.enableBypass) 110 val bypassUnits = exeUnits.filter(_.config.enableBypass) 111 issueQueues.foreach(iq => { 112 for (i <- iq.io.bypassUops.indices) { 113 iq.io.bypassData(i).bits := bypassUnits(i).io.out.bits 114 iq.io.bypassData(i).valid := bypassUnits(i).io.out.valid 115 } 116 iq.io.bypassUops <> bypassQueues.map(_.io.selectedUop) 117 }) 118 119 lsuExeUnits.foreach(_.io.dmem <> io.dmem) 120 lsuExeUnits.foreach(_.io.scommit <> roq.io.scommit) 121 122 io.frontend.redirectInfo <> redirectInfo 123 io.frontend.commits <> roq.io.commits 124 125 decode.io.in <> io.frontend.cfVec 126 brq.io.roqRedirect <> roq.io.redirect 127 brq.io.enqReqs <> decode.io.toBrq 128 for ((x, y) <- brq.io.exuRedirect.zip(exeUnits.filter(_.config.hasRedirect))) { 129 x.bits := y.io.out.bits 130 x.valid := y.io.out.fire() && y.io.out.bits.redirectValid 131 } 132 decode.io.brTags <> brq.io.brTags 133 decBuf.io.redirect <> redirect 134 decBuf.io.in <> decode.io.out 135 136 rename.io.redirect <> redirect 137 rename.io.roqCommits <> roq.io.commits 138 rename.io.in <> decBuf.io.out 139 rename.io.intRfReadAddr <> dispatch.io.readIntRf.map(_.addr) 140 rename.io.fpRfReadAddr <> dispatch.io.readFpRf.map(_.addr) 141 rename.io.intPregRdy <> dispatch.io.intPregRdy 142 rename.io.fpPregRdy <> dispatch.io.fpPregRdy 143 144 dispatch.io.redirect <> redirect 145 dispatch.io.fromRename <> rename.io.out 146 147 roq.io.brqRedirect <> brq.io.redirect 148 roq.io.dp1Req <> dispatch.io.toRoq 149 dispatch.io.roqIdxs <> roq.io.roqIdxs 150 dispatch.io.roqIsEmpty := roq.io.roqIsEmpty 151 dispatch.io.isNoSpecExecCommit := roq.io.commits.head.valid 152 153 intRf.io.readPorts <> dispatch.io.readIntRf 154 fpRf.io.readPorts <> dispatch.io.readFpRf 155 156 val exeWbReqs = exeUnits.map(_.io.out) 157 158 val wbIntIdx = exeUnits.zipWithIndex.filter(_._1.config.writeIntRf).map(_._2) 159 val wbFpIdx = exeUnits.zipWithIndex.filter(_._1.config.writeFpRf).map(_._2) 160 161 val wbu = Module(new Wbu(wbIntIdx, wbFpIdx)) 162 wbu.io.in <> exeWbReqs 163 164 val wbIntResults = wbu.io.toIntRf 165 val wbFpResults = wbu.io.toFpRf 166 167 def exuOutToRfWrite(x: Valid[ExuOutput]): RfWritePort = { 168 val rfWrite = Wire(new RfWritePort) 169 rfWrite.wen := x.valid 170 rfWrite.addr := x.bits.uop.pdest 171 rfWrite.data := x.bits.data 172 rfWrite 173 } 174 175 intRf.io.writePorts <> wbIntResults.map(exuOutToRfWrite) 176 fpRf.io.writePorts <> wbFpResults.map(exuOutToRfWrite) 177 178 rename.io.wbIntResults <> wbIntResults 179 rename.io.wbFpResults <> wbFpResults 180 181 roq.io.exeWbResults.take(exeWbReqs.length).zip(wbu.io.toRoq).foreach(x => x._1 := x._2) 182 roq.io.exeWbResults.last := brq.io.out 183 184 185 // TODO: Remove sink and source 186 val tmp = WireInit(0.U) 187 val sinks = Array[String]( 188 "DTLBFINISH", 189 "DTLBPF", 190 "DTLBENABLE", 191 "perfCntCondMdcacheLoss", 192 "perfCntCondMl2cacheLoss", 193 "perfCntCondMdcacheHit", 194 "lsuMMIO", 195 "perfCntCondMl2cacheHit", 196 "perfCntCondMl2cacheReq", 197 "mtip", 198 "perfCntCondMdcacheReq", 199 "meip" 200 ) 201 for (s <- sinks) { 202 BoringUtils.addSink(tmp, s) 203 } 204 205 val debugIntReg, debugFpReg = WireInit(VecInit(Seq.fill(32)(0.U(XLEN.W)))) 206 BoringUtils.addSink(debugIntReg, "DEBUG_INT_ARCH_REG") 207 BoringUtils.addSink(debugFpReg, "DEBUG_FP_ARCH_REG") 208 val debugArchReg = WireInit(VecInit(debugIntReg ++ debugFpReg)) 209 if (!p.FPGAPlatform) { 210 BoringUtils.addSource(debugArchReg, "difftestRegs") 211 } 212 213} 214