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