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.allocPregs <> ctrlBlock.io.allocPregs 264 exu.rfWriteback <> rfWriteback 265 exu.fastUopIn <> allFastUop1 266 exu.scheExtra.jumpPc <> ctrlBlock.io.jumpPc 267 exu.scheExtra.jalr_target <> ctrlBlock.io.jalr_target 268 exu.scheExtra.stIssuePtr <> memBlock.io.stIssuePtr 269 exu.scheExtra.debug_fp_rat <> ctrlBlock.io.debug_fp_rat 270 exu.scheExtra.debug_int_rat <> ctrlBlock.io.debug_int_rat 271 exu.scheExtra.memWaitUpdateReq.staIssue.zip(memBlock.io.stIn).foreach{case (sink, src) => { 272 sink.bits := src.bits 273 sink.valid := src.valid && !csrioIn.customCtrl.storeset_no_fast_wakeup 274 }} 275 exu.scheExtra.memWaitUpdateReq.stdIssue.zip(stdIssue).foreach{case (sink, src) => { 276 sink.valid := src.valid 277 sink.bits := src.bits 278 }} 279 } 280 XSPerfHistogram("fastIn_count", PopCount(allFastUop1.map(_.valid)), true.B, 0, allFastUop1.length, 1) 281 XSPerfHistogram("wakeup_count", PopCount(rfWriteback.map(_.valid)), true.B, 0, rfWriteback.length, 1) 282 283 // TODO: connect rsPerf 284 val rsPerf = VecInit(exuBlocks.flatMap(_.io.scheExtra.perf)) 285 dontTouch(rsPerf) 286 287 csrioIn.hartId <> io.hartId 288 csrioIn.perf <> DontCare 289 csrioIn.perf.retiredInstr <> ctrlBlock.io.robio.toCSR.perfinfo.retiredInstr 290 csrioIn.perf.ctrlInfo <> ctrlBlock.io.perfInfo.ctrlInfo 291 csrioIn.perf.memInfo <> memBlock.io.memInfo 292 csrioIn.perf.frontendInfo <> frontend.io.frontendInfo 293 294 csrioIn.fpu.fflags <> ctrlBlock.io.robio.toCSR.fflags 295 csrioIn.fpu.isIllegal := false.B 296 csrioIn.fpu.dirty_fs <> ctrlBlock.io.robio.toCSR.dirty_fs 297 csrioIn.fpu.frm <> exuBlocks(1).io.fuExtra.frm.get 298 csrioIn.exception <> ctrlBlock.io.robio.exception 299 csrioIn.isXRet <> ctrlBlock.io.robio.toCSR.isXRet 300 csrioIn.trapTarget <> ctrlBlock.io.robio.toCSR.trapTarget 301 csrioIn.interrupt <> ctrlBlock.io.robio.toCSR.intrBitSet 302 csrioIn.memExceptionVAddr <> memBlock.io.lsqio.exceptionAddr.vaddr 303 304 csrioIn.externalInterrupt.msip := outer.clint_int_sink.in.head._1(0) 305 csrioIn.externalInterrupt.mtip := outer.clint_int_sink.in.head._1(1) 306 csrioIn.externalInterrupt.meip := outer.plic_int_sink.in.head._1(0) 307 csrioIn.externalInterrupt.debug := outer.debug_int_sink.in.head._1(0) 308 309 fenceio.sfence <> memBlock.io.sfence 310 fenceio.sbuffer <> memBlock.io.fenceToSbuffer 311 312 memBlock.io.redirect <> ctrlBlock.io.redirect 313 memBlock.io.rsfeedback <> exuBlocks(0).io.scheExtra.feedback.get 314 memBlock.io.csrCtrl <> csrioIn.customCtrl 315 memBlock.io.tlbCsr <> csrioIn.tlb 316 memBlock.io.lsqio.rob <> ctrlBlock.io.robio.lsq 317 memBlock.io.lsqio.exceptionAddr.lsIdx.lqIdx := ctrlBlock.io.robio.exception.bits.uop.lqIdx 318 memBlock.io.lsqio.exceptionAddr.lsIdx.sqIdx := ctrlBlock.io.robio.exception.bits.uop.sqIdx 319 memBlock.io.lsqio.exceptionAddr.isStore := CommitType.lsInstIsStore(ctrlBlock.io.robio.exception.bits.uop.ctrl.commitType) 320 321 val itlbRepeater = Module(new PTWRepeater(2)) 322 val dtlbRepeater = Module(new PTWFilter(LoadPipelineWidth + StorePipelineWidth, l2tlbParams.filterSize)) 323 itlbRepeater.io.tlb <> frontend.io.ptw 324 dtlbRepeater.io.tlb <> memBlock.io.ptw 325 itlbRepeater.io.sfence <> fenceio.sfence 326 dtlbRepeater.io.sfence <> fenceio.sfence 327 ptw.io.tlb(0) <> itlbRepeater.io.ptw 328 ptw.io.tlb(1) <> dtlbRepeater.io.ptw 329 ptw.io.sfence <> fenceio.sfence 330 ptw.io.csr.tlb <> csrioIn.tlb 331 ptw.io.csr.distribute_csr <> csrioIn.customCtrl.distribute_csr 332 333 // if l2 prefetcher use stream prefetch, it should be placed in XSCore 334 io.l2_pf_enable := csrioIn.customCtrl.l2_pf_enable 335 336 val ptw_reset_gen = Module(new ResetGen(2, !debugOpts.FPGAPlatform)) 337 ptw.reset := ptw_reset_gen.io.out 338 itlbRepeater.reset := ptw_reset_gen.io.out 339 dtlbRepeater.reset := ptw_reset_gen.io.out 340 341 val memBlock_reset_gen = Module(new ResetGen(3, !debugOpts.FPGAPlatform)) 342 memBlock.reset := memBlock_reset_gen.io.out 343 344 val exuBlock_reset_gen = Module(new ResetGen(4, !debugOpts.FPGAPlatform)) 345 exuBlocks.foreach(_.reset := exuBlock_reset_gen.io.out) 346 347 val ctrlBlock_reset_gen = Module(new ResetGen(6, !debugOpts.FPGAPlatform)) 348 ctrlBlock.reset := ctrlBlock_reset_gen.io.out 349 350 val frontend_reset_gen = Module(new ResetGen(7, !debugOpts.FPGAPlatform)) 351 frontend.reset := frontend_reset_gen.io.out 352} 353