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, Wb} 24import xiangshan.frontend._ 25import xiangshan.cache.mmu._ 26import xiangshan.cache.L1plusCacheWrapper 27import chipsalliance.rocketchip.config 28import chipsalliance.rocketchip.config.Parameters 29import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 30import freechips.rocketchip.tile.HasFPUParameters 31import system.{HasSoCParameter, L1CacheErrorInfo, SoCParamsKey} 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 // outer facing nodes 67 val frontend = LazyModule(new Frontend()) 68 val l1pluscache = LazyModule(new L1plusCacheWrapper()) 69 val ptw = LazyModule(new PTWWrapper()) 70 71 val intConfigs = exuConfigs.filter(_.writeIntRf) 72 val intArbiter = LazyModule(new Wb(intConfigs, NRIntWritePorts, isFp = false)) 73 val intWbPorts = intArbiter.allConnections.map(c => c.map(intConfigs(_))) 74 val numIntWbPorts = intWbPorts.length 75 76 val fpConfigs = exuConfigs.filter(_.writeFpRf) 77 val fpArbiter = LazyModule(new Wb(fpConfigs, NRFpWritePorts, isFp = true)) 78 val fpWbPorts = fpArbiter.allConnections.map(c => c.map(fpConfigs(_))) 79 val numFpWbPorts = fpWbPorts.length 80 81 // TODO: better RS organization 82 // generate rs according to number of function units 83 require(exuParameters.JmpCnt == 1) 84 require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0) 85 require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0) 86 require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2) 87 88 // one RS every 2 MDUs 89 val schedulePorts = Seq( 90 // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget 91 Seq( 92 (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StExeUnitCfg), Seq()) 93 ), 94 Seq( 95 (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StExeUnitCfg), Seq()), 96 (JumpCSRExeUnitCfg, 1, Seq(), Seq()) 97 ), 98 Seq( 99 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 100 (FmiscExeUnitCfg, exuParameters.FmiscCnt, Seq(), Seq()) 101 ), 102 Seq( 103 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 104 (StExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 105 ) 106 ) 107 108 // should do outer fast wakeup ports here 109 val otherFastPorts = schedulePorts.zipWithIndex.map { case (sche, i) => 110 val otherCfg = schedulePorts.zipWithIndex.filter(_._2 != i).map(_._1).reduce(_ ++ _) 111 val outerPorts = sche.map(cfg => { 112 // exe units from this scheduler need fastUops from exeunits 113 val outerWakeupInSche = sche.filter(_._1.wakeupFromExu) 114 val intraIntScheOuter = outerWakeupInSche.filter(_._3.contains(cfg._1)).map(_._1) 115 val intraFpScheOuter = outerWakeupInSche.filter(_._4.contains(cfg._1)).map(_._1) 116 // exe units from other schedulers need fastUop from outside 117 val otherIntSource = otherCfg.filter(_._3.contains(cfg._1)).map(_._1) 118 val otherFpSource = otherCfg.filter(_._4.contains(cfg._1)).map(_._1) 119 val intSource = findInWbPorts(intWbPorts, intraIntScheOuter ++ otherIntSource) 120 val fpSource = findInWbPorts(fpWbPorts, intraFpScheOuter ++ otherFpSource) 121 getFastWakeupIndex(cfg._1, intSource, fpSource, numIntWbPorts).sorted 122 }) 123 println(s"inter-scheduler wakeup sources for $i: $outerPorts") 124 outerPorts 125 } 126 127 // allow mdu and fmisc to have 2*numDeq enqueue ports 128 val intDpPorts = (0 until exuParameters.AluCnt).map(i => Seq((0, i))) 129 val int1DpPorts = (0 until 2*exuParameters.MduCnt).map(i => { 130 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i)) 131 else Seq((0, i)) 132 }) 133 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 134 if (i < 2*exuParameters.FmiscCnt) Seq((0, i), (1, i)) 135 else Seq((1, i)) 136 }) 137 val lsDpPorts = Seq( 138 Seq((0, 0)), 139 Seq((0, 1)), 140 Seq((1, 0)), 141 Seq((1, 1)) 142 ) 143 val dispatchPorts = Seq(intDpPorts, int1DpPorts, fpDpPorts, lsDpPorts) 144 145 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).reverse.drop(1).reverseMap { case ((sche, disp), other) => 146 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other)) 147 } 148 149 val memScheduler = LazyModule(new Scheduler(schedulePorts.last, dispatchPorts.last, intWbPorts, fpWbPorts, otherFastPorts.last)) 150 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 151 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 152 IssQueSize = memScheduler.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 l1pluscache = outer.l1pluscache.module 183 val ptw = outer.ptw.module 184 val exuBlocks = outer.exuBlocks.map(_.module) 185 val memScheduler = outer.memScheduler.module 186 187 val allWriteback = exuBlocks.map(_.io.fuWriteback).fold(Seq())(_ ++ _) ++ memBlock.io.writeback 188 189 val intWriteback = allWriteback.zip(exuConfigs).filter(_._2.writeIntRf).map(_._1) 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 <> l1pluscache.io.error 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 229 frontend.io.icacheMemAcq <> l1pluscache.io.req 230 l1pluscache.io.resp <> frontend.io.icacheMemGrant 231 l1pluscache.io.flush := frontend.io.l1plusFlush 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(2).io.allocate ++ memScheduler.io.allocate 251 for (i <- 0 until exuParameters.AluCnt) { 252 val rsIn = VecInit(Seq(exuBlocks(0).io.allocate(i), exuBlocks(1).io.allocate(i))) 253 val func1 = (op: MicroOp) => outer.exuBlocks(0).scheduler.canAccept(op.ctrl.fuType) 254 val func2 = (op: MicroOp) => outer.exuBlocks(1).scheduler.canAccept(op.ctrl.fuType) 255 val arbiterOut = DispatchArbiter(ctrlBlock.io.enqIQ(i), Seq(func1, func2)) 256 rsIn <> arbiterOut 257 } 258 memScheduler.io.redirect <> ctrlBlock.io.redirect 259 memScheduler.io.flush <> ctrlBlock.io.flush 260 memScheduler.io.issue <> memBlock.io.issue 261 memScheduler.io.writeback <> rfWriteback 262 memScheduler.io.fastUopIn <> allFastUop1 263 memScheduler.io.extra.jumpPc <> ctrlBlock.io.jumpPc 264 memScheduler.io.extra.jalr_target <> ctrlBlock.io.jalr_target 265 memScheduler.io.extra.stIssuePtr <> memBlock.io.stIssuePtr 266 memScheduler.io.extra.debug_int_rat <> ctrlBlock.io.debug_int_rat 267 memScheduler.io.extra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 268 269 exuBlocks.map(_.io).foreach { exu => 270 exu.redirect <> ctrlBlock.io.redirect 271 exu.flush <> ctrlBlock.io.flush 272 exu.rfWriteback <> rfWriteback 273 exu.fastUopIn <> allFastUop1 274 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 275 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 276 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 277 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 278 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 279 } 280 281 csrioIn.hartId <> io.hartId 282 csrioIn.perf <> DontCare 283 csrioIn.perf.retiredInstr <> ctrlBlock.io.roqio.toCSR.perfinfo.retiredInstr 284 // csrioIn.perf.bpuInfo <> DontCare // TODO: reassign this 285 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 286 csrioIn.perf.memInfo <> memBlock.io.memInfo 287 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 288 289 csrioIn.fpu.fflags <> ctrlBlock.io.roqio.toCSR.fflags 290 csrioIn.fpu.isIllegal := false.B 291 csrioIn.fpu.dirty_fs <> ctrlBlock.io.roqio.toCSR.dirty_fs 292 csrioIn.fpu.frm <> exuBlocks(2).io.fuExtra.frm.get 293 csrioIn.exception <> ctrlBlock.io.roqio.exception 294 csrioIn.isXRet <> ctrlBlock.io.roqio.toCSR.isXRet 295 csrioIn.trapTarget <> ctrlBlock.io.roqio.toCSR.trapTarget 296 csrioIn.interrupt <> ctrlBlock.io.roqio.toCSR.intrBitSet 297 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 298 csrioIn.externalInterrupt <> io.externalInterrupt 299 300 fenceio.sfence <> memBlock.io.sfence 301 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 302 303 memBlock.io.redirect <> ctrlBlock.io.redirect 304 memBlock.io.flush <> ctrlBlock.io.flush 305 memBlock.io.replay <> memScheduler.io.extra.feedback.get.map(_.replay) 306 memBlock.io.rsIdx <> memScheduler.io.extra.feedback.get.map(_.rsIdx) 307 memBlock.io.isFirstIssue <> memScheduler.io.extra.feedback.get.map(_.isFirstIssue) 308 memBlock.io.stData <> memScheduler.stData 309 memBlock.io.csrCtrl <> csrioIn.customCtrl 310 memBlock.io.tlbCsr <> csrioIn.tlb 311 memBlock.io.lsqio.roq <> ctrlBlock.io.roqio.lsq 312 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.roqio.exception.bits.uop.lqIdx 313 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.roqio.exception.bits.uop.sqIdx 314 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.roqio.exception.bits.uop.ctrl.commitType) 315 316 val itlbRepeater = Module(new PTWRepeater(2)) 317 val dtlbRepeater = if (usePTWRepeater) { 318 Module(new PTWRepeater(LoadPipelineWidth + StorePipelineWidth)) 319 } else { 320 Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, PtwMissQueueSize)) 321 } 322 itlbRepeater.io.tlb <> frontend.io.ptw 323 dtlbRepeater.io.tlb <> memBlock.io.ptw 324 itlbRepeater.io.sfence <> fenceio.sfence 325 dtlbRepeater.io.sfence <> fenceio.sfence 326 ptw.io.tlb(0) <> itlbRepeater.io.ptw 327 ptw.io.tlb(1) <> dtlbRepeater.io.ptw 328 ptw.io.sfence <> fenceio.sfence 329 ptw.io.csr <> csrioIn.tlb 330 331 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 332 assert(l2PrefetcherParameters._type == "bop") 333 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 334 335 val l1plus_reset_gen = Module(new ResetGen(1, !debugOpts.FPGAPlatform)) 336 l1pluscache.reset := l1plus_reset_gen.io.out 337 338 val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform)) 339 ptw.reset := ptw_reset_gen.io.out 340 itlbRepeater.reset := ptw_reset_gen.io.out 341 dtlbRepeater.reset := ptw_reset_gen.io.out 342 343 val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform)) 344 memBlock.reset := memBlock_reset_gen.io.out 345 346 val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform)) 347 exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out) 348 349 val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform)) 350 ctrlBlock.reset := ctrlBlock_reset_gen.io.out 351 352 val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform)) 353 frontend.reset := frontend_reset_gen.io.out 354} 355