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 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 94 (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()), 95 (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 96 ), 97 Seq( 98 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 99 (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq()) 100 ) 101 ) 102 103 // should do outer fast wakeup ports here 104 val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) => 105 val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _) 106 val outerPorts = sche.map(cfg => { 107 // exe units from this scheduler need fastUops from exeunits 108 val outerWakeupInSche = sche.filter(_._1.wakeupFromExu) 109 val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1) 110 val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1) 111 // exe units from other schedulers need fastUop from outside 112 val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1) 113 val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1) 114 val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource) 115 val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource) 116 getFastWakeupIndex(cfg._1, intSource, fpSource, numIntWbPorts).sorted 117 }) 118 println(s"inter-scheduler wakeup sources for $i: $outerPorts") 119 outerPorts 120 } 121 122 // allow mdu and fmisc to have 2*numDeq enqueue ports 123 val intDpPorts = (0 until exuParameters.AluCnt).map(i => { 124 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i)) 125 else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i)) 126 else Seq((0, i)) 127 }) 128 val lsDpPorts = Seq( 129 Seq((3, 0)), 130 Seq((3, 1)), 131 Seq((4, 0)), 132 Seq((4, 1)) 133 ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i))) 134 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 135 if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i)) 136 else Seq((0, i)) 137 }) 138 139 val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts) 140 141 val outIntRfReadPorts = Seq(0, 0) 142 val outFpRfReadPorts = Seq(0, 2) 143 val hasIntRf = Seq(true, false) 144 val hasFpRf = Seq(false, true) 145 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map { 146 case (((sche, disp), other), i) => 147 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i))) 148 } 149 150 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 151 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 152 IssQueSize = exuBlocks.head.scheduler.memRsEntries.max 153 ) 154 }))) 155} 156 157class XSCore()(implicit p: config.Parameters) extends XSCoreBase 158 with HasXSDts 159{ 160 lazy val module = new XSCoreImp(this) 161} 162 163class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) 164 with HasXSParameter 165 with HasSoCParameter 166 with HasExeBlockHelper { 167 val io = IO(new Bundle { 168 val hartId = Input(UInt(64.W)) 169 val externalInterrupt = new ExternalInterruptIO 170 val l2_pf_enable = Output(Bool()) 171 val l1plus_error, icache_error, dcache_error = Output(new L1CacheErrorInfo) 172 }) 173 174 println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}") 175 AddressSpace.checkMemmap() 176 AddressSpace.printMemmap() 177 178 val ctrlBlock = Module(new CtrlBlock) 179 180 val frontend = outer.frontend.module 181 val memBlock = outer.memBlock.module 182 val ptw = outer.ptw.module 183 val exuBlocks = outer.exuBlocks.map(_.module) 184 185 val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ memBlock.io.writeback 186 187 val intWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 188 require(exuConfigs.length == allWriteback.length, s"${exuConfigs.length} != ${allWriteback.length}") 189 190 // set default value for ready 191 exuBlocks.foreach(_.io.fuWriteback.foreach(_.ready := true.B)) 192 memBlock.io.writeback.foreach(_.ready := true.B) 193 194 val intArbiter = outer.intArbiter.module 195 intArbiter.io.in.zip(intWriteback).foreach { case (arb, wb) => 196 arb.valid := wb.valid && !wb.bits.uop.ctrl.fpWen 197 arb.bits := wb.bits 198 when (arb.valid) { 199 wb.ready := arb.ready 200 } 201 } 202 203 val fpArbiter = outer.fpArbiter.module 204 val fpWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 205 fpArbiter.io.in.zip(fpWriteback).foreach{ case (arb, wb) => 206 arb.valid := wb.valid && wb.bits.uop.ctrl.fpWen 207 arb.bits := wb.bits 208 when (arb.valid) { 209 wb.ready := arb.ready 210 } 211 } 212 213 val rfWriteback = VecInit(intArbiter.io.out ++ fpArbiter.io.out) 214 215 io.l1plus_error <> DontCare 216 io.icache_error <> frontend.io.error 217 io.dcache_error <> memBlock.io.error 218 219 require(exuBlocks.count(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)) == 1) 220 val csrFenceMod = exuBlocks.filter(_.fuConfigs.map(_._1).contains(JumpCSRExeUnitCfg)).head 221 val csrioIn = csrFenceMod.io.fuExtra.csrio.get 222 val fenceio = csrFenceMod.io.fuExtra.fenceio.get 223 224 frontend.io.backend <> ctrlBlock.io.frontend 225 frontend.io.sfence <> fenceio.sfence 226 frontend.io.tlbCsr <> csrioIn.tlb 227 frontend.io.csrCtrl <> csrioIn.customCtrl 228 frontend.io.fencei := fenceio.fencei 229 230 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 231 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 232 ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect) 233 ctrlBlock.io.stIn <> memBlock.io.stIn 234 ctrlBlock.io.stOut <> memBlock.io.stOut 235 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 236 ctrlBlock.io.enqLsq <> memBlock.io.enqLsq 237 ctrlBlock.io.writeback <> rfWriteback 238 239 val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup 240 require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}") 241 val intFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 242 val fpFastUop = allFastUop.zip(exuConfigs).filter(_._2.writeFpRf).map(_._1) 243 val intFastUop1 = outer.intArbiter.allConnections.map(c => intFastUop(c.head)) 244 val fpFastUop1 = outer.fpArbiter.allConnections.map(c => fpFastUop(c.head)) 245 val allFastUop1 = intFastUop1 ++ fpFastUop1 246 247 ctrlBlock.io.dispatch <> exuBlocks.flatMap(_.io.in) 248 249 exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 250 exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get 251 252 memBlock.io.issue <> exuBlocks(0).io.issue.get 253 // By default, instructions do not have exceptions when they enter the function units. 254 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 255 exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch 256 257 val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt) 258 exuBlocks.map(_.io).foreach { exu => 259 exu.redirect <> ctrlBlock.io.redirect 260 exu.flush <> ctrlBlock.io.flush 261 exu.allocPregs <> ctrlBlock.io.allocPregs 262 exu.rfWriteback <> rfWriteback 263 exu.fastUopIn <> allFastUop1 264 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 265 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 266 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 267 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 268 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 269 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 270 sink.bits := src.bits 271 sink.valid := src.valid && !csrioIn.customCtrl.storeset_no_fast_wakeup 272 }} 273 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 274 sink.valid := src.valid 275 sink.bits := src.bits 276 }} 277 } 278 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 279 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 280 281 csrioIn.hartId <> io.hartId 282 csrioIn.perf <> DontCare 283 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 284 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 285 csrioIn.perf.memInfo <> memBlock.io.memInfo 286 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 287 288 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 289 csrioIn.fpu.isIllegal := false.B 290 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 291 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 292 csrioIn.exception <> ctrlBlock.io.robio.exception 293 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 294 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 295 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 296 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 297 csrioIn.externalInterrupt <> io.externalInterrupt 298 299 fenceio.sfence <> memBlock.io.sfence 300 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 301 302 memBlock.io.redirect <> ctrlBlock.io.redirect 303 memBlock.io.flush <> ctrlBlock.io.flush 304 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 305 memBlock.io.csrCtrl <> csrioIn.customCtrl 306 memBlock.io.tlbCsr <> csrioIn.tlb 307 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 308 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 309 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 310 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 311 312 val itlbRepeater = Module(new PTWRepeater(2)) 313 val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.missQueueSize - 1)) 314 itlbRepeater.io.tlb <> frontend.io.ptw 315 dtlbRepeater.io.tlb <> memBlock.io.ptw 316 itlbRepeater.io.sfence <> fenceio.sfence 317 dtlbRepeater.io.sfence <> fenceio.sfence 318 ptw.io.tlb(0) <> itlbRepeater.io.ptw 319 ptw.io.tlb(1) <> dtlbRepeater.io.ptw 320 ptw.io.sfence <> fenceio.sfence 321 ptw.io.csr.tlb <> csrioIn.tlb 322 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 323 324 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 325 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 326 327 val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform)) 328 ptw.reset := ptw_reset_gen.io.out 329 itlbRepeater.reset := ptw_reset_gen.io.out 330 dtlbRepeater.reset := ptw_reset_gen.io.out 331 332 val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform)) 333 memBlock.reset := memBlock_reset_gen.io.out 334 335 val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform)) 336 exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out) 337 338 val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform)) 339 ctrlBlock.reset := ctrlBlock_reset_gen.io.out 340 341 val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform)) 342 frontend.reset := frontend_reset_gen.io.out 343} 344