xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/mainpipe/WritebackQueue.scala (revision 6c7e5e86b0156ac97456497c877afd4168fa4587)
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