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.{ExuConfig, WbArbiter, 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 val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback 182 require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}") 183 outer.wbArbiter.module.io.in <> allWriteback 184 val rfWriteback = outer.wbArbiter.module.io.out 185 186 io.beu_errors.icache <> frontend.io.error 187 io.beu_errors.dcache <> memBlock.io.error 188 189 require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1) 190 val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head 191 val csrioIn = csrFenceMod.io.fuExtra.csrio.get 192 val fenceio = csrFenceMod.io.fuExtra.fenceio.get 193 194 frontend.io.backend <> ctrlBlock.io.frontend 195 frontend.io.sfence <> fenceio.sfence 196 frontend.io.tlbCsr <> csrioIn.tlb 197 frontend.io.csrCtrl <> csrioIn.customCtrl 198 frontend.io.fencei := fenceio.fencei 199 200 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 201 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 202 ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect) 203 ctrlBlock.io.stIn <> memBlock.io.stIn 204 ctrlBlock.io.stOut <> memBlock.io.stOut 205 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 206 exuBlocks.head.io.scheExtra.enqLsq.get <> memBlock.io.enqLsq 207 ctrlBlock.io.writeback <> rfWriteback 208 209 val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup 210 require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}") 211 val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 212 val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 213 val intFastUop1 = outer.wbArbiter.intConnections.map(c => intFastUop(c.head)) 214 val fpFastUop1 = outer.wbArbiter.fpConnections.map(c => fpFastUop(c.head)) 215 val allFastUop1 = intFastUop1 ++ fpFastUop1 216 217 ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in) 218 219 exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 220 exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get 221 222 memBlock.io.issue <> exuBlocks(0).io.issue.get 223 // By default, instructions do not have exceptions when they enter the function units. 224 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 225 exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch 226 227 val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt) 228 exuBlocks.map(_.io).foreach { exu => 229 exu.redirect <> ctrlBlock.io.redirect 230 exu.allocPregs <> ctrlBlock.io.allocPregs 231 exu.rfWriteback <> rfWriteback 232 exu.fastUopIn <> allFastUop1 233 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 234 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 235 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 236 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 237 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 238 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 239 sink.bits := src.bits 240 sink.valid := src.valid 241 }} 242 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 243 sink.valid := src.valid 244 sink.bits := src.bits 245 }} 246 } 247 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 248 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 249 250 // TODO: connect rsPerf 251 val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf)) 252 val rs_perf = Wire(new PerfEventsBundle(rsPerf.length)) 253 val rs_cnt = rs_perf.length 254 for (i <- 0 until rs_cnt){ 255 rs_perf.perf_events(i).incr_step := rsPerf(i).asUInt 256 } 257 dontTouch(rsPerf) 258 exuBlocks(0).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu0 259 exuBlocks(1).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu1 260 memBlock.perfinfo.perfEventsPTW <> ptw.perfinfo.perfEvents 261 ctrlBlock.perfinfo.perfEventsRs := rs_perf 262 263 csrioIn.hartId <> io.hartId 264 csrioIn.perf <> DontCare 265 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 266 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 267 csrioIn.perf.memInfo <> memBlock.io.memInfo 268 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 269 270 csrioIn.perf.perfEventsFrontend <> frontend.perfinfo.perfEvents 271 csrioIn.perf.perfEventsCtrl <> ctrlBlock.perfinfo.perfEvents 272 csrioIn.perf.perfEventsLsu <> memBlock.perfinfo.perfEvents 273 csrioIn.perf.perfEventsHc <> io.perfEvents 274 275 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 276 csrioIn.fpu.isIllegal := false.B 277 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 278 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 279 csrioIn.exception <> ctrlBlock.io.robio.exception 280 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 281 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 282 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 283 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 284 285 csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0) 286 csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1) 287 csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0) 288 csrioIn.externalInterrupt.seip := outer.plic_int_sink.in.last._1(0) 289 csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0) 290 291 csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO 292 293 fenceio.sfence <> memBlock.io.sfence 294 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 295 296 memBlock.io.redirect <> ctrlBlock.io.redirect 297 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 298 memBlock.io.csrCtrl <> csrioIn.customCtrl 299 memBlock.io.tlbCsr <> csrioIn.tlb 300 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 301 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 302 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 303 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 304 305 val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb) 306 val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb) 307 val dtlbRepeater1 = PTWFilter(memBlock.io.ptw, fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize) 308 val dtlbRepeater2 = PTWRepeaterNB(passReady = false, dtlbRepeater1.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb) 309 ptw.io.sfence <> fenceio.sfence 310 ptw.io.csr.tlb <> csrioIn.tlb 311 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 312 313 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 314 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 315 316 // Modules are reset one by one 317 // reset --> SYNC ----> SYNC ------> SYNC -----> SYNC -----> SYNC --- 318 // | | | | | 319 // v v v v v 320 // PTW {MemBlock, dtlb} ExuBlocks CtrlBlock {Frontend, itlb} 321 val resetChain = Seq( 322 Seq(memBlock, dtlbRepeater1, dtlbRepeater2), 323 Seq(exuBlocks.head), 324 // Note: arbiters don't actually have reset ports 325 exuBlocks.tail ++ Seq(outer.wbArbiter.module), 326 Seq(ctrlBlock), 327 Seq(ptw), 328 Seq(frontend, itlbRepeater1, itlbRepeater2) 329 ) 330 ResetGen(resetChain, reset.asBool, !debugOpts.FPGAPlatform) 331} 332