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