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