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.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 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 // interrupt sinks 67 val clint_int_sink = IntSinkNode(IntSinkPortSimple(1, 2)) 68 val debug_int_sink = IntSinkNode(IntSinkPortSimple(1, 1)) 69 val plic_int_sink = IntSinkNode(IntSinkPortSimple(1, 1)) 70 // outer facing nodes 71 val frontend = LazyModule(new Frontend()) 72 val ptw = LazyModule(new PTWWrapper()) 73 74 val intConfigs = exuConfigs.filter(_.writeIntRf) 75 val intArbiter = LazyModule(new WbArbiter(intConfigs, NRIntWritePorts, isFp = false)) 76 val intWbPorts = intArbiter.allConnections.map(c => c.map(intConfigs(_))) 77 val numIntWbPorts = intWbPorts.length 78 79 val fpConfigs = exuConfigs.filter(_.writeFpRf) 80 val fpArbiter = LazyModule(new WbArbiter(fpConfigs, NRFpWritePorts, isFp = true)) 81 val fpWbPorts = fpArbiter.allConnections.map(c => c.map(fpConfigs(_))) 82 val numFpWbPorts = fpWbPorts.length 83 84 // TODO: better RS organization 85 // generate rs according to number of function units 86 require(exuParameters.JmpCnt == 1) 87 require(exuParameters.MduCnt <= exuParameters.AluCnt && exuParameters.MduCnt > 0) 88 require(exuParameters.FmiscCnt <= exuParameters.FmacCnt && exuParameters.FmiscCnt > 0) 89 require(exuParameters.LduCnt == 2 && exuParameters.StuCnt == 2) 90 91 // one RS every 2 MDUs 92 val schedulePorts = Seq( 93 // exuCfg, numDeq, intFastWakeupTarget, fpFastWakeupTarget 94 Seq( 95 (AluExeUnitCfg, exuParameters.AluCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg, JumpCSRExeUnitCfg, LdExeUnitCfg, StaExeUnitCfg), Seq()), 96 (MulDivExeUnitCfg, exuParameters.MduCnt, Seq(AluExeUnitCfg, MulDivExeUnitCfg), Seq()), 97 (JumpCSRExeUnitCfg, 1, Seq(), Seq()), 98 (LdExeUnitCfg, exuParameters.LduCnt, Seq(AluExeUnitCfg, LdExeUnitCfg), Seq()), 99 (StaExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()), 100 (StdExeUnitCfg, exuParameters.StuCnt, Seq(), Seq()) 101 ), 102 Seq( 103 (FmacExeUnitCfg, exuParameters.FmacCnt, Seq(), Seq(FmacExeUnitCfg, FmiscExeUnitCfg)), 104 (FmiscExeUnitCfg, exuParameters.FmiscCnt, 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 => { 129 if (i < exuParameters.JmpCnt) Seq((0, i), (1, i), (2, i)) 130 else if (i < 2 * exuParameters.MduCnt) Seq((0, i), (1, i)) 131 else Seq((0, i)) 132 }) 133 val lsDpPorts = Seq( 134 Seq((3, 0)), 135 Seq((3, 1)), 136 Seq((4, 0)), 137 Seq((4, 1)) 138 ) ++ (0 until exuParameters.StuCnt).map(i => Seq((5, i))) 139 val fpDpPorts = (0 until exuParameters.FmacCnt).map(i => { 140 if (i < 2 * exuParameters.FmiscCnt) Seq((0, i), (1, i)) 141 else Seq((0, i)) 142 }) 143 144 val dispatchPorts = Seq(intDpPorts ++ lsDpPorts, fpDpPorts) 145 146 val outIntRfReadPorts = Seq(0, 0) 147 val outFpRfReadPorts = Seq(0, 2) 148 val hasIntRf = Seq(true, false) 149 val hasFpRf = Seq(false, true) 150 val exuBlocks = schedulePorts.zip(dispatchPorts).zip(otherFastPorts).zipWithIndex.map { 151 case (((sche, disp), other), i) => 152 LazyModule(new ExuBlock(sche, disp, intWbPorts, fpWbPorts, other, outIntRfReadPorts(i), outFpRfReadPorts(i), hasIntRf(i), hasFpRf(i))) 153 } 154 155 val memBlock = LazyModule(new MemBlock()(p.alter((site, here, up) => { 156 case XSCoreParamsKey => up(XSCoreParamsKey).copy( 157 IssQueSize = exuBlocks.head.scheduler.memRsEntries.max 158 ) 159 }))) 160} 161 162class XSCore()(implicit p: config.Parameters) extends XSCoreBase 163 with HasXSDts 164{ 165 lazy val module = new XSCoreImp(this) 166} 167 168class XSCoreImp(outer: XSCoreBase) extends LazyModuleImp(outer) 169 with HasXSParameter 170 with HasSoCParameter 171 with HasExeBlockHelper { 172 val io = IO(new Bundle { 173 val hartId = Input(UInt(64.W)) 174 val l2_pf_enable = Output(Bool()) 175 val beu_errors = Output(new XSL1BusErrors()) 176 }) 177 178 println(s"FPGAPlatform:${env.FPGAPlatform} EnableDebug:${env.EnableDebug}") 179 AddressSpace.checkMemmap() 180 AddressSpace.printMemmap() 181 182 val ctrlBlock = Module(new CtrlBlock) 183 184 val frontend = outer.frontend.module 185 val memBlock = outer.memBlock.module 186 val ptw = outer.ptw.module 187 val exuBlocks = outer.exuBlocks.map(_.module) 188 189 val allWriteback = exuBlocks.flatMap(_.io.fuWriteback) ++ 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.beu_errors.icache <> frontend.io.error 220 io.beu_errors.dcache <> 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 frontend.io.fencei := fenceio.fencei 232 233 ctrlBlock.io.csrCtrl <> csrioIn.customCtrl 234 val redirectBlocks = exuBlocks.reverse.filter(_.fuConfigs.map(_._1).map(_.hasRedirect).reduce(_ || _)) 235 ctrlBlock.io.exuRedirect <> redirectBlocks.flatMap(_.io.fuExtra.exuRedirect) 236 ctrlBlock.io.stIn <> memBlock.io.stIn 237 ctrlBlock.io.stOut <> memBlock.io.stOut 238 ctrlBlock.io.memoryViolation <> memBlock.io.memoryViolation 239 ctrlBlock.io.enqLsq <> memBlock.io.enqLsq 240 ctrlBlock.io.writeback <> rfWriteback 241 242 val allFastUop = exuBlocks.flatMap(b => b.io.fastUopOut.dropRight(b.numOutFu)) ++ memBlock.io.otherFastWakeup 243 require(allFastUop.length == exuConfigs.length, s"${allFastUop.length} != ${exuConfigs.length}") 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.dispatch <> exuBlocks.flatMap(_.io.in) 251 252 exuBlocks(0).io.scheExtra.fpRfReadIn.get <> exuBlocks(1).io.scheExtra.fpRfReadOut.get 253 exuBlocks(0).io.scheExtra.fpStateReadIn.get <> exuBlocks(1).io.scheExtra.fpStateReadOut.get 254 255 memBlock.io.issue <> exuBlocks(0).io.issue.get 256 // By default, instructions do not have exceptions when they enter the function units. 257 memBlock.io.issue.map(_.bits.uop.clearExceptions()) 258 exuBlocks(0).io.scheExtra.loadFastMatch.get <> memBlock.io.loadFastMatch 259 260 val stdIssue = exuBlocks(0).io.issue.get.takeRight(exuParameters.StuCnt) 261 exuBlocks.map(_.io).foreach { exu => 262 exu.redirect <> ctrlBlock.io.redirect 263 exu.flush <> ctrlBlock.io.flush 264 exu.allocPregs <> ctrlBlock.io.allocPregs 265 exu.rfWriteback <> rfWriteback 266 exu.fastUopIn <> allFastUop1 267 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 268 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 269 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 270 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 271 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 272 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 273 sink.bits := src.bits 274 sink.valid := src.valid && !csrioIn.customCtrl.storeset_no_fast_wakeup 275 }} 276 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 277 sink.valid := src.valid 278 sink.bits := src.bits 279 }} 280 } 281 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 282 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 283 284 // TODO: connect rsPerf 285 val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf)) 286 dontTouch(rsPerf) 287 288 csrioIn.hartId <> io.hartId 289 csrioIn.perf <> DontCare 290 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 291 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 292 csrioIn.perf.memInfo <> memBlock.io.memInfo 293 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 294 295 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 296 csrioIn.fpu.isIllegal := false.B 297 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 298 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 299 csrioIn.exception <> ctrlBlock.io.robio.exception 300 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 301 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 302 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 303 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 304 305 csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0) 306 csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1) 307 csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0) 308 csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0) 309 310 fenceio.sfence <> memBlock.io.sfence 311 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 312 313 memBlock.io.redirect <> ctrlBlock.io.redirect 314 memBlock.io.flush <> ctrlBlock.io.flush 315 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 316 memBlock.io.csrCtrl <> csrioIn.customCtrl 317 memBlock.io.tlbCsr <> csrioIn.tlb 318 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 319 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 320 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 321 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 322 323 val itlbRepeater = Module(new PTWRepeater(2)) 324 val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.filterSize)) 325 itlbRepeater.io.tlb <> frontend.io.ptw 326 dtlbRepeater.io.tlb <> memBlock.io.ptw 327 itlbRepeater.io.sfence <> fenceio.sfence 328 dtlbRepeater.io.sfence <> fenceio.sfence 329 ptw.io.tlb(0) <> itlbRepeater.io.ptw 330 ptw.io.tlb(1) <> dtlbRepeater.io.ptw 331 ptw.io.sfence <> fenceio.sfence 332 ptw.io.csr.tlb <> csrioIn.tlb 333 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 334 335 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 336 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 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