1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan 18 19import chisel3._ 20import chisel3.util._ 21import xiangshan.backend._ 22import xiangshan.backend.fu.HasExceptionNO 23import xiangshan.backend.exu.WbArbiterWrapper 24import xiangshan.frontend._ 25import xiangshan.cache.mmu._ 26import chipsalliance.rocketchip.config 27import chipsalliance.rocketchip.config.Parameters 28import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 29import freechips.rocketchip.interrupts.{IntSinkNode, IntSinkPortSimple} 30import freechips.rocketchip.tile.HasFPUParameters 31import system.HasSoCParameter 32import utils._ 33 34abstract class XSModule(implicit val p: Parameters) extends MultiIOModule 35 with HasXSParameter 36 with HasExceptionNO 37 with HasFPUParameters { 38 def io: Record 39} 40 41//remove this trait after impl module logic 42trait NeedImpl { 43 this: RawModule => 44 override protected def IO[T <: Data](iodef: T): T = { 45 println(s"[Warn]: (${this.name}) please reomve 'NeedImpl' after implement this module") 46 val io = chisel3.experimental.IO(iodef) 47 io <> DontCare 48 io 49 } 50} 51 52abstract class XSBundle(implicit val p: Parameters) extends Bundle 53 with HasXSParameter 54 55abstract class XSCoreBase()(implicit p: config.Parameters) extends LazyModule 56 with HasXSParameter with HasExuWbMappingHelper 57{ 58 // interrupt sinks 59 val clint_int_sink = IntSinkNode(IntSinkPortSimple(1, 2)) 60 val debug_int_sink = IntSinkNode(IntSinkPortSimple(1, 1)) 61 val plic_int_sink = IntSinkNode(IntSinkPortSimple(2, 1)) 62 // outer facing nodes 63 val frontend = LazyModule(new Frontend()) 64 val ptw = LazyModule(new PTWWrapper()) 65 66 val wbArbiter = LazyModule(new WbArbiterWrapper(exuConfigs, NRIntWritePorts, NRFpWritePorts)) 67 val intWbPorts = wbArbiter.intWbPorts 68 val fpWbPorts = wbArbiter.fpWbPorts 69 70 // TODO: better RS organization 71 // generate rs according to number of function units 72 require(exuParameters.JmpCnt == 1) 73 require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0) 74 require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0) 75 require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2) 76 77 // one RS every 2 MDUs 78 val schedulePorts = Seq( 79 // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget 80 Seq( 81 (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()), 82 (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()), 83 (JumpCSRExeUnitCfg, 1, Seq(), Seq()), 84 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 85 (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()), 86 (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 87 ), 88 Seq( 89 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 90 (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq()) 91 ) 92 ) 93 94 // should do outer fast wakeup ports here 95 val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) => 96 val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _) 97 val outerPorts = sche.map(cfg => { 98 // exe units from this scheduler need fastUops from exeunits 99 val outerWakeupInSche = sche.filter(_._1.wakeupFromExu) 100 val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1) 101 val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1) 102 // exe units from other schedulers need fastUop from outside 103 val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1) 104 val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1) 105 val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource) 106 val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource) 107 getFastWakeupIndex(cfg._1, intSource, fpSource, intWbPorts.length).sorted 108 }) 109 println(s"inter-scheduler wakeup sources for $i: $outerPorts") 110 outerPorts 111 } 112 113 // allow mdu and fmisc to have 2*numDeq enqueue ports 114 val intDpPorts = (0 until exuParameters.AluCnt).map(i => { 115 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i)) 116 else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i)) 117 else Seq((0, i)) 118 }) 119 val lsDpPorts = Seq( 120 Seq((3, 0)), 121 Seq((3, 1)), 122 Seq((4, 0)), 123 Seq((4, 1)) 124 ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i))) 125 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 126 if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i)) 127 else Seq((0, i)) 128 }) 129 130 val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts) 131 132 val outIntRfReadPorts = Seq(0, 0) 133 val outFpRfReadPorts = Seq(0, 2) 134 val hasIntRf = Seq(true, false) 135 val hasFpRf = Seq(false, true) 136 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map { 137 case (((sche, disp), other), i) => 138 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i))) 139 } 140 141 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 142 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 143 IssQueSize = exuBlocks.head.scheduler.memRsEntries.max 144 ) 145 }))) 146} 147 148class XSCore()(implicit p: config.Parameters) extends XSCoreBase 149 with HasXSDts 150{ 151 lazy val module = new XSCoreImp(this) 152} 153 154class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) 155 with HasXSParameter 156 with HasSoCParameter 157 with HasExeBlockHelper { 158 val io = IO(new Bundle { 159 val hartId = Input(UInt(64.W)) 160 val l2_pf_enable = Output(Bool()) 161 val perfEvents = Vec(numPCntHc * coreParams.L2NBanks,(Input(UInt(6.W)))) 162 val beu_errors = Output(new XSL1BusErrors()) 163 }) 164 165 println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}") 166 167 val ctrlBlock = Module(new CtrlBlock) 168 169 val frontend = outer.frontend.module 170 val memBlock = outer.memBlock.module 171 val ptw = outer.ptw.module 172 val exuBlocks = outer.exuBlocks.map(_.module) 173 174 175 ctrlBlock.io.hartId := io.hartId 176 exuBlocks.foreach(_.io.hartId := io.hartId) 177 memBlock.io.hartId := io.hartId 178 outer.wbArbiter.module.io.hartId := io.hartId 179 180 181 outer.wbArbiter.module.io.redirect <> ctrlBlock.io.redirect 182 val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback 183 require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}") 184 outer.wbArbiter.module.io.in <> allWriteback 185 val rfWriteback = outer.wbArbiter.module.io.out 186 187 io.beu_errors.icache <> frontend.io.error 188 io.beu_errors.dcache <> memBlock.io.error 189 190 require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1) 191 val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head 192 val csrioIn = csrFenceMod.io.fuExtra.csrio.get 193 val fenceio = csrFenceMod.io.fuExtra.fenceio.get 194 195 frontend.io.backend <> ctrlBlock.io.frontend 196 frontend.io.sfence <> fenceio.sfence 197 frontend.io.tlbCsr <> csrioIn.tlb 198 frontend.io.csrCtrl <> csrioIn.customCtrl 199 frontend.io.fencei := fenceio.fencei 200 201 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 202 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 203 ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect) 204 ctrlBlock.io.stIn <> memBlock.io.stIn 205 ctrlBlock.io.stOut <> memBlock.io.stOut 206 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 207 exuBlocks.head.io.scheExtra.enqLsq.get <> memBlock.io.enqLsq 208 val intWriteback = rfWriteback.take(outer.wbArbiter.intArbiter.numOutPorts) 209 val fpWriteback = rfWriteback.drop(outer.wbArbiter.intArbiter.numOutPorts) 210 val fpWritbackNoLoad = fpWriteback.zip(outer.wbArbiter.fpWbPorts).filterNot(_._2.contains(LdExeUnitCfg)).map(_._1) 211 require(fpWritbackNoLoad.length + intWriteback.length == ctrlBlock.io.writeback.length) 212 ctrlBlock.io.writeback <> VecInit(intWriteback ++ fpWritbackNoLoad) 213 // Load Int and Fp have the same bits and we can re-use the write-back ports 214 for (i <- 0 until exuParameters.LduCnt) { 215 ctrlBlock.io.writeback(exuParameters.AluCnt + i).valid := memBlock.io.writeback(i).valid 216 } 217 218 val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup 219 require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}") 220 val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 221 val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 222 val intFastUop1 = outer.wbArbiter.intConnections.map(c => intFastUop(c.head)) 223 val fpFastUop1 = outer.wbArbiter.fpConnections.map(c => fpFastUop(c.head)) 224 val allFastUop1 = intFastUop1 ++ fpFastUop1 225 226 ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in) 227 228 exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 229 exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get 230 231 memBlock.io.issue <> exuBlocks(0).io.issue.get 232 // By default, instructions do not have exceptions when they enter the function units. 233 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 234 exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch 235 236 val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt) 237 exuBlocks.map(_.io).foreach { exu => 238 exu.redirect <> ctrlBlock.io.redirect 239 exu.allocPregs <> ctrlBlock.io.allocPregs 240 exu.rfWriteback <> rfWriteback 241 exu.fastUopIn <> allFastUop1 242 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 243 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 244 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 245 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 246 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 247 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 248 sink.bits := src.bits 249 sink.valid := src.valid 250 }} 251 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 252 sink.valid := src.valid 253 sink.bits := src.bits 254 }} 255 } 256 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 257 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 258 259 // TODO: connect rsPerf 260 val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf)) 261 val rs_perf = Wire(new PerfEventsBundle(rsPerf.length)) 262 val rs_cnt = rs_perf.length 263 for (i <- 0 until rs_cnt){ 264 rs_perf.perf_events(i).incr_step := rsPerf(i).asUInt 265 } 266 dontTouch(rsPerf) 267 exuBlocks(0).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu0 268 exuBlocks(1).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu1 269 memBlock.perfinfo.perfEventsPTW <> ptw.perfinfo.perfEvents 270 ctrlBlock.perfinfo.perfEventsRs := rs_perf 271 272 csrioIn.hartId <> io.hartId 273 csrioIn.perf <> DontCare 274 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 275 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 276 csrioIn.perf.memInfo <> memBlock.io.memInfo 277 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 278 279 csrioIn.perf.perfEventsFrontend <> frontend.perfinfo.perfEvents 280 csrioIn.perf.perfEventsCtrl <> ctrlBlock.perfinfo.perfEvents 281 csrioIn.perf.perfEventsLsu <> memBlock.perfinfo.perfEvents 282 csrioIn.perf.perfEventsHc <> io.perfEvents 283 284 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 285 csrioIn.fpu.isIllegal := false.B 286 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 287 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 288 csrioIn.exception <> ctrlBlock.io.robio.exception 289 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 290 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 291 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 292 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 293 294 csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0) 295 csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1) 296 csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0) 297 csrioIn.externalInterrupt.seip := outer.plic_int_sink.in.last._1(0) 298 csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0) 299 300 csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO 301 302 fenceio.sfence <> memBlock.io.sfence 303 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 304 305 memBlock.io.redirect <> ctrlBlock.io.redirect 306 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 307 memBlock.io.csrCtrl <> csrioIn.customCtrl 308 memBlock.io.tlbCsr <> csrioIn.tlb 309 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 310 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 311 312 val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb) 313 val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb) 314 val dtlbRepeater1 = PTWFilter(memBlock.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize) 315 val dtlbRepeater2 = PTWRepeaterNB(passReady = false, dtlbRepeater1.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb) 316 ptw.io.sfence <> fenceio.sfence 317 ptw.io.csr.tlb <> csrioIn.tlb 318 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 319 320 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 321 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 322 323 // Modules are reset one by one 324 // reset --> SYNC ----> SYNC ------> SYNC -----> SYNC -----> SYNC --- 325 // | | | | | 326 // v v v v v 327 // PTW {MemBlock, dtlb} ExuBlocks CtrlBlock {Frontend, itlb} 328 val resetChain = Seq( 329 Seq(memBlock, dtlbRepeater1, dtlbRepeater2), 330 Seq(exuBlocks.head), 331 // Note: arbiters don't actually have reset ports 332 exuBlocks.tail ++ Seq(outer.wbArbiter.module), 333 Seq(ctrlBlock), 334 Seq(ptw), 335 Seq(frontend, itlbRepeater1, itlbRepeater2) 336 ) 337 ResetGen(resetChain, reset.asBool, !debugOpts.FPGAPlatform) 338} 339