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.frontend.icache 18 19import chisel3._ 20import chisel3.util._ 21import difftest._ 22import freechips.rocketchip.tilelink.ClientStates 23import org.chipsalliance.cde.config.Parameters 24import utility._ 25import utils._ 26import xiangshan._ 27import xiangshan.backend.fu.PMPReqBundle 28import xiangshan.backend.fu.PMPRespBundle 29import xiangshan.cache.mmu._ 30import xiangshan.frontend.ExceptionType 31import xiangshan.frontend.FtqICacheInfo 32import xiangshan.frontend.FtqToICacheRequestBundle 33 34class ICacheMainPipeReq(implicit p: Parameters) extends ICacheBundle { 35 val vaddr = UInt(VAddrBits.W) 36 def vSetIdx = get_idx(vaddr) 37} 38 39class ICacheMainPipeResp(implicit p: Parameters) extends ICacheBundle { 40 val doubleline = Bool() 41 val vaddr = Vec(PortNumber, UInt(VAddrBits.W)) 42 val data = UInt(blockBits.W) 43 val paddr = Vec(PortNumber, UInt(PAddrBits.W)) 44 val exception = Vec(PortNumber, UInt(ExceptionType.width.W)) 45 val pmp_mmio = Vec(PortNumber, Bool()) 46 val itlb_pbmt = Vec(PortNumber, UInt(Pbmt.width.W)) 47 val backendException = Bool() 48 /* NOTE: GPAddrBits(=50bit) is not enough for gpaddr here, refer to PR#3795 49 * Sv48*4 only allows 50bit gpaddr, when software violates this requirement 50 * it needs to fill the mtval2 register with the full XLEN(=64bit) gpaddr, 51 * PAddrBitsMax(=56bit currently) is required for the frontend datapath due to the itlb ppn length limitation 52 * (cases 56<x<=64 are handled by the backend datapath) 53 */ 54 val gpaddr = UInt(PAddrBitsMax.W) 55 val isForVSnonLeafPTE = Bool() 56} 57 58class ICacheMainPipeBundle(implicit p: Parameters) extends ICacheBundle { 59 val req = Flipped(Decoupled(new FtqToICacheRequestBundle)) 60 val resp = ValidIO(new ICacheMainPipeResp) 61 val topdownIcacheMiss = Output(Bool()) 62 val topdownItlbMiss = Output(Bool()) 63} 64 65class ICacheMetaReqBundle(implicit p: Parameters) extends ICacheBundle { 66 val toIMeta = DecoupledIO(new ICacheReadBundle) 67 val fromIMeta = Input(new ICacheMetaRespBundle) 68} 69 70class ICacheDataReqBundle(implicit p: Parameters) extends ICacheBundle { 71 val toIData = Vec(partWayNum, DecoupledIO(new ICacheReadBundle)) 72 val fromIData = Input(new ICacheDataRespBundle) 73} 74 75class ICacheMSHRBundle(implicit p: Parameters) extends ICacheBundle { 76 val req = Decoupled(new ICacheMissReq) 77 val resp = Flipped(ValidIO(new ICacheMissResp)) 78} 79 80class ICachePMPBundle(implicit p: Parameters) extends ICacheBundle { 81 val req = Valid(new PMPReqBundle()) 82 val resp = Input(new PMPRespBundle()) 83} 84 85class ICachePerfInfo(implicit p: Parameters) extends ICacheBundle { 86 val only_0_hit = Bool() 87 val only_0_miss = Bool() 88 val hit_0_hit_1 = Bool() 89 val hit_0_miss_1 = Bool() 90 val miss_0_hit_1 = Bool() 91 val miss_0_miss_1 = Bool() 92 val hit_0_except_1 = Bool() 93 val miss_0_except_1 = Bool() 94 val except_0 = Bool() 95 val bank_hit = Vec(2, Bool()) 96 val hit = Bool() 97} 98 99class ICacheMainPipeInterface(implicit p: Parameters) extends ICacheBundle { 100 val hartId = Input(UInt(hartIdLen.W)) 101 102 /*** internal interface ***/ 103 val dataArray = new ICacheDataReqBundle 104 val metaArrayFlush = Vec(PortNumber, ValidIO(new ICacheMetaFlushBundle)) 105 106 /** prefetch io */ 107 val touch = Vec(PortNumber, ValidIO(new ReplacerTouch)) 108 val wayLookupRead = Flipped(DecoupledIO(new WayLookupInfo)) 109 110 val mshr = new ICacheMSHRBundle 111 val errors = Output(Vec(PortNumber, ValidIO(new L1CacheErrorInfo))) 112 113 /*** outside interface ***/ 114 // val fetch = Vec(PortNumber, new ICacheMainPipeBundle) 115 /* when ftq.valid is high in T + 1 cycle 116 * the ftq component must be valid in T cycle 117 */ 118 val fetch = new ICacheMainPipeBundle 119 val pmp = Vec(PortNumber, new ICachePMPBundle) 120 val respStall = Input(Bool()) 121 122 val csr_parity_enable = Input(Bool()) 123 val flush = Input(Bool()) 124 125 val perfInfo = Output(new ICachePerfInfo) 126} 127 128class ICacheDB(implicit p: Parameters) extends ICacheBundle { 129 val blk_vaddr = UInt((VAddrBits - blockOffBits).W) 130 val blk_paddr = UInt((PAddrBits - blockOffBits).W) 131 val hit = Bool() 132} 133 134class ICacheMainPipe(implicit p: Parameters) extends ICacheModule { 135 val io = IO(new ICacheMainPipeInterface) 136 137 /** Input/Output port */ 138 val (fromFtq, toIFU) = (io.fetch.req, io.fetch.resp) 139 val (toData, fromData) = (io.dataArray.toIData, io.dataArray.fromIData) 140 val toMetaFlush = io.metaArrayFlush 141 val (toMSHR, fromMSHR) = (io.mshr.req, io.mshr.resp) 142 val (toPMP, fromPMP) = (io.pmp.map(_.req), io.pmp.map(_.resp)) 143 val fromWayLookup = io.wayLookupRead 144 val csr_parity_enable = if (ICacheForceMetaECCError || ICacheForceDataECCError) true.B else io.csr_parity_enable 145 146 // Statistics on the frequency distribution of FTQ fire interval 147 val cntFtqFireInterval = RegInit(0.U(32.W)) 148 cntFtqFireInterval := Mux(fromFtq.fire, 1.U, cntFtqFireInterval + 1.U) 149 XSPerfHistogram("ftq2icache_fire", cntFtqFireInterval, fromFtq.fire, 1, 300, 1, right_strict = true) 150 151 /** pipeline control signal */ 152 val s1_ready, s2_ready = Wire(Bool()) 153 val s0_fire, s1_fire, s2_fire = Wire(Bool()) 154 val s0_flush, s1_flush, s2_flush = Wire(Bool()) 155 156 /** 157 ****************************************************************************** 158 * ICache Stage 0 159 * - send req to data SRAM 160 * - get waymask and tlb info from wayLookup 161 ****************************************************************************** 162 */ 163 164 /** s0 control */ 165 // 0,1,2,3 -> dataArray(data); 4 -> mainPipe 166 // Ftq RegNext Register 167 val fromFtqReq = fromFtq.bits.pcMemRead 168 val s0_valid = fromFtq.valid 169 val s0_req_valid_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i)) 170 val s0_req_vaddr_all = 171 (0 until partWayNum + 1).map(i => VecInit(Seq(fromFtqReq(i).startAddr, fromFtqReq(i).nextlineStart))) 172 val s0_req_vSetIdx_all = (0 until partWayNum + 1).map(i => VecInit(s0_req_vaddr_all(i).map(get_idx))) 173 val s0_req_offset_all = (0 until partWayNum + 1).map(i => s0_req_vaddr_all(i)(0)(log2Ceil(blockBytes) - 1, 0)) 174 val s0_doubleline_all = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && fromFtqReq(i).crossCacheline) 175 176 val s0_req_vaddr = s0_req_vaddr_all.last 177 val s0_req_vSetIdx = s0_req_vSetIdx_all.last 178 val s0_doubleline = s0_doubleline_all.last 179 180 val s0_backendException = fromFtq.bits.backendException 181 182 /** 183 ****************************************************************************** 184 * get waymask and tlb info from wayLookup 185 ****************************************************************************** 186 */ 187 fromWayLookup.ready := s0_fire 188 val s0_waymasks = VecInit(fromWayLookup.bits.waymask.map(_.asTypeOf(Vec(nWays, Bool())))) 189 val s0_req_ptags = fromWayLookup.bits.ptag 190 val s0_req_gpaddr = fromWayLookup.bits.gpaddr 191 val s0_req_isForVSnonLeafPTE = fromWayLookup.bits.isForVSnonLeafPTE 192 val s0_itlb_exception = fromWayLookup.bits.itlb_exception 193 val s0_itlb_pbmt = fromWayLookup.bits.itlb_pbmt 194 val s0_meta_codes = fromWayLookup.bits.meta_codes 195 val s0_hits = VecInit(fromWayLookup.bits.waymask.map(_.orR)) 196 197 when(s0_fire) { 198 assert( 199 (0 until PortNumber).map(i => s0_req_vSetIdx(i) === fromWayLookup.bits.vSetIdx(i)).reduce(_ && _), 200 "vSetIdxs from ftq and wayLookup are different! vaddr0=0x%x ftq: vidx0=0x%x vidx1=0x%x wayLookup: vidx0=0x%x vidx1=0x%x", 201 s0_req_vaddr(0), 202 s0_req_vSetIdx(0), 203 s0_req_vSetIdx(1), 204 fromWayLookup.bits.vSetIdx(0), 205 fromWayLookup.bits.vSetIdx(1) 206 ) 207 } 208 209 /** 210 ****************************************************************************** 211 * data SRAM request 212 ****************************************************************************** 213 */ 214 for (i <- 0 until partWayNum) { 215 toData(i).valid := s0_req_valid_all(i) 216 toData(i).bits.isDoubleLine := s0_doubleline_all(i) 217 toData(i).bits.vSetIdx := s0_req_vSetIdx_all(i) 218 toData(i).bits.blkOffset := s0_req_offset_all(i) 219 toData(i).bits.wayMask := s0_waymasks 220 } 221 222 val s0_can_go = toData.last.ready && fromWayLookup.valid && s1_ready 223 s0_flush := io.flush 224 s0_fire := s0_valid && s0_can_go && !s0_flush 225 226 fromFtq.ready := s0_can_go 227 228 /** 229 ****************************************************************************** 230 * ICache Stage 1 231 * - PMP check 232 * - get Data SRAM read responses (latched for pipeline stop) 233 * - monitor missUint response port 234 ****************************************************************************** 235 */ 236 val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = s1_flush, lastFlush = false.B) 237 238 val s1_req_vaddr = RegEnable(s0_req_vaddr, 0.U.asTypeOf(s0_req_vaddr), s0_fire) 239 val s1_req_ptags = RegEnable(s0_req_ptags, 0.U.asTypeOf(s0_req_ptags), s0_fire) 240 val s1_req_gpaddr = RegEnable(s0_req_gpaddr, 0.U.asTypeOf(s0_req_gpaddr), s0_fire) 241 val s1_req_isForVSnonLeafPTE = RegEnable(s0_req_isForVSnonLeafPTE, 0.U.asTypeOf(s0_req_isForVSnonLeafPTE), s0_fire) 242 val s1_doubleline = RegEnable(s0_doubleline, 0.U.asTypeOf(s0_doubleline), s0_fire) 243 val s1_SRAMhits = RegEnable(s0_hits, 0.U.asTypeOf(s0_hits), s0_fire) 244 val s1_itlb_exception = RegEnable(s0_itlb_exception, 0.U.asTypeOf(s0_itlb_exception), s0_fire) 245 val s1_backendException = RegEnable(s0_backendException, false.B, s0_fire) 246 val s1_itlb_pbmt = RegEnable(s0_itlb_pbmt, 0.U.asTypeOf(s0_itlb_pbmt), s0_fire) 247 val s1_waymasks = RegEnable(s0_waymasks, 0.U.asTypeOf(s0_waymasks), s0_fire) 248 val s1_meta_codes = RegEnable(s0_meta_codes, 0.U.asTypeOf(s0_meta_codes), s0_fire) 249 250 val s1_req_vSetIdx = s1_req_vaddr.map(get_idx) 251 val s1_req_paddr = s1_req_vaddr.zip(s1_req_ptags).map { case (vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag) } 252 val s1_req_offset = s1_req_vaddr(0)(log2Ceil(blockBytes) - 1, 0) 253 254 // do metaArray ECC check 255 val s1_meta_corrupt = VecInit((s1_req_ptags zip s1_meta_codes zip s1_waymasks).map { case ((meta, code), waymask) => 256 val hit_num = PopCount(waymask) 257 // NOTE: if not hit, encodeMetaECC(meta) =/= code can also be true, but we don't care about it 258 (encodeMetaECC(meta) =/= code && hit_num === 1.U) || // hit one way, but parity code does not match, ECC failure 259 hit_num > 1.U // hit multi way, must be a ECC failure 260 }) 261 // force clear meta_corrupt when parity check is disabled 262 when(!csr_parity_enable) { 263 s1_meta_corrupt := VecInit(Seq.fill(PortNumber)(false.B)) 264 } 265 266 /** 267 ****************************************************************************** 268 * update replacement status register 269 ****************************************************************************** 270 */ 271 (0 until PortNumber).foreach { i => 272 io.touch(i).bits.vSetIdx := s1_req_vSetIdx(i) 273 io.touch(i).bits.way := OHToUInt(s1_waymasks(i)) 274 } 275 io.touch(0).valid := RegNext(s0_fire) && s1_SRAMhits(0) 276 io.touch(1).valid := RegNext(s0_fire) && s1_SRAMhits(1) && s1_doubleline 277 278 /** 279 ****************************************************************************** 280 * PMP check 281 ****************************************************************************** 282 */ 283 toPMP.zipWithIndex.foreach { case (p, i) => 284 // if itlb has exception, paddr can be invalid, therefore pmp check can be skipped 285 p.valid := s1_valid // && !ExceptionType.hasException(s1_itlb_exception(i)) 286 p.bits.addr := s1_req_paddr(i) 287 p.bits.size := 3.U // TODO 288 p.bits.cmd := TlbCmd.exec 289 } 290 val s1_pmp_exception = VecInit(fromPMP.map(ExceptionType.fromPMPResp)) 291 val s1_pmp_mmio = VecInit(fromPMP.map(_.mmio)) 292 293 // merge s1 itlb/pmp exceptions, itlb has the highest priority, pmp next 294 val s1_exception_out = ExceptionType.merge( 295 s1_itlb_exception, 296 s1_pmp_exception 297 ) 298 299 /** 300 ****************************************************************************** 301 * select data from MSHR, SRAM 302 ****************************************************************************** 303 */ 304 val s1_MSHR_match = VecInit((0 until PortNumber).map(i => 305 (s1_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) && 306 (s1_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) && 307 fromMSHR.valid && !fromMSHR.bits.corrupt 308 )) 309 val s1_MSHR_hits = Seq(s1_valid && s1_MSHR_match(0), s1_valid && (s1_MSHR_match(1) && s1_doubleline)) 310 val s1_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits / ICacheDataBanks).W))) 311 312 val s1_hits = (0 until PortNumber).map(i => 313 ValidHoldBypass(s1_MSHR_hits(i) || (RegNext(s0_fire) && s1_SRAMhits(i)), s1_fire || s1_flush) 314 ) 315 316 val s1_bankIdxLow = s1_req_offset >> log2Ceil(blockBytes / ICacheDataBanks) 317 val s1_bankMSHRHit = VecInit((0 until ICacheDataBanks).map(i => 318 (i.U >= s1_bankIdxLow) && s1_MSHR_hits(0) || 319 (i.U < s1_bankIdxLow) && s1_MSHR_hits(1) 320 )) 321 val s1_datas = VecInit((0 until ICacheDataBanks).map(i => 322 DataHoldBypass(Mux(s1_bankMSHRHit(i), s1_MSHR_datas(i), fromData.datas(i)), s1_bankMSHRHit(i) || RegNext(s0_fire)) 323 )) 324 val s1_data_is_from_MSHR = VecInit((0 until ICacheDataBanks).map(i => 325 DataHoldBypass(s1_bankMSHRHit(i), s1_bankMSHRHit(i) || RegNext(s0_fire)) 326 )) 327 val s1_codes = DataHoldBypass(fromData.codes, RegNext(s0_fire)) 328 329 s1_flush := io.flush 330 s1_ready := s2_ready || !s1_valid 331 s1_fire := s1_valid && s2_ready && !s1_flush 332 333 /** 334 ****************************************************************************** 335 * ICache Stage 2 336 * - send request to MSHR if ICache miss 337 * - monitor missUint response port 338 * - response to IFU 339 ****************************************************************************** 340 */ 341 342 val s2_valid = generatePipeControl(lastFire = s1_fire, thisFire = s2_fire, thisFlush = s2_flush, lastFlush = false.B) 343 344 val s2_req_vaddr = RegEnable(s1_req_vaddr, 0.U.asTypeOf(s1_req_vaddr), s1_fire) 345 val s2_req_ptags = RegEnable(s1_req_ptags, 0.U.asTypeOf(s1_req_ptags), s1_fire) 346 val s2_req_gpaddr = RegEnable(s1_req_gpaddr, 0.U.asTypeOf(s1_req_gpaddr), s1_fire) 347 val s2_req_isForVSnonLeafPTE = RegEnable(s1_req_isForVSnonLeafPTE, 0.U.asTypeOf(s1_req_isForVSnonLeafPTE), s1_fire) 348 val s2_doubleline = RegEnable(s1_doubleline, 0.U.asTypeOf(s1_doubleline), s1_fire) 349 val s2_exception = RegEnable(s1_exception_out, 0.U.asTypeOf(s1_exception_out), s1_fire) 350 val s2_backendException = RegEnable(s1_backendException, false.B, s1_fire) 351 val s2_pmp_mmio = RegEnable(s1_pmp_mmio, 0.U.asTypeOf(s1_pmp_mmio), s1_fire) 352 val s2_itlb_pbmt = RegEnable(s1_itlb_pbmt, 0.U.asTypeOf(s1_itlb_pbmt), s1_fire) 353 val s2_waymasks = RegEnable(s1_waymasks, 0.U.asTypeOf(s1_waymasks), s1_fire) 354 355 val s2_req_vSetIdx = s2_req_vaddr.map(get_idx) 356 val s2_req_offset = s2_req_vaddr(0)(log2Ceil(blockBytes) - 1, 0) 357 val s2_req_paddr = s2_req_vaddr.zip(s2_req_ptags).map { case (vaddr, ptag) => get_paddr_from_ptag(vaddr, ptag) } 358 359 val s2_SRAMhits = RegEnable(s1_SRAMhits, 0.U.asTypeOf(s1_SRAMhits), s1_fire) 360 val s2_codes = RegEnable(s1_codes, 0.U.asTypeOf(s1_codes), s1_fire) 361 val s2_hits = RegInit(VecInit(Seq.fill(PortNumber)(false.B))) 362 val s2_datas = RegInit(VecInit(Seq.fill(ICacheDataBanks)(0.U((blockBits / ICacheDataBanks).W)))) 363 val s2_data_is_from_MSHR = RegInit(VecInit(Seq.fill(ICacheDataBanks)(false.B))) 364 365 /** 366 ****************************************************************************** 367 * ECC check 368 ****************************************************************************** 369 */ 370 // check data error 371 val s2_bankSel = getBankSel(s2_req_offset, s2_valid) 372 val s2_bank_corrupt = (0 until ICacheDataBanks).map(i => encodeDataECC(s2_datas(i)) =/= s2_codes(i)) 373 // if data is from MSHR, we don't need to check ECC 374 val s2_data_corrupt = VecInit((0 until PortNumber).map(port => 375 (0 until ICacheDataBanks).map(bank => 376 s2_bank_corrupt(bank) && s2_bankSel(port)(bank).asBool && !s2_data_is_from_MSHR(bank) 377 ).reduce(_ || _) && s2_SRAMhits(port) 378 )) 379 // force clear data_corrupt when parity check is disabled 380 when(!csr_parity_enable) { 381 s2_data_corrupt := VecInit(Seq.fill(PortNumber)(false.B)) 382 } 383 // meta error is checked in s1 stage 384 val s2_meta_corrupt = RegEnable(s1_meta_corrupt, 0.U.asTypeOf(s1_meta_corrupt), s1_fire) 385 // send errors to top 386 // TODO: support RERI spec standard interface 387 (0 until PortNumber).map { i => 388 io.errors(i).valid := (s2_meta_corrupt(i) || s2_data_corrupt(i)) && RegNext(s1_fire) 389 io.errors(i).bits.report_to_beu := (s2_meta_corrupt(i) || s2_data_corrupt(i)) && RegNext(s1_fire) 390 io.errors(i).bits.paddr := s2_req_paddr(i) 391 io.errors(i).bits.source := DontCare 392 io.errors(i).bits.source.tag := s2_meta_corrupt(i) 393 io.errors(i).bits.source.data := s2_data_corrupt(i) 394 io.errors(i).bits.source.l2 := false.B 395 io.errors(i).bits.opType := DontCare 396 io.errors(i).bits.opType.fetch := true.B 397 } 398 // flush metaArray to prepare for re-fetch 399 (0 until PortNumber).foreach { i => 400 toMetaFlush(i).valid := (s2_meta_corrupt(i) || s2_data_corrupt(i)) && RegNext(s1_fire) 401 toMetaFlush(i).bits.virIdx := s2_req_vSetIdx(i) 402 // if is meta corrupt, clear all way (since waymask may be unreliable) 403 // if is data corrupt, only clear the way that has error 404 toMetaFlush(i).bits.waymask := Mux(s2_meta_corrupt(i), Fill(nWays, true.B), s2_waymasks(i).asUInt) 405 } 406 // PERF: count the number of data parity errors 407 XSPerfAccumulate("data_corrupt_0", s2_data_corrupt(0) && RegNext(s1_fire)) 408 XSPerfAccumulate("data_corrupt_1", s2_data_corrupt(1) && RegNext(s1_fire)) 409 XSPerfAccumulate("meta_corrupt_0", s2_meta_corrupt(0) && RegNext(s1_fire)) 410 XSPerfAccumulate("meta_corrupt_1", s2_meta_corrupt(1) && RegNext(s1_fire)) 411 // TEST: stop simulation if parity error is detected, and dump wave 412// val (assert_valid, assert_val) = DelayNWithValid(s2_meta_corrupt.reduce(_ || _), s2_valid, 1000) 413// assert(!(assert_valid && assert_val)) 414// val (assert_valid, assert_val) = DelayNWithValid(s2_data_corrupt.reduce(_ || _), s2_valid, 1000) 415// assert(!(assert_valid && assert_val)) 416 417 /** 418 ****************************************************************************** 419 * monitor missUint response port 420 ****************************************************************************** 421 */ 422 val s2_MSHR_match = VecInit((0 until PortNumber).map(i => 423 (s2_req_vSetIdx(i) === fromMSHR.bits.vSetIdx) && 424 (s2_req_ptags(i) === getPhyTagFromBlk(fromMSHR.bits.blkPaddr)) && 425 fromMSHR.valid // we don't care about whether it's corrupt here 426 )) 427 val s2_MSHR_hits = Seq(s2_valid && s2_MSHR_match(0), s2_valid && s2_MSHR_match(1) && s2_doubleline) 428 val s2_MSHR_datas = fromMSHR.bits.data.asTypeOf(Vec(ICacheDataBanks, UInt((blockBits / ICacheDataBanks).W))) 429 430 val s2_bankIdxLow = s2_req_offset >> log2Ceil(blockBytes / ICacheDataBanks) 431 val s2_bankMSHRHit = VecInit((0 until ICacheDataBanks).map(i => 432 ((i.U >= s2_bankIdxLow) && s2_MSHR_hits(0)) || ((i.U < s2_bankIdxLow) && s2_MSHR_hits(1)) 433 )) 434 435 (0 until ICacheDataBanks).foreach { i => 436 when(s1_fire) { 437 s2_datas := s1_datas 438 s2_data_is_from_MSHR := s1_data_is_from_MSHR 439 }.elsewhen(s2_bankMSHRHit(i)) { 440 s2_datas(i) := s2_MSHR_datas(i) 441 // also update s2_data_is_from_MSHR when re-fetched, to clear s2_data_corrupt flag and let s2_fire 442 s2_data_is_from_MSHR(i) := true.B 443 } 444 } 445 446 (0 until PortNumber).foreach { i => 447 when(s1_fire) { 448 s2_hits := s1_hits 449 }.elsewhen(s2_MSHR_hits(i)) { 450 // update s2_hits even if it's corrupt, to let s2_fire 451 s2_hits(i) := true.B 452 // also clear s2_meta_corrupt flag when re-fetched, to let s2_fire 453 s2_meta_corrupt(i) := false.B 454 } 455 } 456 457 val s2_l2_corrupt = RegInit(VecInit(Seq.fill(PortNumber)(false.B))) 458 (0 until PortNumber).foreach { i => 459 when(s1_fire) { 460 s2_l2_corrupt(i) := false.B 461 }.elsewhen(s2_MSHR_hits(i)) { 462 s2_l2_corrupt(i) := fromMSHR.bits.corrupt 463 } 464 } 465 466 /** 467 ****************************************************************************** 468 * send request to MSHR if ICache miss / ECC corrupt 469 ****************************************************************************** 470 */ 471 472 // merge pmp mmio and itlb pbmt 473 val s2_mmio = VecInit((s2_pmp_mmio zip s2_itlb_pbmt).map { case (mmio, pbmt) => 474 mmio || Pbmt.isUncache(pbmt) 475 }) 476 477 // try re-fetch data from L2 cache if ECC error is detected, unless it's from MSHR 478 val s2_corrupt_refetch = (s2_meta_corrupt zip s2_data_corrupt).map { 479 case (meta, data) => meta || data 480 } 481 482 /* s2_exception includes itlb pf/gpf/af, pmp af and meta corruption (af), neither of which should be fetched 483 * mmio should not be fetched, it will be fetched by IFU mmio fsm 484 * also, if previous has exception, latter port should also not be fetched 485 */ 486 val s2_should_fetch = VecInit((0 until PortNumber).map { i => 487 (!s2_hits(i) || s2_corrupt_refetch(i)) && 488 (if (i == 0) true.B else s2_doubleline) && 489 !ExceptionType.hasException(s2_exception.take(i + 1)) && 490 s2_mmio.take(i + 1).map(!_).reduce(_ && _) 491 }) 492 493 val toMSHRArbiter = Module(new Arbiter(new ICacheMissReq, PortNumber)) 494 495 // To avoid sending duplicate requests. 496 val s2_has_send = RegInit(VecInit(Seq.fill(PortNumber)(false.B))) 497 (0 until PortNumber).foreach { i => 498 when(s1_fire) { 499 s2_has_send(i) := false.B 500 }.elsewhen(toMSHRArbiter.io.in(i).fire) { 501 s2_has_send(i) := true.B 502 } 503 } 504 505 (0 until PortNumber).map { i => 506 toMSHRArbiter.io.in(i).valid := s2_valid && s2_should_fetch(i) && !s2_has_send(i) && !s2_flush 507 toMSHRArbiter.io.in(i).bits.blkPaddr := getBlkAddr(s2_req_paddr(i)) 508 toMSHRArbiter.io.in(i).bits.vSetIdx := s2_req_vSetIdx(i) 509 } 510 toMSHR <> toMSHRArbiter.io.out 511 512 XSPerfAccumulate("to_missUnit_stall", toMSHR.valid && !toMSHR.ready) 513 514 val s2_fetch_finish = !s2_should_fetch.reduce(_ || _) 515 516 // also raise af if l2 corrupt is detected 517 val s2_l2_exception = VecInit(s2_l2_corrupt.map(ExceptionType.fromECC(true.B, _))) 518 // NOTE: do NOT raise af if meta/data corrupt is detected, they are automatically recovered by re-fetching from L2 519 520 // merge s2 exceptions, itlb has the highest priority, then l2 521 val s2_exception_out = ExceptionType.merge( 522 s2_exception, // includes itlb/pmp exception 523 s2_l2_exception 524 ) 525 526 /** 527 ****************************************************************************** 528 * response to IFU 529 ****************************************************************************** 530 */ 531 toIFU.valid := s2_fire 532 toIFU.bits.doubleline := s2_doubleline 533 toIFU.bits.data := s2_datas.asTypeOf(UInt(blockBits.W)) 534 toIFU.bits.backendException := s2_backendException 535 (0 until PortNumber).foreach { i => 536 toIFU.bits.vaddr(i) := s2_req_vaddr(i) 537 toIFU.bits.paddr(i) := s2_req_paddr(i) 538 val needThisLine = if (i == 0) true.B else s2_doubleline 539 toIFU.bits.exception(i) := Mux(needThisLine, s2_exception_out(i), ExceptionType.none) 540 toIFU.bits.pmp_mmio(i) := Mux(needThisLine, s2_pmp_mmio(i), false.B) 541 toIFU.bits.itlb_pbmt(i) := Mux(needThisLine, s2_itlb_pbmt(i), Pbmt.pma) 542 } 543 // valid only for the first gpf 544 toIFU.bits.gpaddr := s2_req_gpaddr 545 toIFU.bits.isForVSnonLeafPTE := s2_req_isForVSnonLeafPTE 546 547 s2_flush := io.flush 548 s2_ready := (s2_fetch_finish && !io.respStall) || !s2_valid 549 s2_fire := s2_valid && s2_fetch_finish && !io.respStall && !s2_flush 550 551 /** 552 ****************************************************************************** 553 * report Tilelink corrupt error 554 ****************************************************************************** 555 */ 556 (0 until PortNumber).map { i => 557 when(RegNext(s2_fire && s2_l2_corrupt(i))) { 558 io.errors(i).valid := true.B 559 io.errors(i).bits.report_to_beu := false.B // l2 should have report that to bus error unit, no need to do it again 560 io.errors(i).bits.paddr := RegNext(s2_req_paddr(i)) 561 io.errors(i).bits.source.tag := false.B 562 io.errors(i).bits.source.data := false.B 563 io.errors(i).bits.source.l2 := true.B 564 } 565 } 566 567 /** 568 ****************************************************************************** 569 * performance info. TODO: need to simplify the logic 570 ***********************************************************s******************* 571 */ 572 io.perfInfo.only_0_hit := s2_hits(0) && !s2_doubleline 573 io.perfInfo.only_0_miss := !s2_hits(0) && !s2_doubleline 574 io.perfInfo.hit_0_hit_1 := s2_hits(0) && s2_hits(1) && s2_doubleline 575 io.perfInfo.hit_0_miss_1 := s2_hits(0) && !s2_hits(1) && s2_doubleline 576 io.perfInfo.miss_0_hit_1 := !s2_hits(0) && s2_hits(1) && s2_doubleline 577 io.perfInfo.miss_0_miss_1 := !s2_hits(0) && !s2_hits(1) && s2_doubleline 578 io.perfInfo.hit_0_except_1 := s2_hits(0) && (ExceptionType.hasException(s2_exception(1))) && s2_doubleline 579 io.perfInfo.miss_0_except_1 := !s2_hits(0) && (ExceptionType.hasException(s2_exception(1))) && s2_doubleline 580 io.perfInfo.bank_hit(0) := s2_hits(0) 581 io.perfInfo.bank_hit(1) := s2_hits(1) && s2_doubleline 582 io.perfInfo.except_0 := ExceptionType.hasException(s2_exception(0)) 583 io.perfInfo.hit := s2_hits(0) && (!s2_doubleline || s2_hits(1)) 584 585 /** <PERF> fetch bubble generated by icache miss */ 586 XSPerfAccumulate("icache_bubble_s2_miss", s2_valid && !s2_fetch_finish) 587 XSPerfAccumulate("icache_bubble_s0_wayLookup", s0_valid && !fromWayLookup.ready) 588 589 io.fetch.topdownIcacheMiss := !s2_fetch_finish 590 io.fetch.topdownItlbMiss := s0_valid && !fromWayLookup.ready 591 592 // class ICacheTouchDB(implicit p: Parameters) extends ICacheBundle{ 593 // val blkPaddr = UInt((PAddrBits - blockOffBits).W) 594 // val vSetIdx = UInt(idxBits.W) 595 // val waymask = UInt(log2Ceil(nWays).W) 596 // } 597 598 // val isWriteICacheTouchTable = WireInit(Constantin.createRecord("isWriteICacheTouchTable" + p(XSCoreParamsKey).HartId.toString)) 599 // val ICacheTouchTable = ChiselDB.createTable("ICacheTouchTable" + p(XSCoreParamsKey).HartId.toString, new ICacheTouchDB) 600 601 // val ICacheTouchDumpData = Wire(Vec(PortNumber, new ICacheTouchDB)) 602 // (0 until PortNumber).foreach{ i => 603 // ICacheTouchDumpData(i).blkPaddr := getBlkAddr(s2_req_paddr(i)) 604 // ICacheTouchDumpData(i).vSetIdx := s2_req_vSetIdx(i) 605 // ICacheTouchDumpData(i).waymask := OHToUInt(s2_tag_match_vec(i)) 606 // ICacheTouchTable.log( 607 // data = ICacheTouchDumpData(i), 608 // en = io.touch(i).valid, 609 // site = "req_" + i.toString, 610 // clock = clock, 611 // reset = reset 612 // ) 613 // } 614 615 /** 616 ****************************************************************************** 617 * difftest refill check 618 ****************************************************************************** 619 */ 620 if (env.EnableDifftest) { 621 val discards = (0 until PortNumber).map { i => 622 ExceptionType.hasException(toIFU.bits.exception(i)) || 623 toIFU.bits.pmp_mmio(i) || 624 Pbmt.isUncache(toIFU.bits.itlb_pbmt(i)) 625 } 626 val blkPaddrAll = s2_req_paddr.map(addr => addr(PAddrBits - 1, blockOffBits) << blockOffBits) 627 (0 until ICacheDataBanks).map { i => 628 val diffMainPipeOut = DifftestModule(new DiffRefillEvent, dontCare = true) 629 diffMainPipeOut.coreid := io.hartId 630 diffMainPipeOut.index := (3 + i).U 631 632 val bankSel = getBankSel(s2_req_offset, s2_valid).reduce(_ | _) 633 val lineSel = getLineSel(s2_req_offset) 634 635 diffMainPipeOut.valid := s2_fire && bankSel(i).asBool && Mux(lineSel(i), !discards(1), !discards(0)) 636 diffMainPipeOut.addr := Mux( 637 lineSel(i), 638 blkPaddrAll(1) + (i.U << (log2Ceil(blockBytes / ICacheDataBanks))), 639 blkPaddrAll(0) + (i.U << (log2Ceil(blockBytes / ICacheDataBanks))) 640 ) 641 642 diffMainPipeOut.data := s2_datas(i).asTypeOf(diffMainPipeOut.data) 643 diffMainPipeOut.idtfr := DontCare 644 } 645 } 646} 647