xref: /XiangShan/src/main/scala/xiangshan/cache/dcache/mainpipe/WritebackQueue.scala (revision 8b33cd30e0034914b58520e0dc3c0c4b1aad6a03)
11f0e2dc7SJiawei Lin/***************************************************************************************
21f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
31f0e2dc7SJiawei Lin* Copyright (c) 2020-2021 Peng Cheng Laboratory
41f0e2dc7SJiawei Lin*
51f0e2dc7SJiawei Lin* XiangShan is licensed under Mulan PSL v2.
61f0e2dc7SJiawei Lin* You can use this software according to the terms and conditions of the Mulan PSL v2.
71f0e2dc7SJiawei Lin* You may obtain a copy of Mulan PSL v2 at:
81f0e2dc7SJiawei Lin*          http://license.coscl.org.cn/MulanPSL2
91f0e2dc7SJiawei Lin*
101f0e2dc7SJiawei Lin* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
111f0e2dc7SJiawei Lin* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
121f0e2dc7SJiawei Lin* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
131f0e2dc7SJiawei Lin*
141f0e2dc7SJiawei Lin* See the Mulan PSL v2 for more details.
151f0e2dc7SJiawei Lin***************************************************************************************/
161f0e2dc7SJiawei Lin
171f0e2dc7SJiawei Linpackage xiangshan.cache
181f0e2dc7SJiawei Lin
191f0e2dc7SJiawei Linimport chisel3._
201f0e2dc7SJiawei Linimport chisel3.util._
2177af2baeSWilliam Wangimport freechips.rocketchip.tilelink.TLPermissions._
221ca0e4f3SYinan Xuimport freechips.rocketchip.tilelink.{TLArbiter, TLBundleC, TLBundleD, TLEdgeOut}
237f37d55fSTang Haojinimport org.chipsalliance.cde.config.Parameters
2444f2941bSJiru Sunimport utils.HasTLDump
2544f2941bSJiru Sunimport utility.{XSDebug, XSPerfAccumulate, HasPerfEvents}
26bb2f3f51STang Haojin
271f0e2dc7SJiawei Lin
2884026448SWilliam Wangclass WritebackReqCtrl(implicit p: Parameters) extends DCacheBundle {
2977af2baeSWilliam Wang  val param  = UInt(cWidth.W)
301f0e2dc7SJiawei Lin  val voluntary = Bool()
311f0e2dc7SJiawei Lin  val hasData = Bool()
3272dab974Scz4e  val corrupt = Bool()
331f0e2dc7SJiawei Lin  val dirty = Bool()
341f0e2dc7SJiawei Lin
35ad3ba452Szhanglinjuan  val delay_release = Bool()
36ad3ba452Szhanglinjuan  val miss_id = UInt(log2Up(cfg.nMissEntries).W)
3784026448SWilliam Wang}
3884026448SWilliam Wang
3984026448SWilliam Wangclass WritebackReqWodata(implicit p: Parameters) extends WritebackReqCtrl {
4084026448SWilliam Wang  val addr = UInt(PAddrBits.W)
41ad3ba452Szhanglinjuan
42*8b33cd30Sklin02  def dump(cond: Bool) = {
43*8b33cd30Sklin02    XSDebug(cond, "WritebackReq addr: %x param: %d voluntary: %b hasData: %b\n",
447a919e05SWilliam Wang      addr, param, voluntary, hasData)
457a919e05SWilliam Wang  }
467a919e05SWilliam Wang}
477a919e05SWilliam Wang
487a919e05SWilliam Wangclass WritebackReqData(implicit p: Parameters) extends DCacheBundle {
497a919e05SWilliam Wang  val data = UInt((cfg.blockBytes * 8).W)
507a919e05SWilliam Wang}
517a919e05SWilliam Wang
527a919e05SWilliam Wangclass WritebackReq(implicit p: Parameters) extends WritebackReqWodata {
537a919e05SWilliam Wang  val data = UInt((cfg.blockBytes * 8).W)
547a919e05SWilliam Wang
55*8b33cd30Sklin02  override def dump(cond: Bool) = {
56*8b33cd30Sklin02    XSDebug(cond, "WritebackReq addr: %x param: %d voluntary: %b hasData: %b data: %x\n",
571f0e2dc7SJiawei Lin      addr, param, voluntary, hasData, data)
581f0e2dc7SJiawei Lin  }
597a919e05SWilliam Wang
607a919e05SWilliam Wang  def toWritebackReqWodata(): WritebackReqWodata = {
617a919e05SWilliam Wang    val out = Wire(new WritebackReqWodata)
627a919e05SWilliam Wang    out.addr := addr
6384026448SWilliam Wang    out.param := param
6484026448SWilliam Wang    out.voluntary := voluntary
6584026448SWilliam Wang    out.hasData := hasData
6672dab974Scz4e    out.corrupt := corrupt
6784026448SWilliam Wang    out.dirty := dirty
6884026448SWilliam Wang    out.delay_release := delay_release
6984026448SWilliam Wang    out.miss_id := miss_id
7084026448SWilliam Wang    out
7184026448SWilliam Wang  }
7284026448SWilliam Wang
7384026448SWilliam Wang  def toWritebackReqCtrl(): WritebackReqCtrl = {
7484026448SWilliam Wang    val out = Wire(new WritebackReqCtrl)
757a919e05SWilliam Wang    out.param := param
767a919e05SWilliam Wang    out.voluntary := voluntary
777a919e05SWilliam Wang    out.hasData := hasData
7872dab974Scz4e    out.corrupt := corrupt
797a919e05SWilliam Wang    out.dirty := dirty
807a919e05SWilliam Wang    out.delay_release := delay_release
817a919e05SWilliam Wang    out.miss_id := miss_id
827a919e05SWilliam Wang    out
837a919e05SWilliam Wang  }
847a919e05SWilliam Wang
857a919e05SWilliam Wang  def toWritebackReqData(): WritebackReqData = {
867a919e05SWilliam Wang    val out = Wire(new WritebackReqData)
877a919e05SWilliam Wang    out.data := data
887a919e05SWilliam Wang    out
897a919e05SWilliam Wang  }
901f0e2dc7SJiawei Lin}
911f0e2dc7SJiawei Lin
92ad3ba452Szhanglinjuan// While a Release sleeps and waits for a refill to wake it up,
93ad3ba452Szhanglinjuan// main pipe might update meta & data during this time.
94ad3ba452Szhanglinjuan// So the meta & data to be released need to be updated too.
95ad3ba452Szhanglinjuanclass ReleaseUpdate(implicit p: Parameters) extends DCacheBundle {
96ad3ba452Szhanglinjuan  // only consider store here
97ad3ba452Szhanglinjuan  val addr = UInt(PAddrBits.W)
98ad3ba452Szhanglinjuan  val mask = UInt(DCacheBanks.W)
99ad3ba452Szhanglinjuan  val data = UInt((cfg.blockBytes * 8).W)
100ad3ba452Szhanglinjuan}
101ad3ba452Szhanglinjuan
102b8f6ff86SWilliam Wang// To reduce fanout, writeback queue entry data is updated 1 cycle
103935edac4STang Haojin// after ReleaseUpdate.fire
104b8f6ff86SWilliam Wangclass WBQEntryReleaseUpdate(implicit p: Parameters) extends DCacheBundle {
1057a919e05SWilliam Wang  // only consider store here
1067a919e05SWilliam Wang  val addr = UInt(PAddrBits.W)
1077a919e05SWilliam Wang  val mask_delayed = UInt(DCacheBanks.W)
1087a919e05SWilliam Wang  val data_delayed = UInt((cfg.blockBytes * 8).W)
1097a919e05SWilliam Wang  val mask_orr = Bool()
1107a919e05SWilliam Wang}
1117a919e05SWilliam Wang
112b8f6ff86SWilliam Wang// When a probe TtoB req enter dcache main pipe, check if that cacheline
113b8f6ff86SWilliam Wang// is waiting for release. If it is so, change TtoB to TtoN, set dcache
114b8f6ff86SWilliam Wang// coh to N.
115b8f6ff86SWilliam Wangclass ProbeToBCheckReq(implicit p: Parameters) extends DCacheBundle {
116b8f6ff86SWilliam Wang  val addr = UInt(PAddrBits.W) // paddr from mainpipe s1
117b8f6ff86SWilliam Wang}
118b8f6ff86SWilliam Wang
119b8f6ff86SWilliam Wangclass ProbeToBCheckResp(implicit p: Parameters) extends DCacheBundle {
120b8f6ff86SWilliam Wang  val toN = Bool() // need to set dcache coh to N
121b8f6ff86SWilliam Wang}
122b8f6ff86SWilliam Wang
1231f0e2dc7SJiawei Linclass WritebackEntry(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule with HasTLDump
1241f0e2dc7SJiawei Lin{
1251f0e2dc7SJiawei Lin  val io = IO(new Bundle {
1261f0e2dc7SJiawei Lin    val id = Input(UInt())
127ffd3154dSCharlieLiu
1287a919e05SWilliam Wang    val req = Flipped(DecoupledIO(new WritebackReqWodata))
1297a919e05SWilliam Wang    val req_data = Input(new WritebackReqData)
130a98b054bSWilliam Wang
1311f0e2dc7SJiawei Lin    val mem_release = DecoupledIO(new TLBundleC(edge.bundle))
1321f0e2dc7SJiawei Lin    val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
133ffd3154dSCharlieLiu    val primary_valid = Input(Bool())
134ffd3154dSCharlieLiu    val primary_ready = Output(Bool())
135ffd3154dSCharlieLiu    val primary_ready_dup = Vec(nDupWbReady, Output(Bool()))
1361f0e2dc7SJiawei Lin
1371f0e2dc7SJiawei Lin    val block_addr  = Output(Valid(UInt()))
1381f0e2dc7SJiawei Lin  })
1391f0e2dc7SJiawei Lin
140ffd3154dSCharlieLiu  val s_invalid :: s_release_req :: s_release_resp ::Nil = Enum(3)
14177af2baeSWilliam Wang  // ProbeAck:               s_invalid ->            s_release_req
14277af2baeSWilliam Wang  // ProbeAck merge Release: s_invalid ->            s_release_req
14377af2baeSWilliam Wang  // Release:                s_invalid -> s_sleep -> s_release_req -> s_release_resp
14477af2baeSWilliam Wang  // Release merge ProbeAck: s_invalid -> s_sleep -> s_release_req
14577af2baeSWilliam Wang  //                        (change Release into ProbeAck when Release is not fired)
14677af2baeSWilliam Wang  //                     or: s_invalid -> s_sleep -> s_release_req -> s_release_resp -> s_release_req
14777af2baeSWilliam Wang  //                        (send a ProbeAck after Release transaction is over)
148ffd3154dSCharlieLiu
1491f0e2dc7SJiawei Lin  val state = RegInit(s_invalid)
150f94d088cSZiyue-Zhang  val state_dup_0 = RegInit(s_invalid)
151f94d088cSZiyue-Zhang  val state_dup_1 = RegInit(s_invalid)
1525adc4829SYanqin Li  val state_dup_for_mp = RegInit(VecInit(Seq.fill(nDupWbReady)(s_invalid))) //TODO: clock gate
1531f0e2dc7SJiawei Lin
1541f0e2dc7SJiawei Lin  val remain = RegInit(0.U(refillCycles.W))
155f94d088cSZiyue-Zhang  val remain_dup_0 = RegInit(0.U(refillCycles.W))
156f94d088cSZiyue-Zhang  val remain_dup_1 = RegInit(0.U(refillCycles.W))
1571f0e2dc7SJiawei Lin  val remain_set = WireInit(0.U(refillCycles.W))
1581f0e2dc7SJiawei Lin  val remain_clr = WireInit(0.U(refillCycles.W))
1591f0e2dc7SJiawei Lin  remain := (remain | remain_set) & ~remain_clr
160f94d088cSZiyue-Zhang  remain_dup_0 := (remain_dup_0 | remain_set) & ~remain_clr
161f94d088cSZiyue-Zhang  remain_dup_1 := (remain_dup_1 | remain_set) & ~remain_clr
1621f0e2dc7SJiawei Lin
1637a919e05SWilliam Wang  // writeback queue data
1647a919e05SWilliam Wang  val data = Reg(UInt((cfg.blockBytes * 8).W))
1651f0e2dc7SJiawei Lin
16684026448SWilliam Wang  // writeback queue paddr
16784026448SWilliam Wang  val paddr_dup_0 = Reg(UInt(PAddrBits.W))
16884026448SWilliam Wang  val paddr_dup_1 = Reg(UInt(PAddrBits.W))
16984026448SWilliam Wang  val paddr_dup_2 = Reg(UInt(PAddrBits.W))
17084026448SWilliam Wang
1717a919e05SWilliam Wang  // pending data write
1727a919e05SWilliam Wang  // !s_data_override means there is an in-progress data write
1737a919e05SWilliam Wang  val s_data_override = RegInit(true.B)
1747a919e05SWilliam Wang  // !s_data_merge means there is an in-progress data merge
175ffd3154dSCharlieLiu  //val s_data_merge = RegInit(true.B)
1767a919e05SWilliam Wang
1777a919e05SWilliam Wang  // there are valid request that can be sent to release bus
178ffd3154dSCharlieLiu  //val busy = remain.orR && s_data_override && s_data_merge // have remain beats and data write finished
179ffd3154dSCharlieLiu  val busy = remain.orR && s_data_override  // have remain beats and data write finished
180ffd3154dSCharlieLiu  val req = Reg(new WritebackReqWodata)
1811f0e2dc7SJiawei Lin
1821f0e2dc7SJiawei Lin  // assign default signals to output signals
1831f0e2dc7SJiawei Lin  io.req.ready := false.B
1841f0e2dc7SJiawei Lin  io.mem_release.valid := false.B
1851f0e2dc7SJiawei Lin  io.mem_release.bits  := DontCare
1861f0e2dc7SJiawei Lin  io.mem_grant.ready   := false.B
1871f0e2dc7SJiawei Lin  io.block_addr.valid  := state =/= s_invalid
188ffd3154dSCharlieLiu  io.block_addr.bits   := req.addr
1891f0e2dc7SJiawei Lin
1907a919e05SWilliam Wang  s_data_override := true.B // data_override takes only 1 cycle
191ffd3154dSCharlieLiu  //s_data_merge := true.B // data_merge takes only 1 cycle
1921f0e2dc7SJiawei Lin
193*8b33cd30Sklin02  XSDebug(state =/= s_invalid, "WritebackEntry: %d state: %d block_addr: %x\n", io.id, state, io.block_addr.bits)
194ad3ba452Szhanglinjuan
1951f0e2dc7SJiawei Lin  // --------------------------------------------------------------------------------
1961f0e2dc7SJiawei Lin  // s_invalid: receive requests
1971f0e2dc7SJiawei Lin  // new req entering
198ffd3154dSCharlieLiu  io.req.ready := state === s_invalid
19915ee59e4Swakafa  val alloc = io.req.valid && io.primary_valid && io.primary_ready
20015ee59e4Swakafa  when (alloc) {
2011f0e2dc7SJiawei Lin    assert (remain === 0.U)
2021f0e2dc7SJiawei Lin    req := io.req.bits
2037a919e05SWilliam Wang    s_data_override := false.B
20484026448SWilliam Wang    // only update paddr when allocate a new missqueue entry
20584026448SWilliam Wang    paddr_dup_0 := io.req.bits.addr
20684026448SWilliam Wang    paddr_dup_1 := io.req.bits.addr
20784026448SWilliam Wang    paddr_dup_2 := io.req.bits.addr
208ffd3154dSCharlieLiu
209ad3ba452Szhanglinjuan    remain_set := Mux(io.req.bits.hasData, ~0.U(refillCycles.W), 1.U(refillCycles.W))
210ad3ba452Szhanglinjuan    state      := s_release_req
211f94d088cSZiyue-Zhang    state_dup_0 := s_release_req
212f94d088cSZiyue-Zhang    state_dup_1 := s_release_req
213c3a5fe5fShappy-lx    state_dup_for_mp.foreach(_ := s_release_req)
2141f0e2dc7SJiawei Lin  }
2151f0e2dc7SJiawei Lin
2161f0e2dc7SJiawei Lin  // --------------------------------------------------------------------------------
2171f0e2dc7SJiawei Lin  // while there beats remaining to be sent, we keep sending
2181f0e2dc7SJiawei Lin  // which beat to send in this cycle?
219f94d088cSZiyue-Zhang  val beat = PriorityEncoder(remain_dup_0)
2201f0e2dc7SJiawei Lin
2211f0e2dc7SJiawei Lin  val beat_data = Wire(Vec(refillCycles, UInt(beatBits.W)))
2221f0e2dc7SJiawei Lin  for (i <- 0 until refillCycles) {
2237a919e05SWilliam Wang    beat_data(i) := data((i + 1) * beatBits - 1, i * beatBits)
2241f0e2dc7SJiawei Lin  }
2251f0e2dc7SJiawei Lin
2261f0e2dc7SJiawei Lin  val probeResponse = edge.ProbeAck(
2271f0e2dc7SJiawei Lin    fromSource = io.id,
22884026448SWilliam Wang    toAddress = paddr_dup_1,
2291f0e2dc7SJiawei Lin    lgSize = log2Ceil(cfg.blockBytes).U,
2301f0e2dc7SJiawei Lin    reportPermissions = req.param
2311f0e2dc7SJiawei Lin  )
23272dab974Scz4e  probeResponse.corrupt := req.corrupt
2331f0e2dc7SJiawei Lin
2341f0e2dc7SJiawei Lin  val probeResponseData = edge.ProbeAck(
2351f0e2dc7SJiawei Lin    fromSource = io.id,
23684026448SWilliam Wang    toAddress = paddr_dup_1,
2371f0e2dc7SJiawei Lin    lgSize = log2Ceil(cfg.blockBytes).U,
2381f0e2dc7SJiawei Lin    reportPermissions = req.param,
23972dab974Scz4e    data = beat_data(beat),
24072dab974Scz4e    corrupt = req.corrupt
2411f0e2dc7SJiawei Lin  )
2421f0e2dc7SJiawei Lin
2431f0e2dc7SJiawei Lin  val voluntaryRelease = edge.Release(
2441f0e2dc7SJiawei Lin    fromSource = io.id,
24584026448SWilliam Wang    toAddress = paddr_dup_2,
2461f0e2dc7SJiawei Lin    lgSize = log2Ceil(cfg.blockBytes).U,
2471f0e2dc7SJiawei Lin    shrinkPermissions = req.param
2481f0e2dc7SJiawei Lin  )._2
24972dab974Scz4e  voluntaryRelease.corrupt := req.corrupt
2501f0e2dc7SJiawei Lin
2511f0e2dc7SJiawei Lin  val voluntaryReleaseData = edge.Release(
2521f0e2dc7SJiawei Lin    fromSource = io.id,
25384026448SWilliam Wang    toAddress = paddr_dup_2,
2541f0e2dc7SJiawei Lin    lgSize = log2Ceil(cfg.blockBytes).U,
2551f0e2dc7SJiawei Lin    shrinkPermissions = req.param,
25672dab974Scz4e    data = beat_data(beat),
25772dab974Scz4e    corrupt = req.corrupt
2581f0e2dc7SJiawei Lin  )._2
2591f0e2dc7SJiawei Lin
26015ee59e4Swakafa  // voluntaryReleaseData.echo.lift(DirtyKey).foreach(_ := req.dirty)
2611f0e2dc7SJiawei Lin  when(busy) {
262fddcfe1fSwakafa    assert(!req.dirty || req.hasData)
2631f0e2dc7SJiawei Lin  }
2641f0e2dc7SJiawei Lin
2651f0e2dc7SJiawei Lin  io.mem_release.valid := busy
2661f0e2dc7SJiawei Lin  io.mem_release.bits  := Mux(req.voluntary,
2671f0e2dc7SJiawei Lin    Mux(req.hasData, voluntaryReleaseData, voluntaryRelease),
2681f0e2dc7SJiawei Lin    Mux(req.hasData, probeResponseData, probeResponse))
2691f0e2dc7SJiawei Lin
270ffd3154dSCharlieLiu
271935edac4STang Haojin  when (io.mem_release.fire) {remain_clr := PriorityEncoderOH(remain_dup_1)}
2721f0e2dc7SJiawei Lin
2731f0e2dc7SJiawei Lin  val (_, _, release_done, _) = edge.count(io.mem_release)
2741f0e2dc7SJiawei Lin
275ffd3154dSCharlieLiu  when(state === s_release_req && release_done){
276ffd3154dSCharlieLiu    state := Mux(req.voluntary, s_release_resp, s_invalid)
27777af2baeSWilliam Wang    when(req.voluntary){
278c3a5fe5fShappy-lx      state_dup_for_mp.foreach(_ := s_release_resp)
27977af2baeSWilliam Wang    } .otherwise{
280c3a5fe5fShappy-lx      state_dup_for_mp.foreach(_ := s_invalid)
28177af2baeSWilliam Wang    }
28277af2baeSWilliam Wang  }
28377af2baeSWilliam Wang
284ffd3154dSCharlieLiu  io.primary_ready := state === s_invalid
285ffd3154dSCharlieLiu  io.primary_ready_dup.zip(state_dup_for_mp).foreach { case (rdy, st) => rdy := st === s_invalid }
2861f0e2dc7SJiawei Lin  // --------------------------------------------------------------------------------
2871f0e2dc7SJiawei Lin  // receive ReleaseAck for Releases
288ffd3154dSCharlieLiu  when (state === s_release_resp) {
2891f0e2dc7SJiawei Lin    io.mem_grant.ready := true.B
290935edac4STang Haojin    when (io.mem_grant.fire) {
2911f0e2dc7SJiawei Lin      state := s_invalid
292c3a5fe5fShappy-lx      state_dup_for_mp.foreach(_ := s_invalid)
29377af2baeSWilliam Wang    }
2941f0e2dc7SJiawei Lin  }
295b8f6ff86SWilliam Wang
2967a919e05SWilliam Wang  // data update logic
29715ee59e4Swakafa  when(!s_data_override && (req.hasData || RegNext(alloc))) {
2987a919e05SWilliam Wang    data := io.req_data.data
2997a919e05SWilliam Wang  }
3007a919e05SWilliam Wang
301ffd3154dSCharlieLiu  // assert(!RegNext(!s_data_merge && !s_data_override))
3027a919e05SWilliam Wang
3031f0e2dc7SJiawei Lin  // performance counters
304935edac4STang Haojin  XSPerfAccumulate("wb_req", io.req.fire)
3051f0e2dc7SJiawei Lin  XSPerfAccumulate("wb_release", state === s_release_req && release_done && req.voluntary)
306ffd3154dSCharlieLiu  XSPerfAccumulate("wb_probe_resp", state === s_release_req && release_done && !req.voluntary)
3071f0e2dc7SJiawei Lin  XSPerfAccumulate("penalty_blocked_by_channel_C", io.mem_release.valid && !io.mem_release.ready)
308ffd3154dSCharlieLiu  XSPerfAccumulate("penalty_waiting_for_channel_D", io.mem_grant.ready && !io.mem_grant.valid && state === s_release_resp)
3091f0e2dc7SJiawei Lin}
3101f0e2dc7SJiawei Lin
311ffd3154dSCharlieLiuclass WritebackQueue(edge: TLEdgeOut)(implicit p: Parameters) extends DCacheModule with HasTLDump with HasPerfEvents
312ffd3154dSCharlieLiu{
3131f0e2dc7SJiawei Lin  val io = IO(new Bundle {
3141f0e2dc7SJiawei Lin    val req = Flipped(DecoupledIO(new WritebackReq))
3156c7e5e86Szhanglinjuan    val req_ready_dup = Vec(nDupWbReady, Output(Bool()))
3161f0e2dc7SJiawei Lin    val mem_release = DecoupledIO(new TLBundleC(edge.bundle))
3171f0e2dc7SJiawei Lin    val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
3181f0e2dc7SJiawei Lin
319ffd3154dSCharlieLiu    //val probe_ttob_check_req = Flipped(ValidIO(new ProbeToBCheckReq))
320ffd3154dSCharlieLiu    //val probe_ttob_check_resp = ValidIO(new ProbeToBCheckResp)
321b8f6ff86SWilliam Wang
32208b0bc30Shappy-lx    // 5 miss_req to check: 3*LoadPipe + 1*MainPipe + 1*missReqArb_out
32308b0bc30Shappy-lx    val miss_req_conflict_check = Vec(LoadPipelineWidth + 2, Flipped(Valid(UInt())))
32408b0bc30Shappy-lx    val block_miss_req = Vec(LoadPipelineWidth + 2, Output(Bool()))
3251f0e2dc7SJiawei Lin  })
3261f0e2dc7SJiawei Lin
327300ded30SWilliam Wang  require(cfg.nReleaseEntries > cfg.nMissEntries)
328300ded30SWilliam Wang
329a98b054bSWilliam Wang  val primary_ready_vec = Wire(Vec(cfg.nReleaseEntries, Bool()))
330ffd3154dSCharlieLiu  val alloc = Cat(primary_ready_vec).orR
331ffd3154dSCharlieLiu
332ffd3154dSCharlieLiu  val req = io.req
333ffd3154dSCharlieLiu  val block_conflict = Wire(Bool())
334ffd3154dSCharlieLiu
335ffd3154dSCharlieLiu  req.ready := alloc && !block_conflict
3361f0e2dc7SJiawei Lin
3371f0e2dc7SJiawei Lin  // assign default values to output signals
3381f0e2dc7SJiawei Lin  io.mem_release.valid := false.B
3391f0e2dc7SJiawei Lin  io.mem_release.bits  := DontCare
3401f0e2dc7SJiawei Lin  io.mem_grant.ready   := false.B
3411f0e2dc7SJiawei Lin
342b8f6ff86SWilliam Wang  // delay data write in writeback req for 1 cycle
3437a919e05SWilliam Wang  val req_data = RegEnable(io.req.bits.toWritebackReqData(), io.req.valid)
3447a919e05SWilliam Wang
345ad3ba452Szhanglinjuan  require(isPow2(cfg.nMissEntries))
346300ded30SWilliam Wang  val grant_source = io.mem_grant.bits.source
347a98b054bSWilliam Wang  val entries = Seq.fill(cfg.nReleaseEntries)(Module(new WritebackEntry(edge)))
348a98b054bSWilliam Wang  entries.zipWithIndex.foreach {
349a98b054bSWilliam Wang    case (entry, i) =>
350a98b054bSWilliam Wang      val former_primary_ready = if(i == 0)
351a98b054bSWilliam Wang        false.B
352a98b054bSWilliam Wang      else
353a98b054bSWilliam Wang        Cat((0 until i).map(j => entries(j).io.primary_ready)).orR
354300ded30SWilliam Wang      val entry_id = (i + releaseIdBase).U
3551f0e2dc7SJiawei Lin
356300ded30SWilliam Wang      entry.io.id := entry_id
3571f0e2dc7SJiawei Lin
3581f0e2dc7SJiawei Lin      // entry req
3597ecd6591SCharlie Liu      entry.io.req.valid := req.valid && !block_conflict
360a98b054bSWilliam Wang      primary_ready_vec(i)   := entry.io.primary_ready
361ffd3154dSCharlieLiu      entry.io.req.bits  := req.bits
3627a919e05SWilliam Wang      entry.io.req_data  := req_data
3631f0e2dc7SJiawei Lin
364a98b054bSWilliam Wang      entry.io.primary_valid := alloc &&
365a98b054bSWilliam Wang        !former_primary_ready &&
366a98b054bSWilliam Wang        entry.io.primary_ready
367a98b054bSWilliam Wang
368300ded30SWilliam Wang      entry.io.mem_grant.valid := (entry_id === grant_source) && io.mem_grant.valid
3691f0e2dc7SJiawei Lin      entry.io.mem_grant.bits  := io.mem_grant.bits
370ffd3154dSCharlieLiu      //when (i.U === io.mem_grant.bits.source) {
371ffd3154dSCharlieLiu      //  io.mem_grant.ready := entry.io.mem_grant.ready
372ffd3154dSCharlieLiu      //}
3731f0e2dc7SJiawei Lin  }
374c3a5fe5fShappy-lx
375c3a5fe5fShappy-lx  io.req_ready_dup.zipWithIndex.foreach { case (rdy, i) =>
376ffd3154dSCharlieLiu    rdy := Cat(entries.map(_.io.primary_ready_dup(i))).orR && !block_conflict
377c3a5fe5fShappy-lx  }
378c3a5fe5fShappy-lx
37977af2baeSWilliam Wang  io.mem_grant.ready := true.B
380ffd3154dSCharlieLiu  block_conflict := VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === io.req.bits.addr)).asUInt.orR
38108b0bc30Shappy-lx  val miss_req_conflict = io.miss_req_conflict_check.map{ r =>
38208b0bc30Shappy-lx    VecInit(entries.map(e => e.io.block_addr.valid && e.io.block_addr.bits === r.bits)).asUInt.orR
38308b0bc30Shappy-lx  }
38408b0bc30Shappy-lx  io.block_miss_req.zipWithIndex.foreach{ case(blk, i) =>
38508b0bc30Shappy-lx    blk := io.miss_req_conflict_check(i).valid && miss_req_conflict(i)
38608b0bc30Shappy-lx  }
3871f0e2dc7SJiawei Lin
3881f0e2dc7SJiawei Lin  TLArbiter.robin(edge, io.mem_release, entries.map(_.io.mem_release):_*)
3891f0e2dc7SJiawei Lin
3901f0e2dc7SJiawei Lin  // sanity check
3911f0e2dc7SJiawei Lin  // print all input/output requests for debug purpose
3921f0e2dc7SJiawei Lin  // print req
393*8b33cd30Sklin02  io.req.bits.dump(io.req.fire)
3941f0e2dc7SJiawei Lin
395*8b33cd30Sklin02  io.mem_grant.bits.dump(io.mem_release.fire)
3961f0e2dc7SJiawei Lin
397*8b33cd30Sklin02  // XSDebug(io.miss_req.valid, "miss_req: addr: %x\n", io.miss_req.bits)
398*8b33cd30Sklin02  // XSDebug(io.block_miss_req, "block_miss_req\n")
3991f0e2dc7SJiawei Lin
4001f0e2dc7SJiawei Lin  // performance counters
401935edac4STang Haojin  XSPerfAccumulate("wb_req", io.req.fire)
402cd365d4cSrvcoresjw
403b6d53cefSWilliam Wang  val perfValidCount = RegNext(PopCount(entries.map(e => e.io.block_addr.valid)))
404cd365d4cSrvcoresjw  val perfEvents = Seq(
405935edac4STang Haojin    ("dcache_wbq_req      ", io.req.fire),
406b6d53cefSWilliam Wang    ("dcache_wbq_1_4_valid", (perfValidCount < (cfg.nReleaseEntries.U/4.U))),
407b6d53cefSWilliam Wang    ("dcache_wbq_2_4_valid", (perfValidCount > (cfg.nReleaseEntries.U/4.U)) & (perfValidCount <= (cfg.nReleaseEntries.U/2.U))),
408b6d53cefSWilliam Wang    ("dcache_wbq_3_4_valid", (perfValidCount > (cfg.nReleaseEntries.U/2.U)) & (perfValidCount <= (cfg.nReleaseEntries.U*3.U/4.U))),
409b6d53cefSWilliam Wang    ("dcache_wbq_4_4_valid", (perfValidCount > (cfg.nReleaseEntries.U*3.U/4.U))),
410cd365d4cSrvcoresjw  )
4111ca0e4f3SYinan Xu  generatePerfEvent()
412ffd3154dSCharlieLiu
4131f0e2dc7SJiawei Lin}