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.cache 18 19import chipsalliance.rocketchip.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import freechips.rocketchip.tilelink.TLPermissions._ 23import freechips.rocketchip.tilelink.{TLArbiter, TLBundleC, TLBundleD, TLEdgeOut} 24import huancun.DirtyKey 25import utils.{HasPerfEvents, HasTLDump, XSDebug, XSPerfAccumulate} 26 27class WritebackReqWodata(implicit p: Parameters) extends DCacheBundle { 28 val addr = UInt(PAddrBits.W) 29 val addr_dup_0 = UInt(PAddrBits.W) 30 val addr_dup_1 = UInt(PAddrBits.W) 31 val param = UInt(cWidth.W) 32 val voluntary = Bool() 33 val hasData = Bool() 34 val dirty = Bool() 35 36 val delay_release = Bool() 37 val miss_id = UInt(log2Up(cfg.nMissEntries).W) 38 39 def dump() = { 40 XSDebug("WritebackReq addr: %x param: %d voluntary: %b hasData: %b\n", 41 addr, param, voluntary, hasData) 42 } 43} 44 45class WritebackReqData(implicit p: Parameters) extends DCacheBundle { 46 val data = UInt((cfg.blockBytes * 8).W) 47} 48 49class WritebackReq(implicit p: Parameters) extends WritebackReqWodata { 50 val data = UInt((cfg.blockBytes * 8).W) 51 52 override def dump() = { 53 XSDebug("WritebackReq addr: %x param: %d voluntary: %b hasData: %b data: %x\n", 54 addr, param, voluntary, hasData, data) 55 } 56 57 def toWritebackReqWodata(): WritebackReqWodata = { 58 val out = Wire(new WritebackReqWodata) 59 out.addr := addr 60 out.addr_dup_0 := addr_dup_0 61 out.addr_dup_1 := addr_dup_1 62 out.param := param 63 out.voluntary := voluntary 64 out.hasData := hasData 65 out.dirty := dirty 66 out.delay_release := delay_release 67 out.miss_id := miss_id 68 out 69 } 70 71 def toWritebackReqData(): WritebackReqData = { 72 val out = Wire(new WritebackReqData) 73 out.data := data 74 out 75 } 76} 77 78// While a Release sleeps and waits for a refill to wake it up, 79// main pipe might update meta & data during this time. 80// So the meta & data to be released need to be updated too. 81class ReleaseUpdate(implicit p: Parameters) extends DCacheBundle { 82 // only consider store here 83 val addr = UInt(PAddrBits.W) 84 val mask = UInt(DCacheBanks.W) 85 val data = UInt((cfg.blockBytes * 8).W) 86} 87 88// To reduce fanout, miss queue entry data is updated 1 cycle 89// after ReleaseUpdate.fire() 90class MissQueueEntryReleaseUpdate(implicit p: Parameters) extends DCacheBundle { 91 // only consider store here 92 val addr = UInt(PAddrBits.W) 93 val mask_delayed = UInt(DCacheBanks.W) 94 val data_delayed = UInt((cfg.blockBytes * 8).W) 95 val mask_orr = Bool() 96} 97 98class WritebackEntry(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule with HasTLDump 99{ 100 val io = IO(new Bundle { 101 val id = Input(UInt()) 102 // allocate this entry for new req 103 val primary_valid = Input(Bool()) 104 // this entry is free and can be allocated to new reqs 105 val primary_ready = Output(Bool()) 106 val primary_ready_dup = Vec(4, Output(Bool())) 107 // this entry is busy, but it can merge the new req 108 val secondary_valid = Input(Bool()) 109 val secondary_ready = Output(Bool()) 110 val req = Flipped(DecoupledIO(new WritebackReqWodata)) 111 val req_data = Input(new WritebackReqData) 112 113 val mem_release = DecoupledIO(new TLBundleC(edge.bundle)) 114 val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 115 116 val block_addr = Output(Valid(UInt())) 117 118 val release_wakeup = Flipped(ValidIO(UInt(log2Up(cfg.nMissEntries).W))) 119 val release_update = Flipped(ValidIO(new MissQueueEntryReleaseUpdate)) 120 }) 121 122 val s_invalid :: s_sleep :: s_release_req :: s_release_resp :: Nil = Enum(4) 123 // ProbeAck: s_invalid -> s_release_req 124 // ProbeAck merge Release: s_invalid -> s_release_req 125 // Release: s_invalid -> s_sleep -> s_release_req -> s_release_resp 126 // Release merge ProbeAck: s_invalid -> s_sleep -> s_release_req 127 // (change Release into ProbeAck when Release is not fired) 128 // or: s_invalid -> s_sleep -> s_release_req -> s_release_resp -> s_release_req 129 // (send a ProbeAck after Release transaction is over) 130 val state = RegInit(s_invalid) 131 val state_dup_0 = RegInit(s_invalid) 132 val state_dup_1 = RegInit(s_invalid) 133 val state_dup_for_mp = RegInit(VecInit(Seq.fill(4)(s_invalid))) 134 135 // internal regs 136 // remaining beats 137 val remain = RegInit(0.U(refillCycles.W)) 138 val remain_dup_0 = RegInit(0.U(refillCycles.W)) 139 val remain_dup_1 = RegInit(0.U(refillCycles.W)) 140 val remain_set = WireInit(0.U(refillCycles.W)) 141 val remain_clr = WireInit(0.U(refillCycles.W)) 142 remain := (remain | remain_set) & ~remain_clr 143 remain_dup_0 := (remain_dup_0 | remain_set) & ~remain_clr 144 remain_dup_1 := (remain_dup_1 | remain_set) & ~remain_clr 145 146 // writeback queue data 147 val data = Reg(UInt((cfg.blockBytes * 8).W)) 148 149 // pending data write 150 // !s_data_override means there is an in-progress data write 151 val s_data_override = RegInit(true.B) 152 // !s_data_merge means there is an in-progress data merge 153 val s_data_merge = RegInit(true.B) 154 155 // there are valid request that can be sent to release bus 156 val busy = remain.orR && s_data_override && s_data_merge // have remain beats and data write finished 157 158 val req = Reg(new WritebackReqWodata) 159 160 // assign default signals to output signals 161 io.req.ready := false.B 162 io.mem_release.valid := false.B 163 io.mem_release.bits := DontCare 164 io.mem_grant.ready := false.B 165 io.block_addr.valid := state =/= s_invalid 166 io.block_addr.bits := req.addr 167 168 s_data_override := true.B // data_override takes only 1 cycle 169 s_data_merge := true.B // data_merge takes only 1 cycle 170 171 172 when (state =/= s_invalid) { 173 XSDebug("WritebackEntry: %d state: %d block_addr: %x\n", io.id, state, io.block_addr.bits) 174 } 175 176 def mergeData(old_data: UInt, new_data: UInt, wmask: UInt): UInt = { 177 val full_wmask = FillInterleaved(64, wmask) 178 (~full_wmask & old_data | full_wmask & new_data) 179 } 180 181 // -------------------------------------------------------------------------------- 182 // s_invalid: receive requests 183 // new req entering 184 when (io.req.valid && io.primary_valid && io.primary_ready) { 185 assert (remain === 0.U) 186 req := io.req.bits 187 s_data_override := false.B 188 when (io.req.bits.delay_release) { 189 state := s_sleep 190 state_dup_0 := s_sleep 191 state_dup_1 := s_sleep 192 state_dup_for_mp.foreach(_ := s_sleep) 193 }.otherwise { 194 state := s_release_req 195 state_dup_0 := s_release_req 196 state_dup_1 := s_release_req 197 state_dup_for_mp.foreach(_ := s_release_req) 198 remain_set := Mux(io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W)) 199 } 200 } 201 202 // -------------------------------------------------------------------------------- 203 // s_sleep: wait for refill pipe to inform me that I can keep releasing 204 val merge = io.secondary_valid && io.secondary_ready 205 when (state === s_sleep) { 206 assert(remain === 0.U) 207 // There shouldn't be a new Release with the same addr in sleep state 208 assert(!(merge && io.req.bits.voluntary)) 209 210 val update = io.release_update.valid && io.release_update.bits.addr === req.addr 211 when (update) { 212 req.hasData := req.hasData || io.release_update.bits.mask_orr 213 req.dirty := req.dirty || io.release_update.bits.mask_orr 214 s_data_merge := false.B 215 }.elsewhen (merge) { 216 state := s_release_req 217 state_dup_0 := s_release_req 218 state_dup_1 := s_release_req 219 state_dup_for_mp.foreach(_ := s_release_req) 220 req.voluntary := false.B 221 req.param := req.param 222 req.hasData := req.hasData || io.req.bits.hasData 223 req.dirty := req.dirty || io.req.bits.dirty 224 s_data_override := !io.req.bits.hasData // update data when io.req.bits.hasData 225 req.delay_release := false.B 226 remain_set := Mux(req.hasData || io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W)) 227 } 228 229 when (io.release_wakeup.valid && io.release_wakeup.bits === req.miss_id) { 230 state := s_release_req 231 state_dup_0 := s_release_req 232 state_dup_1 := s_release_req 233 state_dup_for_mp.foreach(_ := s_release_req) 234 req.delay_release := false.B 235 remain_set := Mux( 236 req.hasData || update && io.release_update.bits.mask_orr || merge && io.req.bits.hasData, 237 ~0.U(refillCycles.W), 238 1.U(refillCycles.W) 239 ) 240 } 241 } 242 243 // -------------------------------------------------------------------------------- 244 // while there beats remaining to be sent, we keep sending 245 // which beat to send in this cycle? 246 val beat = PriorityEncoder(remain_dup_0) 247 248 val beat_data = Wire(Vec(refillCycles, UInt(beatBits.W))) 249 for (i <- 0 until refillCycles) { 250 beat_data(i) := data((i + 1) * beatBits - 1, i * beatBits) 251 } 252 253 val probeResponse = edge.ProbeAck( 254 fromSource = io.id, 255 toAddress = req.addr_dup_0, 256 lgSize = log2Ceil(cfg.blockBytes).U, 257 reportPermissions = req.param 258 ) 259 260 val probeResponseData = edge.ProbeAck( 261 fromSource = io.id, 262 toAddress = req.addr_dup_0, 263 lgSize = log2Ceil(cfg.blockBytes).U, 264 reportPermissions = req.param, 265 data = beat_data(beat) 266 ) 267 268 val voluntaryRelease = edge.Release( 269 fromSource = io.id, 270 toAddress = req.addr_dup_1, 271 lgSize = log2Ceil(cfg.blockBytes).U, 272 shrinkPermissions = req.param 273 )._2 274 275 val voluntaryReleaseData = edge.Release( 276 fromSource = io.id, 277 toAddress = req.addr_dup_1, 278 lgSize = log2Ceil(cfg.blockBytes).U, 279 shrinkPermissions = req.param, 280 data = beat_data(beat) 281 )._2 282 283 voluntaryReleaseData.echo.lift(DirtyKey).foreach(_ := req.dirty) 284 when(busy) { 285 assert(!req.dirty || req.hasData) 286 } 287 288 io.mem_release.valid := busy 289 io.mem_release.bits := Mux(req.voluntary, 290 Mux(req.hasData, voluntaryReleaseData, voluntaryRelease), 291 Mux(req.hasData, probeResponseData, probeResponse)) 292 293 when (io.mem_release.fire()) { remain_clr := PriorityEncoderOH(remain_dup_1) } 294 295 val (_, _, release_done, _) = edge.count(io.mem_release) 296 297// when (state === s_release_req && release_done) { 298// state := Mux(req.voluntary, s_release_resp, s_invalid) 299// } 300 301 // Because now wbq merges a same-addr req unconditionally, when the req to be merged comes too late, 302 // the previous req might not be able to merge. Thus we have to handle the new req later after the 303 // previous one finishes. 304 // TODO: initiate these 305 val release_later = RegInit(false.B) 306 val c_already_sent = RegInit(false.B) 307 def tmp_req() = new Bundle { 308 val param = UInt(cWidth.W) 309 val voluntary = Bool() 310 val hasData = Bool() 311 val dirty = Bool() 312 val delay_release = Bool() 313 val miss_id = UInt(log2Up(cfg.nMissEntries).W) 314 315 def toWritebackReq = { 316 val r = Wire(new WritebackReq()) 317 r.data := data 318 r.addr := req.addr 319 r.addr_dup_0 := req.addr_dup_0 320 r.addr_dup_1 := req.addr_dup_1 321 r.param := param 322 r.voluntary := voluntary 323 r.hasData := hasData 324 r.dirty := dirty 325 r.delay_release := delay_release 326 r.miss_id := miss_id 327 r 328 } 329 } 330 val req_later = Reg(tmp_req()) 331 332 when (state_dup_0 === s_release_req) { 333 when (io.mem_release.fire()) { 334 c_already_sent := !release_done 335 } 336 337 when (req.voluntary) { 338 // The previous req is Release 339 when (release_done) { 340 state := s_release_resp 341 state_dup_0 := s_release_resp 342 state_dup_1 := s_release_resp 343 state_dup_for_mp.foreach(_ := s_release_resp) 344 } 345 // merge a ProbeAck 346 when (merge) { 347 when (io.mem_release.fire() || c_already_sent) { 348 // too late to merge, handle the ProbeAck later 349 release_later := true.B 350 req_later.param := io.req.bits.param 351 req_later.voluntary := io.req.bits.voluntary 352 req_later.hasData := io.req.bits.hasData 353 req_later.dirty := io.req.bits.dirty 354 req_later.delay_release := io.req.bits.delay_release 355 req_later.miss_id := io.req.bits.miss_id 356 }.otherwise { 357 // Release hasn't been sent out yet, change Release to ProbeAck 358 req.voluntary := false.B 359 req.hasData := req.hasData || io.req.bits.hasData 360 req.dirty := req.dirty || io.req.bits.dirty 361 // s_data_override := false.B 362 req.delay_release := false.B 363 remain_set := Mux(req.hasData || io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W)) 364 } 365 } 366 }.otherwise { 367 // The previous req is ProbeAck 368 when (merge) { 369 release_later := true.B 370 req_later.param := io.req.bits.param 371 req_later.voluntary := io.req.bits.voluntary 372 req_later.hasData := io.req.bits.hasData 373 req_later.dirty := io.req.bits.dirty 374 req_later.delay_release := io.req.bits.delay_release 375 req_later.miss_id := io.req.bits.miss_id 376 } 377 378 when (release_done) { 379 when (merge) { 380 // Send the Release after ProbeAck 381// state := s_release_req 382// req := Mux(merge, io.req.bits, req_later.toWritebackReq) 383// release_later := false.B 384 state := s_sleep 385 state_dup_0 := s_sleep 386 state_dup_1 := s_sleep 387 state_dup_for_mp.foreach(_ := s_sleep) 388 req := io.req.bits 389 release_later := false.B 390 }.elsewhen (release_later) { 391 state := Mux( 392 io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id || !req_later.delay_release, 393 s_release_req, 394 s_sleep 395 ) 396 state_dup_0 := Mux( 397 io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id || !req_later.delay_release, 398 s_release_req, 399 s_sleep 400 ) 401 state_dup_1 := Mux( 402 io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id || !req_later.delay_release, 403 s_release_req, 404 s_sleep 405 ) 406 state_dup_for_mp.foreach(_ := Mux( 407 io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id || !req_later.delay_release, 408 s_release_req, 409 s_sleep 410 )) 411 req := req_later.toWritebackReq 412 when (io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id) { 413 req.delay_release := false.B 414 } 415 release_later := false.B 416 }.otherwise { 417 state := s_invalid 418 state_dup_0 := s_invalid 419 state_dup_1 := s_invalid 420 state_dup_for_mp.foreach(_ := s_invalid) 421 release_later := false.B 422 } 423 } 424 425 when (io.release_wakeup.valid && io.release_wakeup.bits === req_later.miss_id) { 426 req_later.delay_release := false.B 427 } 428 } 429 } 430 431 // -------------------------------------------------------------------------------- 432 // receive ReleaseAck for Releases 433 when (state_dup_0 === s_release_resp) { 434 io.mem_grant.ready := true.B 435 436 when (merge) { 437 release_later := true.B 438 req_later.param := io.req.bits.param 439 req_later.voluntary := io.req.bits.voluntary 440 req_later.hasData := io.req.bits.hasData 441 req_later.dirty := io.req.bits.dirty 442 req_later.delay_release := io.req.bits.delay_release 443 req_later.miss_id := io.req.bits.miss_id 444 } 445 when (io.mem_grant.fire()) { 446 when (merge) { 447 state := s_release_req 448 state_dup_0 := s_release_req 449 state_dup_1 := s_release_req 450 state_dup_for_mp.foreach(_ := s_release_req) 451 req := io.req.bits 452 remain_set := Mux(io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W)) 453 release_later := false.B 454 }.elsewhen(release_later) { 455 state := s_release_req 456 state_dup_0 := s_release_req 457 state_dup_1 := s_release_req 458 state_dup_for_mp.foreach(_ := s_release_req) 459 req := req_later.toWritebackReq 460 remain_set := Mux(req_later.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W)) 461 release_later := false.B 462 }.otherwise { 463 state := s_invalid 464 state_dup_0 := s_invalid 465 state_dup_1 := s_invalid 466 state_dup_for_mp.foreach(_ := s_invalid) 467 release_later := false.B 468 } 469 } 470 } 471 472 // When does this entry merge a new req? 473 // 1. When this entry is free 474 // 2. When this entry wants to release while still waiting for release_wakeup signal, 475 // and a probe req with the same addr comes. In this case we merge probe with release, 476 // handle this probe, so we don't need another release. 477 io.primary_ready := state_dup_1 === s_invalid 478 io.primary_ready_dup.zip(state_dup_for_mp).foreach { case (rdy, st) => rdy := st === s_invalid } 479 io.secondary_ready := state_dup_1 =/= s_invalid && io.req.bits.addr === req.addr 480 481 // data update logic 482 when (!s_data_merge) { 483 data := mergeData(data, io.release_update.bits.data_delayed, io.release_update.bits.mask_delayed) 484 } 485 486 when (!s_data_override && req.hasData) { 487 data := io.req_data.data 488 } 489 490 assert(!RegNext(!s_data_merge && !s_data_override)) 491 492 // performance counters 493 XSPerfAccumulate("wb_req", io.req.fire()) 494 XSPerfAccumulate("wb_release", state === s_release_req && release_done && req.voluntary) 495 XSPerfAccumulate("wb_probe_resp", state_dup_0 === s_release_req && release_done && !req.voluntary) 496 XSPerfAccumulate("penalty_blocked_by_channel_C", io.mem_release.valid && !io.mem_release.ready) 497 XSPerfAccumulate("penalty_waiting_for_channel_D", io.mem_grant.ready && !io.mem_grant.valid && state_dup_1 === s_release_resp) 498} 499 500class WritebackQueue(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule with HasTLDump with HasPerfEvents { 501 val io = IO(new Bundle { 502 val req = Flipped(DecoupledIO(new WritebackReq)) 503 val req_ready_dup = Vec(4, Output(Bool())) 504 val mem_release = DecoupledIO(new TLBundleC(edge.bundle)) 505 val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 506 507 val release_wakeup = Flipped(ValidIO(UInt(log2Up(cfg.nMissEntries).W))) 508 val release_update = Flipped(ValidIO(new ReleaseUpdate)) 509 510 val miss_req = Flipped(Valid(UInt())) 511 val block_miss_req = Output(Bool()) 512 }) 513 514 require(cfg.nReleaseEntries > cfg.nMissEntries) 515 516 val primary_ready_vec = Wire(Vec(cfg.nReleaseEntries, Bool())) 517 val secondary_ready_vec = Wire(Vec(cfg.nReleaseEntries, Bool())) 518 val accept = Cat(primary_ready_vec).orR 519 val merge = Cat(secondary_ready_vec).orR 520 val alloc = accept && !merge 521 // When there are empty entries, merge or allocate a new entry. 522 // When there is no empty entry, reject it even if it can be merged. 523 io.req.ready := accept 524 525 // assign default values to output signals 526 io.mem_release.valid := false.B 527 io.mem_release.bits := DontCare 528 io.mem_grant.ready := false.B 529 530 // dalay data write in miss queue release update for 1 cycle 531 val release_update_bits_for_entry = Wire(new MissQueueEntryReleaseUpdate) 532 release_update_bits_for_entry.addr := io.release_update.bits.addr 533 release_update_bits_for_entry.mask_delayed := RegEnable(io.release_update.bits.mask, io.release_update.valid) 534 release_update_bits_for_entry.data_delayed := RegEnable(io.release_update.bits.data, io.release_update.valid) 535 release_update_bits_for_entry.mask_orr := io.release_update.bits.mask.orR 536 537 // delay data write in miss queue req for 1 cycle 538 val req_data = RegEnable(io.req.bits.toWritebackReqData(), io.req.valid) 539 540 require(isPow2(cfg.nMissEntries)) 541 val grant_source = io.mem_grant.bits.source 542 val entries = Seq.fill(cfg.nReleaseEntries)(Module(new WritebackEntry(edge))) 543 entries.zipWithIndex.foreach { 544 case (entry, i) => 545 val former_primary_ready = if(i == 0) 546 false.B 547 else 548 Cat((0 until i).map(j => entries(j).io.primary_ready)).orR 549 val entry_id = (i + releaseIdBase).U 550 551 entry.io.id := entry_id 552 553 // entry req 554 entry.io.req.valid := io.req.valid 555 primary_ready_vec(i) := entry.io.primary_ready 556 secondary_ready_vec(i) := entry.io.secondary_ready 557 entry.io.req.bits := io.req.bits 558 entry.io.req_data := req_data 559 560 entry.io.primary_valid := alloc && 561 !former_primary_ready && 562 entry.io.primary_ready 563 entry.io.secondary_valid := io.req.valid && accept 564 565 entry.io.mem_grant.valid := (entry_id === grant_source) && io.mem_grant.valid 566 entry.io.mem_grant.bits := io.mem_grant.bits 567 568 entry.io.release_wakeup := io.release_wakeup 569 entry.io.release_update.valid := io.release_update.valid 570 entry.io.release_update.bits := release_update_bits_for_entry // data write delayed 571 } 572 573 io.req_ready_dup.zipWithIndex.foreach { case (rdy, i) => 574 rdy := Cat(entries.map(_.io.primary_ready_dup(i))).orR 575 } 576 577 assert(RegNext(!(io.mem_grant.valid && !io.mem_grant.ready))) 578 io.mem_grant.ready := true.B 579 580 val miss_req_conflict = VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === io.miss_req.bits)).asUInt.orR 581 io.block_miss_req := io.miss_req.valid && miss_req_conflict 582 583 TLArbiter.robin(edge, io.mem_release, entries.map(_.io.mem_release):_*) 584 585 // sanity check 586 // print all input/output requests for debug purpose 587 // print req 588 when (io.req.fire()) { 589 io.req.bits.dump() 590 } 591 592 when (io.mem_release.fire()) { 593 io.mem_release.bits.dump 594 } 595 596 when (io.mem_grant.fire()) { 597 io.mem_grant.bits.dump 598 } 599 600 when (io.miss_req.valid) { 601 XSDebug("miss_req: addr: %x\n", io.miss_req.bits) 602 } 603 604 when (io.block_miss_req) { 605 XSDebug("block_miss_req\n") 606 } 607 608 // performance counters 609 XSPerfAccumulate("wb_req", io.req.fire()) 610 611 val perfValidCount = RegNext(PopCount(entries.map(e => e.io.block_addr.valid))) 612 val perfEvents = Seq( 613 ("dcache_wbq_req ", io.req.fire()), 614 ("dcache_wbq_1_4_valid", (perfValidCount < (cfg.nReleaseEntries.U/4.U))), 615 ("dcache_wbq_2_4_valid", (perfValidCount > (cfg.nReleaseEntries.U/4.U)) & (perfValidCount <= (cfg.nReleaseEntries.U/2.U))), 616 ("dcache_wbq_3_4_valid", (perfValidCount > (cfg.nReleaseEntries.U/2.U)) & (perfValidCount <= (cfg.nReleaseEntries.U*3.U/4.U))), 617 ("dcache_wbq_4_4_valid", (perfValidCount > (cfg.nReleaseEntries.U*3.U/4.U))), 618 ) 619 generatePerfEvent() 620} 621