1/*************************************************************************************** 2 * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC) 3 * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 4 * Copyright (c) 2020-2021 Peng Cheng Laboratory 5 * 6 * XiangShan is licensed under Mulan PSL v2. 7 * You can use this software according to the terms and conditions of the Mulan PSL v2. 8 * You may obtain a copy of Mulan PSL v2 at: 9 * http://license.coscl.org.cn/MulanPSL2 10 * 11 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 12 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 13 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14 * 15 * See the Mulan PSL v2 for more details. 16 ***************************************************************************************/ 17package xiangshan.mem 18 19import org.chipsalliance.cde.config._ 20import chisel3._ 21import chisel3.util._ 22import utils._ 23import utility._ 24import xiangshan._ 25import xiangshan.ExceptionNO._ 26import xiangshan.backend.rob.{RobPtr, RobLsqIO} 27import xiangshan.backend.Bundles 28import xiangshan.backend.Bundles.{DynInst, MemExuOutput} 29import xiangshan.backend.fu.FuConfig.LduCfg 30import xiangshan.mem.Bundles._ 31import xiangshan.cache._ 32 33class UncacheEntry(entryIndex: Int)(implicit p: Parameters) extends XSModule 34 with HasCircularQueuePtrHelper 35 with HasLoadHelper 36{ 37 val io = IO(new Bundle() { 38 /* control */ 39 val redirect = Flipped(Valid(new Redirect)) 40 // redirect flush 41 val flush = Output(Bool()) 42 // mmio commit 43 val rob = Flipped(new RobLsqIO) 44 // mmio select 45 val mmioSelect = Output(Bool()) 46 // slaveId 47 val slaveId = ValidIO(UInt(UncacheBufferIndexWidth.W)) 48 49 /* transaction */ 50 // from ldu 51 val req = Flipped(Valid(new LqWriteBundle)) 52 // to ldu: mmio, data 53 val mmioOut = DecoupledIO(new MemExuOutput) 54 val mmioRawData = Output(new LoadDataFromLQBundle) 55 // to ldu: nc with data 56 val ncOut = DecoupledIO(new LsPipelineBundle) 57 // <=> uncache 58 val uncache = new UncacheWordIO 59 // exception generated by outer bus 60 val exception = Valid(new LqWriteBundle) 61 }) 62 63 val req_valid = RegInit(false.B) 64 val req = Reg(new LqWriteBundle) 65 val slaveAccept = RegInit(false.B) 66 val slaveId = Reg(UInt(UncacheBufferIndexWidth.W)) 67 68 val s_idle :: s_req :: s_resp :: s_wait :: Nil = Enum(4) 69 val uncacheState = RegInit(s_idle) 70 val uncacheData = Reg(io.uncache.resp.bits.data.cloneType) 71 val nderr = RegInit(false.B) 72 73 val writeback = Mux(req.nc, io.ncOut.fire, io.mmioOut.fire) 74 val slaveAck = req_valid && io.uncache.idResp.valid && io.uncache.idResp.bits.mid === entryIndex.U 75 76 /** 77 * Flush 78 * 79 * 1. direct flush during idle 80 * 2. otherwise delayed flush until receiving uncache resp 81 */ 82 val needFlushReg = RegInit(false.B) 83 val needFlush = req_valid && req.uop.robIdx.needFlush(io.redirect) 84 val flush = WireInit(false.B) 85 when(flush){ 86 needFlushReg := false.B 87 }.elsewhen(needFlush){ 88 needFlushReg := true.B 89 } 90 91 /* enter req */ 92 when (flush) { 93 req_valid := false.B 94 slaveAccept := false.B 95 } .elsewhen (io.req.valid) { 96 req_valid := true.B 97 slaveAccept := false.B 98 req := io.req.bits 99 nderr := false.B 100 } .elsewhen(slaveAck) { 101 slaveAccept := true.B 102 slaveId := io.uncache.idResp.bits.sid 103 } .elsewhen (writeback) { 104 req_valid := false.B 105 slaveAccept := false.B 106 } 107 XSError(!flush && io.req.valid && req_valid, p"LoadQueueUncache: You can not write an valid entry: $entryIndex") 108 109 /** 110 * Memory mapped IO / NC operations 111 * 112 * States: 113 * (1) s_idle: wait for mmio reaching ROB's head / nc req valid from loadunit 114 * (2) s_req: wait to be sent to uncache channel until req selected and uncache ready 115 * (3) s_resp: wait for response from uncache channel 116 * (4) s_wait: wait for loadunit to receive writeback req 117 */ 118 val pendingld = GatedValidRegNext(io.rob.pendingMMIOld) 119 val pendingPtr = GatedRegNext(io.rob.pendingPtr) 120 val canSendReq = req_valid && !needFlush && Mux( 121 req.nc, true.B, 122 pendingld && req.uop.robIdx === pendingPtr 123 ) 124 switch (uncacheState) { 125 is (s_idle) { 126 when (needFlush) { 127 uncacheState := s_idle 128 flush := true.B 129 }.elsewhen (canSendReq) { 130 uncacheState := s_req 131 } 132 } 133 is (s_req) { 134 when(needFlush){ 135 uncacheState := s_idle 136 flush := true.B 137 }.elsewhen(io.uncache.req.fire) { 138 uncacheState := s_resp 139 } 140 } 141 is (s_resp) { 142 when (io.uncache.resp.fire) { 143 when (needFlush || needFlushReg) { 144 uncacheState := s_idle 145 flush := true.B 146 }.otherwise{ 147 uncacheState := s_wait 148 } 149 } 150 } 151 is (s_wait) { 152 when (needFlush || writeback) { 153 uncacheState := s_idle 154 flush := true.B 155 } 156 } 157 } 158 159 /* control */ 160 io.flush := flush 161 io.rob.mmio := DontCare 162 io.rob.uop := DontCare 163 io.mmioSelect := (uncacheState =/= s_idle) && req.mmio 164 io.slaveId.valid := slaveAccept 165 io.slaveId.bits := slaveId 166 167 /* uncahce req */ 168 io.uncache.req.valid := uncacheState === s_req && !needFlush 169 io.uncache.req.bits := DontCare 170 io.uncache.req.bits.cmd := MemoryOpConstants.M_XRD 171 io.uncache.req.bits.data := DontCare 172 io.uncache.req.bits.addr := req.paddr 173 io.uncache.req.bits.vaddr:= req.vaddr 174 io.uncache.req.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0)) 175 io.uncache.req.bits.id := entryIndex.U 176 io.uncache.req.bits.instrtype := DontCare 177 io.uncache.req.bits.replayCarry := DontCare 178 io.uncache.req.bits.atomic := req.atomic 179 io.uncache.req.bits.nc := req.nc 180 io.uncache.req.bits.memBackTypeMM := req.memBackTypeMM 181 182 io.uncache.resp.ready := true.B 183 184 /* uncahce resp */ 185 when (io.uncache.resp.fire) { 186 uncacheData := io.uncache.resp.bits.data 187 nderr := io.uncache.resp.bits.nderr 188 } 189 190 /* uncahce writeback */ 191 val selUop = req.uop 192 val func = selUop.fuOpType 193 val raddr = req.paddr 194 val rdataSel = LookupTree(raddr(2, 0), List( 195 "b000".U -> uncacheData(63, 0), 196 "b001".U -> uncacheData(63, 8), 197 "b010".U -> uncacheData(63, 16), 198 "b011".U -> uncacheData(63, 24), 199 "b100".U -> uncacheData(63, 32), 200 "b101".U -> uncacheData(63, 40), 201 "b110".U -> uncacheData(63, 48), 202 "b111".U -> uncacheData(63, 56) 203 )) 204 val rdataPartialLoad = rdataHelper(selUop, rdataSel) 205 206 io.mmioOut.valid := false.B 207 io.mmioOut.bits := DontCare 208 io.mmioRawData := DontCare 209 io.ncOut.valid := false.B 210 io.ncOut.bits := DontCare 211 212 when(req.nc){ 213 io.ncOut.valid := (uncacheState === s_wait) && !needFlush 214 io.ncOut.bits := DontCare 215 io.ncOut.bits.uop := selUop 216 io.ncOut.bits.uop.lqIdx := req.uop.lqIdx 217 io.ncOut.bits.uop.exceptionVec(loadAccessFault) := nderr 218 io.ncOut.bits.data := rdataPartialLoad 219 io.ncOut.bits.paddr := req.paddr 220 io.ncOut.bits.vaddr := req.vaddr 221 io.ncOut.bits.nc := true.B 222 io.ncOut.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0)) 223 io.ncOut.bits.schedIndex := req.schedIndex 224 io.ncOut.bits.isvec := req.isvec 225 io.ncOut.bits.is128bit := req.is128bit 226 io.ncOut.bits.vecActive := req.vecActive 227 }.otherwise{ 228 io.mmioOut.valid := (uncacheState === s_wait) && !needFlush 229 io.mmioOut.bits := DontCare 230 io.mmioOut.bits.uop := selUop 231 io.mmioOut.bits.uop.lqIdx := req.uop.lqIdx 232 io.mmioOut.bits.uop.exceptionVec(loadAccessFault) := nderr 233 io.mmioOut.bits.data := rdataPartialLoad 234 io.mmioOut.bits.debug.isMMIO := true.B 235 io.mmioOut.bits.debug.isNC := false.B 236 io.mmioOut.bits.debug.paddr := req.paddr 237 io.mmioOut.bits.debug.vaddr := req.vaddr 238 io.mmioRawData.lqData := uncacheData 239 io.mmioRawData.uop := req.uop 240 io.mmioRawData.addrOffset := req.paddr 241 } 242 243 io.exception.valid := writeback 244 io.exception.bits := req 245 io.exception.bits.uop.exceptionVec(loadAccessFault) := nderr 246 247 /* debug log */ 248 XSDebug(io.uncache.req.fire, 249 "uncache req: pc %x addr %x data %x op %x mask %x\n", 250 req.uop.pc, 251 io.uncache.req.bits.addr, 252 io.uncache.req.bits.data, 253 io.uncache.req.bits.cmd, 254 io.uncache.req.bits.mask 255 ) 256 XSInfo(io.ncOut.fire, 257 "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n", 258 io.ncOut.bits.uop.robIdx.asUInt, 259 io.ncOut.bits.uop.lqIdx.asUInt, 260 io.ncOut.bits.uop.pc, 261 true.B 262 ) 263 XSInfo(io.mmioOut.fire, 264 "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n", 265 io.mmioOut.bits.uop.robIdx.asUInt, 266 io.mmioOut.bits.uop.lqIdx.asUInt, 267 io.mmioOut.bits.uop.pc, 268 true.B 269 ) 270 271} 272 273class LoadQueueUncache(implicit p: Parameters) extends XSModule 274 with HasCircularQueuePtrHelper 275 with HasMemBlockParameters 276{ 277 val io = IO(new Bundle() { 278 /* control */ 279 val redirect = Flipped(Valid(new Redirect)) 280 // mmio commit 281 val rob = Flipped(new RobLsqIO) 282 283 /* transaction */ 284 // enqueue: from ldu s3 285 val req = Vec(LoadPipelineWidth, Flipped(Decoupled(new LqWriteBundle))) 286 // writeback: mmio to ldu s0, s3 287 val mmioOut = Vec(LoadPipelineWidth, DecoupledIO(new MemExuOutput)) 288 val mmioRawData = Vec(LoadPipelineWidth, Output(new LoadDataFromLQBundle)) 289 // writeback: nc to ldu s0--s3 290 val ncOut = Vec(LoadPipelineWidth, Decoupled(new LsPipelineBundle)) 291 // <=>uncache 292 val uncache = new UncacheWordIO 293 294 /* except */ 295 // rollback from frontend when buffer is full 296 val rollback = Output(Valid(new Redirect)) 297 // exception generated by outer bus 298 val exception = Valid(new LqWriteBundle) 299 }) 300 301 /****************************************************************** 302 * Structure 303 ******************************************************************/ 304 val entries = Seq.tabulate(LoadUncacheBufferSize)(i => Module(new UncacheEntry(i))) 305 306 val freeList = Module(new FreeList( 307 size = LoadUncacheBufferSize, 308 allocWidth = LoadPipelineWidth, 309 freeWidth = 4, 310 enablePreAlloc = true, 311 moduleName = "LoadQueueUncache freelist" 312 )) 313 freeList.io := DontCare 314 315 // set default IO 316 entries.foreach { 317 case (e) => 318 e.io.req.valid := false.B 319 e.io.req.bits := DontCare 320 e.io.uncache.req.ready := false.B 321 e.io.uncache.idResp.valid := false.B 322 e.io.uncache.idResp.bits := DontCare 323 e.io.uncache.resp.valid := false.B 324 e.io.uncache.resp.bits := DontCare 325 e.io.ncOut.ready := false.B 326 e.io.mmioOut.ready := false.B 327 } 328 io.uncache.req.valid := false.B 329 io.uncache.req.bits := DontCare 330 io.uncache.resp.ready := false.B 331 for (w <- 0 until LoadPipelineWidth) { 332 io.mmioOut(w).valid := false.B 333 io.mmioOut(w).bits := DontCare 334 io.mmioRawData(w) := DontCare 335 io.ncOut(w).valid := false.B 336 io.ncOut(w).bits := DontCare 337 } 338 339 340 /****************************************************************** 341 * Enqueue 342 * 343 * s1: hold 344 * s2: confirm enqueue and write entry 345 * valid: no redirect, no exception, no replay, is mmio/nc 346 * ready: freelist can allocate 347 ******************************************************************/ 348 349 val s1_sortedVec = HwSort(VecInit(io.req.map { case x => DataWithPtr(x.valid, x.bits, x.bits.uop.robIdx) })) 350 val s1_req = VecInit(s1_sortedVec.map(_.bits)) 351 val s1_valid = VecInit(s1_sortedVec.map(_.valid)) 352 val s2_enqueue = Wire(Vec(LoadPipelineWidth, Bool())) 353 io.req.zipWithIndex.foreach{ case (r, i) => 354 r.ready := true.B 355 } 356 357 // s2: enqueue 358 val s2_req = (0 until LoadPipelineWidth).map(i => {RegEnable(s1_req(i), s1_valid(i))}) 359 val s2_valid = (0 until LoadPipelineWidth).map(i => { 360 RegNext(s1_valid(i)) && 361 !s2_req(i).uop.robIdx.needFlush(RegNext(io.redirect)) && 362 !s2_req(i).uop.robIdx.needFlush(io.redirect) 363 }) 364 val s2_has_exception = s2_req.map(x => ExceptionNO.selectByFu(x.uop.exceptionVec, LduCfg).asUInt.orR) 365 val s2_need_replay = s2_req.map(_.rep_info.need_rep) 366 367 for (w <- 0 until LoadPipelineWidth) { 368 s2_enqueue(w) := s2_valid(w) && !s2_has_exception(w) && !s2_need_replay(w) && (s2_req(w).mmio || s2_req(w).nc) 369 } 370 371 val s2_enqValidVec = Wire(Vec(LoadPipelineWidth, Bool())) 372 val s2_enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt())) 373 374 for (w <- 0 until LoadPipelineWidth) { 375 freeList.io.allocateReq(w) := true.B 376 } 377 378 // freeList real-allocate 379 for (w <- 0 until LoadPipelineWidth) { 380 freeList.io.doAllocate(w) := s2_enqValidVec(w) 381 } 382 383 for (w <- 0 until LoadPipelineWidth) { 384 val offset = PopCount(s2_enqueue.take(w)) 385 s2_enqValidVec(w) := s2_enqueue(w) && freeList.io.canAllocate(offset) 386 s2_enqIndexVec(w) := freeList.io.allocateSlot(offset) 387 } 388 389 390 /****************************************************************** 391 * Uncache Transaction 392 * 393 * 1. uncache req 394 * 2. uncache resp 395 * 3. writeback 396 ******************************************************************/ 397 private val NC_WB_MOD = NCWBPorts.length 398 399 val uncacheReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType)) 400 val mmioSelect = entries.map(e => e.io.mmioSelect).reduce(_ || _) 401 val mmioReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType)) 402 // TODO lyq: It's best to choose in robIdx order / the order in which they enter 403 val ncReqArb = Module(new RRArbiterInit(io.uncache.req.bits.cloneType, LoadUncacheBufferSize)) 404 405 val mmioOut = Wire(DecoupledIO(io.mmioOut(0).bits.cloneType)) 406 val mmioRawData = Wire(io.mmioRawData(0).cloneType) 407 val ncOut = Wire(chiselTypeOf(io.ncOut)) 408 val ncOutValidVec = VecInit(entries.map(e => e.io.ncOut.valid)) 409 val ncOutValidVecRem = SubVec.getMaskRem(ncOutValidVec, NC_WB_MOD) 410 411 // init 412 uncacheReq.valid := false.B 413 uncacheReq.bits := DontCare 414 mmioReq.valid := false.B 415 mmioReq.bits := DontCare 416 mmioOut.valid := false.B 417 mmioOut.bits := DontCare 418 mmioRawData := DontCare 419 for (i <- 0 until LoadUncacheBufferSize) { 420 ncReqArb.io.in(i).valid := false.B 421 ncReqArb.io.in(i).bits := DontCare 422 } 423 for (i <- 0 until LoadPipelineWidth) { 424 ncOut(i).valid := false.B 425 ncOut(i).bits := DontCare 426 } 427 428 entries.zipWithIndex.foreach { 429 case (e, i) => 430 // enqueue 431 for (w <- 0 until LoadPipelineWidth) { 432 when (s2_enqValidVec(w) && (i.U === s2_enqIndexVec(w))) { 433 e.io.req.valid := true.B 434 e.io.req.bits := s2_req(w) 435 } 436 } 437 438 // control 439 e.io.redirect <> io.redirect 440 e.io.rob <> io.rob 441 442 // uncache req, writeback 443 when (e.io.mmioSelect) { 444 mmioReq.valid := e.io.uncache.req.valid 445 mmioReq.bits := e.io.uncache.req.bits 446 e.io.uncache.req.ready := mmioReq.ready 447 448 e.io.mmioOut.ready := mmioOut.ready 449 mmioOut.valid := e.io.mmioOut.valid 450 mmioOut.bits := e.io.mmioOut.bits 451 mmioRawData := e.io.mmioRawData 452 453 }.otherwise{ 454 ncReqArb.io.in(i).valid := e.io.uncache.req.valid 455 ncReqArb.io.in(i).bits := e.io.uncache.req.bits 456 e.io.uncache.req.ready := ncReqArb.io.in(i).ready 457 458 (0 until NC_WB_MOD).map { w => 459 val (idx, ncOutValid) = PriorityEncoderWithFlag(ncOutValidVecRem(w)) 460 val port = NCWBPorts(w) 461 when((i.U === idx) && ncOutValid) { 462 ncOut(port).valid := ncOutValid 463 ncOut(port).bits := e.io.ncOut.bits 464 e.io.ncOut.ready := ncOut(port).ready 465 } 466 } 467 468 } 469 470 // uncache idResp 471 when(i.U === io.uncache.idResp.bits.mid) { 472 e.io.uncache.idResp <> io.uncache.idResp 473 } 474 475 // uncache resp 476 when (e.io.slaveId.valid && e.io.slaveId.bits === io.uncache.resp.bits.id) { 477 e.io.uncache.resp <> io.uncache.resp 478 } 479 480 } 481 482 mmioReq.ready := false.B 483 ncReqArb.io.out.ready := false.B 484 when(mmioSelect){ 485 uncacheReq <> mmioReq 486 }.otherwise{ 487 uncacheReq <> ncReqArb.io.out 488 } 489 490 // uncache Request 491 AddPipelineReg(uncacheReq, io.uncache.req, false.B) 492 493 // uncache Writeback 494 AddPipelineReg(mmioOut, io.mmioOut(UncacheWBPort), false.B) 495 io.mmioRawData(UncacheWBPort) := RegEnable(mmioRawData, mmioOut.fire) 496 497 (0 until LoadPipelineWidth).foreach { i => AddPipelineReg(ncOut(i), io.ncOut(i), false.B) } 498 499 // uncache exception 500 io.exception.valid := Cat(entries.map(_.io.exception.valid)).orR 501 io.exception.bits := ParallelPriorityMux(entries.map(e => 502 (e.io.exception.valid, e.io.exception.bits) 503 )) 504 505 // rob 506 for (i <- 0 until LoadPipelineWidth) { 507 io.rob.mmio(i) := RegNext(s1_valid(i) && s1_req(i).mmio) 508 io.rob.uop(i) := RegEnable(s1_req(i).uop, s1_valid(i)) 509 } 510 511 512 /****************************************************************** 513 * Deallocate 514 ******************************************************************/ 515 // UncacheBuffer deallocate 516 val freeMaskVec = Wire(Vec(LoadUncacheBufferSize, Bool())) 517 518 // init 519 freeMaskVec.map(e => e := false.B) 520 521 // dealloc logic 522 entries.zipWithIndex.foreach { 523 case (e, i) => 524 when ((e.io.mmioSelect && e.io.mmioOut.fire) || e.io.ncOut.fire || e.io.flush) { 525 freeMaskVec(i) := true.B 526 } 527 } 528 529 freeList.io.free := freeMaskVec.asUInt 530 531 532 /****************************************************************** 533 * Uncache rollback detection 534 * 535 * When uncache loads enqueue, it searches uncache loads, They can not enqueue and need re-execution. 536 * 537 * Cycle 0: uncache enqueue. 538 * Cycle 1: Select oldest uncache loads. 539 * Cycle 2: Redirect Fire. 540 * Choose the oldest load from LoadPipelineWidth oldest loads. 541 * Prepare redirect request according to the detected rejection. 542 * Fire redirect request (if valid) 543 * 544 * Load_S3 .... Load_S3 545 * stage 0: lq lq 546 * | | (can not enqueue) 547 * stage 1: lq lq 548 * | | 549 * --------------- 550 * | 551 * stage 2: lq 552 * | 553 * rollback req 554 * 555 ******************************************************************/ 556 def selectOldestRedirect(xs: Seq[Valid[Redirect]]): Vec[Bool] = { 557 val compareVec = (0 until xs.length).map(i => (0 until i).map(j => isAfter(xs(j).bits.robIdx, xs(i).bits.robIdx))) 558 val resultOnehot = VecInit((0 until xs.length).map(i => Cat((0 until xs.length).map(j => 559 (if (j < i) !xs(j).valid || compareVec(i)(j) 560 else if (j == i) xs(i).valid 561 else !xs(j).valid || !compareVec(j)(i)) 562 )).andR)) 563 resultOnehot 564 } 565 val reqNeedCheck = VecInit((0 until LoadPipelineWidth).map(w => 566 s2_enqueue(w) && !s2_enqValidVec(w) 567 )) 568 val reqSelUops = VecInit(s2_req.map(_.uop)) 569 val allRedirect = (0 until LoadPipelineWidth).map(i => { 570 val redirect = Wire(Valid(new Redirect)) 571 redirect.valid := reqNeedCheck(i) 572 redirect.bits := DontCare 573 redirect.bits.isRVC := reqSelUops(i).preDecodeInfo.isRVC 574 redirect.bits.robIdx := reqSelUops(i).robIdx 575 redirect.bits.ftqIdx := reqSelUops(i).ftqPtr 576 redirect.bits.ftqOffset := reqSelUops(i).ftqOffset 577 redirect.bits.level := RedirectLevel.flush 578 redirect.bits.cfiUpdate.target := reqSelUops(i).pc // TODO: check if need pc 579 redirect.bits.debug_runahead_checkpoint_id := reqSelUops(i).debugInfo.runahead_checkpoint_id 580 redirect 581 }) 582 val oldestOneHot = selectOldestRedirect(allRedirect) 583 val oldestRedirect = Mux1H(oldestOneHot, allRedirect) 584 val lastCycleRedirect = Wire(Valid(new Redirect)) 585 lastCycleRedirect.valid := RegNext(io.redirect.valid) 586 lastCycleRedirect.bits := RegEnable(io.redirect.bits, io.redirect.valid) 587 val lastLastCycleRedirect = Wire(Valid(new Redirect)) 588 lastLastCycleRedirect.valid := RegNext(lastCycleRedirect.valid) 589 lastLastCycleRedirect.bits := RegEnable(lastCycleRedirect.bits, lastCycleRedirect.valid) 590 io.rollback.valid := GatedValidRegNext(oldestRedirect.valid && 591 !oldestRedirect.bits.robIdx.needFlush(io.redirect) && 592 !oldestRedirect.bits.robIdx.needFlush(lastCycleRedirect) && 593 !oldestRedirect.bits.robIdx.needFlush(lastLastCycleRedirect)) 594 io.rollback.bits := RegEnable(oldestRedirect.bits, oldestRedirect.valid) 595 596 597 /****************************************************************** 598 * Perf Counter 599 ******************************************************************/ 600 val validCount = freeList.io.validCount 601 val allowEnqueue = !freeList.io.empty 602 QueuePerf(LoadUncacheBufferSize, validCount, !allowEnqueue) 603 604 XSPerfAccumulate("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc) 605 XSPerfAccumulate("mmio_writeback_success", io.mmioOut(0).fire) 606 XSPerfAccumulate("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready) 607 XSPerfAccumulate("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc) 608 XSPerfAccumulate("nc_writeback_success", io.ncOut(0).fire) 609 XSPerfAccumulate("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready) 610 XSPerfAccumulate("uncache_full_rollback", io.rollback.valid) 611 612 val perfEvents: Seq[(String, UInt)] = Seq( 613 ("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc), 614 ("mmio_writeback_success", io.mmioOut(0).fire), 615 ("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready), 616 ("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc), 617 ("nc_writeback_success", io.ncOut(0).fire), 618 ("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready), 619 ("uncache_full_rollback", io.rollback.valid) 620 ) 621 // end 622} 623