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} 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.tile.HasFPUParameters 30import system.{HasSoCParameter, L1CacheErrorInfo, SoCParamsKey} 31import utils._ 32 33abstract class XSModule(implicit val p: Parameters) extends MultiIOModule 34 with HasXSParameter 35 with HasExceptionNO 36 with HasFPUParameters { 37 def io: Record 38} 39 40//remove this trait after impl module logic 41trait NeedImpl { 42 this: RawModule => 43 override protected def IO[T <: Data](iodef: T): T = { 44 println(s"[Warn]: (${this.name}) please reomve 'NeedImpl' after implement this module") 45 val io = chisel3.experimental.IO(iodef) 46 io <> DontCare 47 io 48 } 49} 50 51abstract class XSBundle(implicit val p: Parameters) extends Bundle 52 with HasXSParameter 53 54case class EnviromentParameters 55( 56 FPGAPlatform: Boolean = true, 57 EnableDebug: Boolean = false, 58 EnablePerfDebug: Boolean = true, 59 DualCore: Boolean = false 60) 61 62abstract class XSCoreBase()(implicit p: config.Parameters) extends LazyModule 63 with HasXSParameter with HasExuWbMappingHelper 64{ 65 // outer facing nodes 66 val frontend = LazyModule(new Frontend()) 67 val ptw = LazyModule(new PTWWrapper()) 68 69 val intConfigs = exuConfigs.filter(_.writeIntRf) 70 val intArbiter = LazyModule(new WbArbiter(intConfigs, NRIntWritePorts, isFp = false)) 71 val intWbPorts = intArbiter.allConnections.map(c => c.map(intConfigs(_))) 72 val numIntWbPorts = intWbPorts.length 73 74 val fpConfigs = exuConfigs.filter(_.writeFpRf) 75 val fpArbiter = LazyModule(new WbArbiter(fpConfigs, NRFpWritePorts, isFp = true)) 76 val fpWbPorts = fpArbiter.allConnections.map(c => c.map(fpConfigs(_))) 77 val numFpWbPorts = fpWbPorts.length 78 79 // TODO: better RS organization 80 // generate rs according to number of function units 81 require(exuParameters.JmpCnt == 1) 82 require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0) 83 require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0) 84 require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2) 85 86 // one RS every 2 MDUs 87 val schedulePorts = Seq( 88 // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget 89 Seq( 90 (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()), 91 (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()), 92 (JumpCSRExeUnitCfg, 1, Seq(), Seq()) 93 ), 94 Seq( 95 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 96 (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq()) 97 ), 98 Seq( 99 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 100 (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()), 101 (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 102 ) 103 ) 104 105 // should do outer fast wakeup ports here 106 val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) => 107 val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _) 108 val outerPorts = sche.map(cfg => { 109 // exe units from this scheduler need fastUops from exeunits 110 val outerWakeupInSche = sche.filter(_._1.wakeupFromExu) 111 val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1) 112 val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1) 113 // exe units from other schedulers need fastUop from outside 114 val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1) 115 val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1) 116 val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource) 117 val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource) 118 getFastWakeupIndex(cfg._1, intSource, fpSource, numIntWbPorts).sorted 119 }) 120 println(s"inter-scheduler wakeup sources for $i: $outerPorts") 121 outerPorts 122 } 123 124 // allow mdu and fmisc to have 2*numDeq enqueue ports 125 val intDpPorts = (0 until exuParameters.AluCnt).map(i => { 126 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i)) 127 else if (i < exuParameters.MduCnt) Seq((0, i), (1, i)) 128 else Seq((0, i)) 129 }) 130 val lsDpPorts = Seq( 131 Seq((0, 0)), 132 Seq((0, 1)), 133 Seq((1, 0)), 134 Seq((1, 1)) 135 ) ++ (0 until exuParameters.StuCnt).map(i => Seq((2, i))) 136 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 137 if (i < exuParameters.FmiscCnt) Seq((0, i), (1, i)) 138 else Seq((0, i)) 139 }) 140 141 val dispatchPorts = Seq(intDpPorts, fpDpPorts, lsDpPorts) 142 143 val outIntRfReadPorts = Seq(6, 0, 0) 144 val outFpRfReadPorts = Seq(0, 2, 0) 145 val hasIntRf = Seq(true, false, false) 146 val hasFpRf = Seq(false, true, false) 147 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.dropRight(1).map { 148 case (((sche, disp), other), i) => 149 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i))) 150 } 151 152 val memScheduler = LazyModule(new Scheduler(schedulePorts.last, dispatchPorts.last, intWbPorts, fpWbPorts, otherFastPorts.last, outIntRfReadPorts.last, outFpRfReadPorts.last, hasIntRf.last, hasFpRf.last)) 153 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 154 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 155 IssQueSize = memScheduler.memRsEntries.max 156 ) 157 }))) 158} 159 160class XSCore()(implicit p: config.Parameters) extends XSCoreBase 161 with HasXSDts 162{ 163 lazy val module = new XSCoreImp(this) 164} 165 166class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) 167 with HasXSParameter 168 with HasSoCParameter 169 with HasExeBlockHelper { 170 val io = IO(new Bundle { 171 val hartId = Input(UInt(64.W)) 172 val externalInterrupt = new ExternalInterruptIO 173 val l2_pf_enable = Output(Bool()) 174 val l1plus_error, icache_error, dcache_error = Output(new L1CacheErrorInfo) 175 }) 176 177 println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}") 178 AddressSpace.checkMemmap() 179 AddressSpace.printMemmap() 180 181 val ctrlBlock = Module(new CtrlBlock) 182 183 val frontend = outer.frontend.module 184 val memBlock = outer.memBlock.module 185 val ptw = outer.ptw.module 186 val exuBlocks = outer.exuBlocks.map(_.module) 187 val memScheduler = outer.memScheduler.module 188 189 val allWriteback = exuBlocks.map(_.io.fuWriteback).fold(Seq())(_ ++ _) ++ memBlock.io.writeback 190 191 val intWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 192 require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}") 193 194 // set default value for ready 195 exuBlocks.foreach(_.io.fuWriteback.foreach(_.ready := true.B)) 196 memBlock.io.writeback.foreach(_.ready := true.B) 197 198 val intArbiter = outer.intArbiter.module 199 intArbiter.io.in.zip(intWriteback).foreach { case (arb, wb) => 200 arb.valid := wb.valid && !wb.bits.uop.ctrl.fpWen 201 arb.bits := wb.bits 202 when (arb.valid) { 203 wb.ready := arb.ready 204 } 205 } 206 207 val fpArbiter = outer.fpArbiter.module 208 val fpWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 209 fpArbiter.io.in.zip(fpWriteback).foreach{ case (arb, wb) => 210 arb.valid := wb.valid && wb.bits.uop.ctrl.fpWen 211 arb.bits := wb.bits 212 when (arb.valid) { 213 wb.ready := arb.ready 214 } 215 } 216 217 val rfWriteback = VecInit(intArbiter.io.out ++ fpArbiter.io.out) 218 219 io.l1plus_error <> DontCare 220 io.icache_error <> frontend.io.error 221 io.dcache_error <> memBlock.io.error 222 223 require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1) 224 val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head 225 val csrioIn = csrFenceMod.io.fuExtra.csrio.get 226 val fenceio = csrFenceMod.io.fuExtra.fenceio.get 227 228 frontend.io.backend <> ctrlBlock.io.frontend 229 frontend.io.sfence <> fenceio.sfence 230 frontend.io.tlbCsr <> csrioIn.tlb 231 frontend.io.csrCtrl <> csrioIn.customCtrl 232 frontend.io.fencei := fenceio.fencei 233 234 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 235 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 236 ctrlBlock.io.exuRedirect <> redirectBlocks.map(_.io.fuExtra.exuRedirect).fold(Seq())(_ ++ _) 237 ctrlBlock.io.stIn <> memBlock.io.stIn 238 ctrlBlock.io.stOut <> memBlock.io.stOut 239 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 240 ctrlBlock.io.enqLsq <> memBlock.io.enqLsq 241 ctrlBlock.io.writeback <> rfWriteback 242 243 val allFastUop = exuBlocks.map(_.io.fastUopOut).fold(Seq())(_ ++ _) ++ memBlock.io.otherFastWakeup 244 val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 245 val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 246 val intFastUop1 = outer.intArbiter.allConnections.map(c => intFastUop(c.head)) 247 val fpFastUop1 = outer.fpArbiter.allConnections.map(c => fpFastUop(c.head)) 248 val allFastUop1 = intFastUop1 ++ fpFastUop1 249 250 ctrlBlock.io.enqIQ <> exuBlocks(0).io.allocate ++ exuBlocks(1).io.allocate ++ memScheduler.io.allocate.take(4) 251 252 val stdAllocate = memScheduler.io.allocate.takeRight(2) 253 val staAllocate = memScheduler.io.allocate.slice(2, 4) 254 stdAllocate.zip(staAllocate).zip(ctrlBlock.io.enqIQ.takeRight(2)).zipWithIndex.foreach{ case (((std, sta), enq), i) => 255 std.valid := enq.valid && sta.ready 256 sta.valid := enq.valid && std.ready 257 std.bits := enq.bits 258 sta.bits := enq.bits 259 std.bits.ctrl.lsrc(0) := enq.bits.ctrl.lsrc(1) 260 std.bits.psrc(0) := enq.bits.psrc(1) 261 std.bits.srcState(0) := enq.bits.srcState(1) 262 std.bits.ctrl.srcType(0) := enq.bits.ctrl.srcType(1) 263 enq.ready := sta.ready && std.ready 264 XSPerfAccumulate(s"st_rs_not_ready_$i", enq.valid && !enq.ready) 265 XSPerfAccumulate(s"sta_rs_not_ready_$i", sta.valid && !sta.ready) 266 XSPerfAccumulate(s"std_rs_not_ready_$i", std.valid && !std.ready) 267 } 268 memScheduler.io.extra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 269 memScheduler.io.extra.intRfReadIn.get <> exuBlocks(0).io.scheExtra.intRfReadOut.get 270 271 memScheduler.io.redirect <> ctrlBlock.io.redirect 272 memScheduler.io.flush <> ctrlBlock.io.flush 273 memBlock.io.issue <> memScheduler.io.issue 274 // By default, instructions do not have exceptions when they enter the function units. 275 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 276 memScheduler.io.writeback <> rfWriteback 277 memScheduler.io.fastUopIn <> allFastUop1 278 memScheduler.io.extra.jumpPc <> ctrlBlock.io.jumpPc 279 memScheduler.io.extra.jalr_target <> ctrlBlock.io.jalr_target 280 memScheduler.io.extra.stIssuePtr <> memBlock.io.stIssuePtr 281 memScheduler.io.extra.loadFastMatch.get <> memBlock.io.loadFastMatch 282 memScheduler.io.extra.debug_int_rat <> ctrlBlock.io.debug_int_rat 283 memScheduler.io.extra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 284 285 exuBlocks.map(_.io).foreach { exu => 286 exu.redirect <> ctrlBlock.io.redirect 287 exu.flush <> ctrlBlock.io.flush 288 exu.rfWriteback <> rfWriteback 289 exu.fastUopIn <> allFastUop1 290 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 291 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 292 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 293 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 294 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 295 } 296 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 297 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 298 299 csrioIn.hartId <> io.hartId 300 csrioIn.perf <> DontCare 301 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 302 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 303 csrioIn.perf.memInfo <> memBlock.io.memInfo 304 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 305 306 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 307 csrioIn.fpu.isIllegal := false.B 308 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 309 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 310 csrioIn.exception <> ctrlBlock.io.robio.exception 311 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 312 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 313 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 314 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 315 csrioIn.externalInterrupt <> io.externalInterrupt 316 317 fenceio.sfence <> memBlock.io.sfence 318 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 319 320 memBlock.io.redirect <> ctrlBlock.io.redirect 321 memBlock.io.flush <> ctrlBlock.io.flush 322 memBlock.io.replay <> memScheduler.io.extra.feedback.get.map(_.replay) 323 memBlock.io.rsIdx <> memScheduler.io.extra.feedback.get.map(_.rsIdx) 324 memBlock.io.isFirstIssue <> memScheduler.io.extra.feedback.get.map(_.isFirstIssue) 325 memBlock.io.csrCtrl <> csrioIn.customCtrl 326 memBlock.io.tlbCsr <> csrioIn.tlb 327 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 328 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 329 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 330 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 331 332 val itlbRepeater = Module(new PTWRepeater(2)) 333 val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.missQueueSize - 1)) 334 itlbRepeater.io.tlb <> frontend.io.ptw 335 dtlbRepeater.io.tlb <> memBlock.io.ptw 336 itlbRepeater.io.sfence <> fenceio.sfence 337 dtlbRepeater.io.sfence <> fenceio.sfence 338 ptw.io.tlb(0) <> itlbRepeater.io.ptw 339 ptw.io.tlb(1) <> dtlbRepeater.io.ptw 340 ptw.io.sfence <> fenceio.sfence 341 ptw.io.csr <> csrioIn.tlb 342 343 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 344 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 345 346 val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform)) 347 ptw.reset := ptw_reset_gen.io.out 348 itlbRepeater.reset := ptw_reset_gen.io.out 349 dtlbRepeater.reset := ptw_reset_gen.io.out 350 351 val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform)) 352 memBlock.reset := memBlock_reset_gen.io.out 353 memScheduler.reset := memBlock_reset_gen.io.out 354 355 val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform)) 356 exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out) 357 358 val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform)) 359 ctrlBlock.reset := ctrlBlock_reset_gen.io.out 360 361 val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform)) 362 frontend.reset := frontend_reset_gen.io.out 363} 364