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