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 55case class EnviromentParameters 56( 57 FPGAPlatform: Boolean = true, 58 EnableDebug: Boolean = false, 59 EnablePerfDebug: Boolean = true, 60 DualCore: Boolean = false 61) 62 63abstract class XSCoreBase()(implicit p: config.Parameters) extends LazyModule 64 with HasXSParameter with HasExuWbMappingHelper 65{ 66 // interrupt sinks 67 val clint_int_sink = IntSinkNode(IntSinkPortSimple(1, 2)) 68 val debug_int_sink = IntSinkNode(IntSinkPortSimple(1, 1)) 69 val plic_int_sink = IntSinkNode(IntSinkPortSimple(1, 1)) 70 // outer facing nodes 71 val frontend = LazyModule(new Frontend()) 72 val ptw = LazyModule(new PTWWrapper()) 73 74 val wbArbiter = LazyModule(new WbArbiterWrapper(exuConfigs, NRIntWritePorts, NRFpWritePorts)) 75 val intWbPorts = wbArbiter.intWbPorts 76 val fpWbPorts = wbArbiter.fpWbPorts 77 78 // TODO: better RS organization 79 // generate rs according to number of function units 80 require(exuParameters.JmpCnt == 1) 81 require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0) 82 require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0) 83 require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2) 84 85 // one RS every 2 MDUs 86 val schedulePorts = Seq( 87 // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget 88 Seq( 89 (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()), 90 (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()), 91 (JumpCSRExeUnitCfg, 1, Seq(), Seq()), 92 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 93 (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()), 94 (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 95 ), 96 Seq( 97 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 98 (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq()) 99 ) 100 ) 101 102 // should do outer fast wakeup ports here 103 val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) => 104 val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _) 105 val outerPorts = sche.map(cfg => { 106 // exe units from this scheduler need fastUops from exeunits 107 val outerWakeupInSche = sche.filter(_._1.wakeupFromExu) 108 val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1) 109 val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1) 110 // exe units from other schedulers need fastUop from outside 111 val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1) 112 val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1) 113 val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource) 114 val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource) 115 getFastWakeupIndex(cfg._1, intSource, fpSource, intWbPorts.length).sorted 116 }) 117 println(s"inter-scheduler wakeup sources for $i: $outerPorts") 118 outerPorts 119 } 120 121 // allow mdu and fmisc to have 2*numDeq enqueue ports 122 val intDpPorts = (0 until exuParameters.AluCnt).map(i => { 123 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i)) 124 else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i)) 125 else Seq((0, i)) 126 }) 127 val lsDpPorts = Seq( 128 Seq((3, 0)), 129 Seq((3, 1)), 130 Seq((4, 0)), 131 Seq((4, 1)) 132 ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i))) 133 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 134 if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i)) 135 else Seq((0, i)) 136 }) 137 138 val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts) 139 140 val outIntRfReadPorts = Seq(0, 0) 141 val outFpRfReadPorts = Seq(0, 2) 142 val hasIntRf = Seq(true, false) 143 val hasFpRf = Seq(false, true) 144 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map { 145 case (((sche, disp), other), i) => 146 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i))) 147 } 148 149 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 150 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 151 IssQueSize = exuBlocks.head.scheduler.memRsEntries.max 152 ) 153 }))) 154} 155 156class XSCore()(implicit p: config.Parameters) extends XSCoreBase 157 with HasXSDts 158{ 159 lazy val module = new XSCoreImp(this) 160} 161 162class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) 163 with HasXSParameter 164 with HasSoCParameter 165 with HasExeBlockHelper { 166 val io = IO(new Bundle { 167 val hartId = Input(UInt(64.W)) 168 val l2_pf_enable = Output(Bool()) 169 val perfEvents = Vec(numPCntHc * coreParams.L2NBanks,(Input(UInt(6.W)))) 170 val beu_errors = Output(new XSL1BusErrors()) 171 }) 172 173 println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}") 174 AddressSpace.checkMemmap() 175 AddressSpace.printMemmap() 176 177 val ctrlBlock = Module(new CtrlBlock) 178 179 val frontend = outer.frontend.module 180 val memBlock = outer.memBlock.module 181 val ptw = outer.ptw.module 182 val exuBlocks = outer.exuBlocks.map(_.module) 183 184 val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback 185 require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}") 186 outer.wbArbiter.module.io.in <> allWriteback 187 val rfWriteback = outer.wbArbiter.module.io.out 188 189 io.beu_errors.icache <> frontend.io.error 190 io.beu_errors.dcache <> memBlock.io.error 191 192 require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1) 193 val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head 194 val csrioIn = csrFenceMod.io.fuExtra.csrio.get 195 val fenceio = csrFenceMod.io.fuExtra.fenceio.get 196 197 frontend.io.backend <> ctrlBlock.io.frontend 198 frontend.io.sfence <> fenceio.sfence 199 frontend.io.tlbCsr <> csrioIn.tlb 200 frontend.io.csrCtrl <> csrioIn.customCtrl 201 frontend.io.fencei := fenceio.fencei 202 203 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 204 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 205 ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect) 206 ctrlBlock.io.stIn <> memBlock.io.stIn 207 ctrlBlock.io.stOut <> memBlock.io.stOut 208 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 209 exuBlocks.head.io.scheExtra.enqLsq.get <> memBlock.io.enqLsq 210 ctrlBlock.io.writeback <> rfWriteback 211 212 val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup 213 require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}") 214 val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 215 val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 216 val intFastUop1 = outer.wbArbiter.intConnections.map(c => intFastUop(c.head)) 217 val fpFastUop1 = outer.wbArbiter.fpConnections.map(c => fpFastUop(c.head)) 218 val allFastUop1 = intFastUop1 ++ fpFastUop1 219 220 ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in) 221 222 exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 223 exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get 224 225 memBlock.io.issue <> exuBlocks(0).io.issue.get 226 // By default, instructions do not have exceptions when they enter the function units. 227 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 228 exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch 229 230 val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt) 231 exuBlocks.map(_.io).foreach { exu => 232 exu.redirect <> ctrlBlock.io.redirect 233 exu.allocPregs <> ctrlBlock.io.allocPregs 234 exu.rfWriteback <> rfWriteback 235 exu.fastUopIn <> allFastUop1 236 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 237 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 238 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 239 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 240 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 241 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 242 sink.bits := src.bits 243 sink.valid := src.valid 244 }} 245 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 246 sink.valid := src.valid 247 sink.bits := src.bits 248 }} 249 } 250 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 251 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 252 253 // TODO: connect rsPerf 254 val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf)) 255 val rs_perf = Wire(new PerfEventsBundle(rsPerf.length)) 256 val rs_cnt = rs_perf.length 257 for (i <- 0 until rs_cnt){ 258 rs_perf.perf_events(i).incr_step := rsPerf(i).asUInt 259 } 260 dontTouch(rsPerf) 261 exuBlocks(0).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu0 262 exuBlocks(1).perfinfo.perfEvents <> ctrlBlock.perfinfo.perfEventsEu1 263 memBlock.perfinfo.perfEventsPTW <> ptw.perfinfo.perfEvents 264 ctrlBlock.perfinfo.perfEventsRs := rs_perf 265 266 csrioIn.hartId <> io.hartId 267 csrioIn.perf <> DontCare 268 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 269 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 270 csrioIn.perf.memInfo <> memBlock.io.memInfo 271 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 272 273 csrioIn.perf.perfEventsFrontend <> frontend.perfinfo.perfEvents 274 csrioIn.perf.perfEventsCtrl <> ctrlBlock.perfinfo.perfEvents 275 csrioIn.perf.perfEventsLsu <> memBlock.perfinfo.perfEvents 276 csrioIn.perf.perfEventsHc <> io.perfEvents 277 278 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 279 csrioIn.fpu.isIllegal := false.B 280 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 281 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 282 csrioIn.exception <> ctrlBlock.io.robio.exception 283 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 284 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 285 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 286 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 287 288 csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0) 289 csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1) 290 csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0) 291 csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0) 292 293 csrioIn.distributedUpdate <> memBlock.io.csrUpdate // TODO 294 295 fenceio.sfence <> memBlock.io.sfence 296 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 297 298 memBlock.io.redirect <> ctrlBlock.io.redirect 299 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 300 memBlock.io.csrCtrl <> csrioIn.customCtrl 301 memBlock.io.tlbCsr <> csrioIn.tlb 302 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 303 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 304 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 305 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 306 307 val itlbRepeater1 = PTWRepeater(frontend.io.ptw, fenceio.sfence, csrioIn.tlb) 308 val itlbRepeater2 = PTWRepeater(itlbRepeater1.io.ptw, ptw.io.tlb(0), fenceio.sfence, csrioIn.tlb) 309 val dtlbRepeater = PTWFilter(memBlock.io.ptw, ptw.io.tlb(1), fenceio.sfence, csrioIn.tlb, l2tlbParams.filterSize) 310 ptw.io.sfence <> fenceio.sfence 311 ptw.io.csr.tlb <> csrioIn.tlb 312 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 313 314 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 315 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 316 317 // Modules are reset one by one 318 // reset --> SYNC ----> SYNC ------> SYNC -----> SYNC -----> SYNC --- 319 // | | | | | 320 // v v v v v 321 // PTW {MemBlock, dtlb} ExuBlocks CtrlBlock {Frontend, itlb} 322 val resetChain = Seq( 323 Seq(ptw), 324 Seq(memBlock, dtlbRepeater), 325 // Note: arbiters don't actually have reset ports 326 exuBlocks ++ Seq(outer.wbArbiter.module), 327 Seq(ctrlBlock), 328 Seq(frontend, itlbRepeater1, itlbRepeater2) 329 ) 330 ResetGen(resetChain, reset.asBool, !debugOpts.FPGAPlatform) 331} 332