xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala (revision 602b407ccabf2c6a4276345090d317a49650006a)
11d8f4dcbSJay/***************************************************************************************
26c106319Sxu_zh* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
36c106319Sxu_zh* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
41d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
51d8f4dcbSJay*
61d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
71d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
81d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
91d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
101d8f4dcbSJay*
111d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
121d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
131d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
141d8f4dcbSJay*
151d8f4dcbSJay* See the Mulan PSL v2 for more details.
161d8f4dcbSJay***************************************************************************************/
171d8f4dcbSJay
181d8f4dcbSJaypackage xiangshan.frontend.icache
191d8f4dcbSJay
201d8f4dcbSJayimport chisel3._
211d8f4dcbSJayimport chisel3.util._
22cf7d6b7aSMuziimport difftest._
23cf7d6b7aSMuziimport freechips.rocketchip.tilelink._
24cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
25cf7d6b7aSMuziimport utility._
261d8f4dcbSJayimport xiangshan._
271d8f4dcbSJay
28415fcbe2Sxu_zhclass DeMultiplexerIO[T <: Data](gen: T, n: Int) extends Bundle {
29415fcbe2Sxu_zh  val in:     DecoupledIO[T]      = Flipped(DecoupledIO(gen))
30415fcbe2Sxu_zh  val out:    Vec[DecoupledIO[T]] = Vec(n, DecoupledIO(gen))
31415fcbe2Sxu_zh  val chosen: UInt                = Output(UInt(log2Ceil(n).W))
32415fcbe2Sxu_zh}
331d8f4dcbSJay
34415fcbe2Sxu_zh/** Hardware module that is used to sequence 1 producer into n consumer.
35b92f8445Sssszwic * Priority is given to lower producer.
36b92f8445Sssszwic */
37415fcbe2Sxu_zhclass DeMultiplexer[T <: Data](val gen: T, val n: Int) extends Module {
38b92f8445Sssszwic  require(n >= 2)
39415fcbe2Sxu_zh  val io: DeMultiplexerIO[T] = IO(new DeMultiplexerIO(gen, n))
40b92f8445Sssszwic
41415fcbe2Sxu_zh  private val grant = false.B +: (1 until n).map(i => (0 until i).map(io.out(_).ready).reduce(_ || _))
42415fcbe2Sxu_zh  (0 until n).foreach { i =>
43b92f8445Sssszwic    io.out(i).bits  := io.in.bits
44b92f8445Sssszwic    io.out(i).valid := !grant(i) && io.in.valid
45b92f8445Sssszwic  }
46b92f8445Sssszwic
47b92f8445Sssszwic  io.in.ready := grant.last || io.out.last.ready
48b92f8445Sssszwic  io.chosen   := PriorityEncoder(VecInit(io.out.map(_.ready)))
491d8f4dcbSJay}
501d8f4dcbSJay
51415fcbe2Sxu_zhclass MuxBundleIO[T <: Data](gen: T, n: Int) extends Bundle {
52415fcbe2Sxu_zh  val sel: UInt                = Input(UInt(log2Ceil(n).W))
53415fcbe2Sxu_zh  val in:  Vec[DecoupledIO[T]] = Flipped(Vec(n, DecoupledIO(gen)))
54415fcbe2Sxu_zh  val out: DecoupledIO[T]      = DecoupledIO(gen)
55415fcbe2Sxu_zh}
56415fcbe2Sxu_zh
57cf7d6b7aSMuziclass MuxBundle[T <: Data](val gen: T, val n: Int) extends Module {
58b92f8445Sssszwic  require(n >= 2)
59415fcbe2Sxu_zh  val io: MuxBundleIO[T] = IO(new MuxBundleIO[T](gen, n))
60b92f8445Sssszwic
61b92f8445Sssszwic  io.in <> DontCare
62b92f8445Sssszwic  io.out <> DontCare
63415fcbe2Sxu_zh  (0 until n).foreach { i =>
64b92f8445Sssszwic    when(io.sel === i.U) {
65b92f8445Sssszwic      io.out <> io.in(i)
66b92f8445Sssszwic    }
67b92f8445Sssszwic    io.in(i).ready := (io.sel === i.U) && io.out.ready
68b92f8445Sssszwic  }
69b92f8445Sssszwic}
70b92f8445Sssszwic
71b92f8445Sssszwicclass ICacheMissReq(implicit p: Parameters) extends ICacheBundle {
72415fcbe2Sxu_zh  val blkPaddr: UInt = UInt((PAddrBits - blockOffBits).W)
73415fcbe2Sxu_zh  val vSetIdx:  UInt = UInt(idxBits.W)
74b92f8445Sssszwic}
75b92f8445Sssszwic
76b92f8445Sssszwicclass ICacheMissResp(implicit p: Parameters) extends ICacheBundle {
77415fcbe2Sxu_zh  val blkPaddr: UInt = UInt((PAddrBits - blockOffBits).W)
78415fcbe2Sxu_zh  val vSetIdx:  UInt = UInt(idxBits.W)
79415fcbe2Sxu_zh  val waymask:  UInt = UInt(nWays.W)
80415fcbe2Sxu_zh  val data:     UInt = UInt(blockBits.W)
81415fcbe2Sxu_zh  val corrupt:  Bool = Bool()
821d8f4dcbSJay}
831d8f4dcbSJay
84b92f8445Sssszwicclass LookUpMSHR(implicit p: Parameters) extends ICacheBundle {
85415fcbe2Sxu_zh  val info: Valid[ICacheMissReq] = ValidIO(new ICacheMissReq)
86415fcbe2Sxu_zh  val hit:  Bool                 = Input(Bool())
871d8f4dcbSJay}
881d8f4dcbSJay
89b92f8445Sssszwicclass MSHRResp(implicit p: Parameters) extends ICacheBundle {
90415fcbe2Sxu_zh  val blkPaddr: UInt = UInt((PAddrBits - blockOffBits).W)
91415fcbe2Sxu_zh  val vSetIdx:  UInt = UInt(idxBits.W)
92415fcbe2Sxu_zh  val way:      UInt = UInt(wayBits.W)
93b92f8445Sssszwic}
94b92f8445Sssszwic
95b92f8445Sssszwicclass MSHRAcquire(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
96415fcbe2Sxu_zh  val acquire: TLBundleA = new TLBundleA(edge.bundle)
97415fcbe2Sxu_zh  val vSetIdx: UInt      = UInt(idxBits.W)
98b92f8445Sssszwic}
99b92f8445Sssszwic
100415fcbe2Sxu_zhclass ICacheMSHRIO(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
101415fcbe2Sxu_zh  val fencei:    Bool                       = Input(Bool())
102415fcbe2Sxu_zh  val flush:     Bool                       = Input(Bool())
103415fcbe2Sxu_zh  val invalid:   Bool                       = Input(Bool())
104415fcbe2Sxu_zh  val req:       DecoupledIO[ICacheMissReq] = Flipped(DecoupledIO(new ICacheMissReq))
105415fcbe2Sxu_zh  val acquire:   DecoupledIO[MSHRAcquire]   = DecoupledIO(new MSHRAcquire(edge))
106415fcbe2Sxu_zh  val lookUps:   Vec[LookUpMSHR]            = Flipped(Vec(2, new LookUpMSHR))
107415fcbe2Sxu_zh  val resp:      Valid[MSHRResp]            = ValidIO(new MSHRResp)
108415fcbe2Sxu_zh  val victimWay: UInt                       = Input(UInt(wayBits.W))
109415fcbe2Sxu_zh}
1101d8f4dcbSJay
111415fcbe2Sxu_zhclass ICacheMSHR(edge: TLEdgeOut, isFetch: Boolean, ID: Int)(implicit p: Parameters) extends ICacheModule {
112415fcbe2Sxu_zh  val io: ICacheMSHRIO = IO(new ICacheMSHRIO(edge))
113415fcbe2Sxu_zh
114415fcbe2Sxu_zh  private val valid = RegInit(Bool(), false.B)
115415fcbe2Sxu_zh  // this MSHR doesn't respond to fetch and sram
116415fcbe2Sxu_zh  private val flush  = RegInit(Bool(), false.B)
117415fcbe2Sxu_zh  private val fencei = RegInit(Bool(), false.B)
118b92f8445Sssszwic  // this MSHR has been issued
119415fcbe2Sxu_zh  private val issue = RegInit(Bool(), false.B)
1201d8f4dcbSJay
121415fcbe2Sxu_zh  private val blkPaddr = RegInit(UInt((PAddrBits - blockOffBits).W), 0.U)
122415fcbe2Sxu_zh  private val vSetIdx  = RegInit(UInt(idxBits.W), 0.U)
123415fcbe2Sxu_zh  private val way      = RegInit(UInt(wayBits.W), 0.U)
1241d8f4dcbSJay
125b92f8445Sssszwic  // look up and return result at the same cycle
126415fcbe2Sxu_zh  private val hits = io.lookUps.map { lookup =>
127cf7d6b7aSMuzi    valid && !fencei && !flush && (lookup.info.bits.vSetIdx === vSetIdx) &&
128cf7d6b7aSMuzi    (lookup.info.bits.blkPaddr === blkPaddr)
129415fcbe2Sxu_zh  }
130b92f8445Sssszwic  // Decoupling valid and bits
131cf7d6b7aSMuzi  (0 until 2).foreach(i => io.lookUps(i).hit := hits(i))
1321d8f4dcbSJay
133b92f8445Sssszwic  // disable wake up when hit MSHR (fencei is low)
134b92f8445Sssszwic  // when(hit) {
135b92f8445Sssszwic  //   flush := false.B
136b92f8445Sssszwic  // }
1372a6078bfSguohongyu
138b92f8445Sssszwic  // invalid when the req hasn't been issued
139b92f8445Sssszwic  when(io.fencei || io.flush) {
140b92f8445Sssszwic    fencei := true.B
141b92f8445Sssszwic    flush  := true.B
142b92f8445Sssszwic    when(!issue) {
143b92f8445Sssszwic      valid := false.B
144b92f8445Sssszwic    }
145b92f8445Sssszwic  }
1461d8f4dcbSJay
147b92f8445Sssszwic  // receive request and register
148b92f8445Sssszwic  io.req.ready := !valid && !io.flush && !io.fencei
149935edac4STang Haojin  when(io.req.fire) {
150b92f8445Sssszwic    valid    := true.B
151b92f8445Sssszwic    flush    := false.B
152b92f8445Sssszwic    issue    := false.B
153b92f8445Sssszwic    fencei   := false.B
154b92f8445Sssszwic    blkPaddr := io.req.bits.blkPaddr
155b92f8445Sssszwic    vSetIdx  := io.req.bits.vSetIdx
1561d8f4dcbSJay  }
1571d8f4dcbSJay
158b92f8445Sssszwic  // send request to L2
159b92f8445Sssszwic  io.acquire.valid := valid && !issue && !io.flush && !io.fencei
160415fcbe2Sxu_zh  private val getBlock = edge.Get(
161b92f8445Sssszwic    fromSource = ID.U,
162b92f8445Sssszwic    toAddress = Cat(blkPaddr, 0.U(blockOffBits.W)),
163cf7d6b7aSMuzi    lgSize = log2Up(cacheParams.blockBytes).U
16438160951Sguohongyu  )._2
165b92f8445Sssszwic  io.acquire.bits.acquire := getBlock
166b92f8445Sssszwic  io.acquire.bits.acquire.user.lift(ReqSourceKey).foreach(_ := MemReqSource.CPUInst.id.U)
167b92f8445Sssszwic  io.acquire.bits.vSetIdx := vSetIdx
16838160951Sguohongyu
169b92f8445Sssszwic  // get victim way when acquire fire
170b92f8445Sssszwic  when(io.acquire.fire) {
171b92f8445Sssszwic    issue := true.B
172415fcbe2Sxu_zh    way   := io.victimWay
173b92f8445Sssszwic  }
1741d8f4dcbSJay
175b92f8445Sssszwic  // invalid request when grant finish
176b92f8445Sssszwic  when(io.invalid) {
177b92f8445Sssszwic    valid := false.B
178b92f8445Sssszwic  }
1792a25dbb4SJay
180b92f8445Sssszwic  // offer the information other than data for write sram and response fetch
181b92f8445Sssszwic  io.resp.valid         := valid && (!flush && !fencei)
182b92f8445Sssszwic  io.resp.bits.blkPaddr := blkPaddr
183b92f8445Sssszwic  io.resp.bits.vSetIdx  := vSetIdx
184415fcbe2Sxu_zh  io.resp.bits.way      := way
185b92f8445Sssszwic}
186131aa97cSssszwic
187415fcbe2Sxu_zhclass ICacheMissUnitIO(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheBundle {
188b92f8445Sssszwic  // difftest
189415fcbe2Sxu_zh  val hartId: Bool = Input(Bool())
190b92f8445Sssszwic  // control
191415fcbe2Sxu_zh  val fencei: Bool = Input(Bool())
192415fcbe2Sxu_zh  val flush:  Bool = Input(Bool())
193b92f8445Sssszwic  // fetch
194415fcbe2Sxu_zh  val fetch_req:  DecoupledIO[ICacheMissReq] = Flipped(DecoupledIO(new ICacheMissReq))
195415fcbe2Sxu_zh  val fetch_resp: Valid[ICacheMissResp]      = ValidIO(new ICacheMissResp)
196b92f8445Sssszwic  // prefetch
197415fcbe2Sxu_zh  val prefetch_req: DecoupledIO[ICacheMissReq] = Flipped(DecoupledIO(new ICacheMissReq))
198b92f8445Sssszwic  // SRAM Write Req
199415fcbe2Sxu_zh  val meta_write: DecoupledIO[ICacheMetaWriteBundle] = DecoupledIO(new ICacheMetaWriteBundle)
200415fcbe2Sxu_zh  val data_write: DecoupledIO[ICacheDataWriteBundle] = DecoupledIO(new ICacheDataWriteBundle)
201b92f8445Sssszwic  // get victim from replacer
202415fcbe2Sxu_zh  val victim: ReplacerVictim = new ReplacerVictim
203b92f8445Sssszwic  // Tilelink
204415fcbe2Sxu_zh  val mem_acquire: DecoupledIO[TLBundleA] = DecoupledIO(new TLBundleA(edge.bundle))
205415fcbe2Sxu_zh  val mem_grant:   DecoupledIO[TLBundleD] = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
2061d8f4dcbSJay}
2071d8f4dcbSJay
208415fcbe2Sxu_zhclass ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheModule {
209415fcbe2Sxu_zh  val io: ICacheMissUnitIO = IO(new ICacheMissUnitIO(edge))
2101d8f4dcbSJay
211b92f8445Sssszwic  /**
212b92f8445Sssszwic    ******************************************************************************
213b92f8445Sssszwic    * fetch have higher priority
214b92f8445Sssszwic    * fetch MSHR: lower index have a higher priority
215b92f8445Sssszwic    * prefetch MSHR: the prefetchMSHRs earlier have a higher priority
216b92f8445Sssszwic    *                 ---------       --------------       -----------
217b92f8445Sssszwic    * ---fetch reg--->| Demux |-----> | fetch MSHR |------>| Arbiter |---acquire--->
218b92f8445Sssszwic    *                 ---------       --------------       -----------
219b92f8445Sssszwic    *                                 | fetch MSHR |            ^
220b92f8445Sssszwic    *                                 --------------            |
221b92f8445Sssszwic    *                                                           |
222b92f8445Sssszwic    *                                -----------------          |
223b92f8445Sssszwic    *                                | prefetch MSHR |          |
224b92f8445Sssszwic    *                 ---------      -----------------     -----------
225b92f8445Sssszwic    * ---fetch reg--->| Demux |----> | prefetch MSHR |---->| Arbiter |
226b92f8445Sssszwic    *                 ---------      -----------------     -----------
227b92f8445Sssszwic    *                                |    .......    |
228b92f8445Sssszwic    *                                -----------------
229b92f8445Sssszwic    ******************************************************************************
230b92f8445Sssszwic    */
2311d8f4dcbSJay
232415fcbe2Sxu_zh  private val fetchDemux    = Module(new DeMultiplexer(new ICacheMissReq, nFetchMshr))
233415fcbe2Sxu_zh  private val prefetchDemux = Module(new DeMultiplexer(new ICacheMissReq, nPrefetchMshr))
234415fcbe2Sxu_zh  private val prefetchArb   = Module(new MuxBundle(new MSHRAcquire(edge), nPrefetchMshr))
235415fcbe2Sxu_zh  private val acquireArb    = Module(new Arbiter(new MSHRAcquire(edge), nFetchMshr + 1))
236cb6e5d3cSssszwic
237b92f8445Sssszwic  // To avoid duplicate request reception.
238415fcbe2Sxu_zh  private val fetchHit    = Wire(Bool())
239415fcbe2Sxu_zh  private val prefetchHit = Wire(Bool())
240b92f8445Sssszwic  fetchDemux.io.in <> io.fetch_req
241b92f8445Sssszwic  fetchDemux.io.in.valid := io.fetch_req.valid && !fetchHit
242b92f8445Sssszwic  io.fetch_req.ready     := fetchDemux.io.in.ready || fetchHit
243b92f8445Sssszwic  prefetchDemux.io.in <> io.prefetch_req
244b92f8445Sssszwic  prefetchDemux.io.in.valid := io.prefetch_req.valid && !prefetchHit
245b92f8445Sssszwic  io.prefetch_req.ready     := prefetchDemux.io.in.ready || prefetchHit
246b92f8445Sssszwic  acquireArb.io.in.last <> prefetchArb.io.out
2471d8f4dcbSJay
248b92f8445Sssszwic  // mem_acquire connect
249b92f8445Sssszwic  io.mem_acquire.valid    := acquireArb.io.out.valid
250b92f8445Sssszwic  io.mem_acquire.bits     := acquireArb.io.out.bits.acquire
251b92f8445Sssszwic  acquireArb.io.out.ready := io.mem_acquire.ready
2521d8f4dcbSJay
253415fcbe2Sxu_zh  private val fetchMSHRs = (0 until nFetchMshr).map { i =>
254b92f8445Sssszwic    val mshr = Module(new ICacheMSHR(edge, true, i))
255b92f8445Sssszwic    mshr.io.flush  := false.B
256b92f8445Sssszwic    mshr.io.fencei := io.fencei
257b92f8445Sssszwic    mshr.io.req <> fetchDemux.io.out(i)
258b92f8445Sssszwic    mshr.io.lookUps(0).info.valid := io.fetch_req.valid
259b92f8445Sssszwic    mshr.io.lookUps(0).info.bits  := io.fetch_req.bits
260b92f8445Sssszwic    mshr.io.lookUps(1).info.valid := io.prefetch_req.valid
261b92f8445Sssszwic    mshr.io.lookUps(1).info.bits  := io.prefetch_req.bits
262b92f8445Sssszwic    mshr.io.victimWay             := io.victim.way
263b92f8445Sssszwic    acquireArb.io.in(i) <> mshr.io.acquire
264b92f8445Sssszwic    mshr
2651d8f4dcbSJay  }
2661d8f4dcbSJay
267415fcbe2Sxu_zh  private val prefetchMSHRs = (0 until nPrefetchMshr).map { i =>
268b92f8445Sssszwic    val mshr = Module(new ICacheMSHR(edge, false, nFetchMshr + i))
269b92f8445Sssszwic    mshr.io.flush  := io.flush
270b92f8445Sssszwic    mshr.io.fencei := io.fencei
271b92f8445Sssszwic    mshr.io.req <> prefetchDemux.io.out(i)
272b92f8445Sssszwic    mshr.io.lookUps(0).info.valid := io.fetch_req.valid
273b92f8445Sssszwic    mshr.io.lookUps(0).info.bits  := io.fetch_req.bits
274b92f8445Sssszwic    mshr.io.lookUps(1).info.valid := io.prefetch_req.valid
275b92f8445Sssszwic    mshr.io.lookUps(1).info.bits  := io.prefetch_req.bits
276b92f8445Sssszwic    mshr.io.victimWay             := io.victim.way
277b92f8445Sssszwic    prefetchArb.io.in(i) <> mshr.io.acquire
278b92f8445Sssszwic    mshr
2797052722fSJay  }
2807052722fSJay
28158c354d0Sssszwic  /**
28258c354d0Sssszwic    ******************************************************************************
283b92f8445Sssszwic    * MSHR look up
284b92f8445Sssszwic    * - look up all mshr
28558c354d0Sssszwic    ******************************************************************************
28658c354d0Sssszwic    */
287415fcbe2Sxu_zh  private val allMSHRs = fetchMSHRs ++ prefetchMSHRs
288415fcbe2Sxu_zh  private val prefetchHitFetchReq = (io.prefetch_req.bits.blkPaddr === io.fetch_req.bits.blkPaddr) &&
289b92f8445Sssszwic    (io.prefetch_req.bits.vSetIdx === io.fetch_req.bits.vSetIdx) &&
290b92f8445Sssszwic    io.fetch_req.valid
291b92f8445Sssszwic  fetchHit    := allMSHRs.map(mshr => mshr.io.lookUps(0).hit).reduce(_ || _)
292b92f8445Sssszwic  prefetchHit := allMSHRs.map(mshr => mshr.io.lookUps(1).hit).reduce(_ || _) || prefetchHitFetchReq
29358c354d0Sssszwic
294b92f8445Sssszwic  /**
295b92f8445Sssszwic    ******************************************************************************
296b92f8445Sssszwic    * prefetchMSHRs priority
297b92f8445Sssszwic    * - The requests that enter the prefetchMSHRs earlier have a higher priority in issuing.
298415fcbe2Sxu_zh    * - The order of enqueuing is recorded in FIFO when request enters MSHRs.
299b92f8445Sssszwic    * - The requests are dispatched in the order they are recorded in FIFO.
300b92f8445Sssszwic    ******************************************************************************
301b92f8445Sssszwic    */
302b92f8445Sssszwic  // When the FIFO is full, enqueue and dequeue operations do not occur at the same cycle.
303b92f8445Sssszwic  // So the depth of the FIFO is set to match the number of MSHRs.
304b92f8445Sssszwic  // val priorityFIFO = Module(new Queue(UInt(log2Ceil(nPrefetchMshr).W), nPrefetchMshr, hasFlush=true))
305415fcbe2Sxu_zh  private val priorityFIFO = Module(new FIFOReg(UInt(log2Ceil(nPrefetchMshr).W), nPrefetchMshr, hasFlush = true))
306b92f8445Sssszwic  priorityFIFO.io.flush.get := io.flush || io.fencei
307b92f8445Sssszwic  priorityFIFO.io.enq.valid := prefetchDemux.io.in.fire
308b92f8445Sssszwic  priorityFIFO.io.enq.bits  := prefetchDemux.io.chosen
309b92f8445Sssszwic  priorityFIFO.io.deq.ready := prefetchArb.io.out.fire
310b92f8445Sssszwic  prefetchArb.io.sel        := priorityFIFO.io.deq.bits
311cf7d6b7aSMuzi  assert(
312cf7d6b7aSMuzi    !(priorityFIFO.io.enq.fire ^ prefetchDemux.io.in.fire),
313cf7d6b7aSMuzi    "priorityFIFO.io.enq and io.prefetch_req must fire at the same cycle"
314cf7d6b7aSMuzi  )
315cf7d6b7aSMuzi  assert(
316cf7d6b7aSMuzi    !(priorityFIFO.io.deq.fire ^ prefetchArb.io.out.fire),
317cf7d6b7aSMuzi    "priorityFIFO.io.deq and prefetchArb.io.out must fire at the same cycle"
318cf7d6b7aSMuzi  )
3197052722fSJay
320b92f8445Sssszwic  /**
321b92f8445Sssszwic    ******************************************************************************
322b92f8445Sssszwic    * Tilelink D channel (grant)
323b92f8445Sssszwic    ******************************************************************************
324b92f8445Sssszwic    */
325b92f8445Sssszwic  // cacheline register
326415fcbe2Sxu_zh  private val readBeatCnt = RegInit(UInt(log2Up(refillCycles).W), 0.U)
327415fcbe2Sxu_zh  private val respDataReg = RegInit(VecInit(Seq.fill(refillCycles)(0.U(beatBits.W))))
3281d8f4dcbSJay
329415fcbe2Sxu_zh  private val wait_last = readBeatCnt === (refillCycles - 1).U
330b92f8445Sssszwic  when(io.mem_grant.fire && edge.hasData(io.mem_grant.bits)) {
331b92f8445Sssszwic    respDataReg(readBeatCnt) := io.mem_grant.bits.data
33233a531f0Sxu_zh    readBeatCnt              := Mux(wait_last, 0.U, readBeatCnt + 1.U)
333b92f8445Sssszwic  }
334b92f8445Sssszwic
335415fcbe2Sxu_zh  // last transition finish or corrupt
336415fcbe2Sxu_zh  private val last_fire = io.mem_grant.fire && edge.hasData(io.mem_grant.bits) && wait_last
337b92f8445Sssszwic
338415fcbe2Sxu_zh  private val (_, _, refill_done, _) = edge.addr_inc(io.mem_grant)
339b92f8445Sssszwic  assert(!(refill_done ^ last_fire), "refill not done!")
340b92f8445Sssszwic  io.mem_grant.ready := true.B
341b92f8445Sssszwic
342415fcbe2Sxu_zh  private val last_fire_r = RegNext(last_fire)
343415fcbe2Sxu_zh  private val id_r        = RegNext(io.mem_grant.bits.source)
34433a531f0Sxu_zh
34533a531f0Sxu_zh  // if any beat is corrupt, the whole response (to mainPipe/metaArray/dataArray) is corrupt
346415fcbe2Sxu_zh  private val corrupt_r = RegInit(false.B)
34733a531f0Sxu_zh  when(io.mem_grant.fire && edge.hasData(io.mem_grant.bits) && io.mem_grant.bits.corrupt) {
348ca892e73Sxu_zh    // Set corrupt_r when any beat is corrupt
349ca892e73Sxu_zh    // This is actually when(xxx.fire && xxx.hasData) { corrupt_r := corrupt_r || io.mem_grant.bits.corrupt }
35033a531f0Sxu_zh    corrupt_r := true.B
351ca892e73Sxu_zh  }.elsewhen(last_fire_r) {
352ca892e73Sxu_zh    // Clear corrupt_r when response it sent to mainPipe
353*602b407cSxu_zh    // This used to be io.fetch_resp.valid (last_fire_r && mshr_valid) but when mshr is flushed by io.flush/fencei,
354*602b407cSxu_zh    // mshr_valid is false.B and corrupt_r will never be cleared, that's not correct
355*602b407cSxu_zh    // so we remove mshr_valid here, and the condition leftover is last_fire_r
356*602b407cSxu_zh    // or, actually, io.fetch_resp.valid || (last_fire_r && !mshr_valid)
35733a531f0Sxu_zh    corrupt_r := false.B
35833a531f0Sxu_zh  }
359b92f8445Sssszwic
360b92f8445Sssszwic  /**
361b92f8445Sssszwic    ******************************************************************************
362b92f8445Sssszwic    * invalid mshr when finish transition
363b92f8445Sssszwic    ******************************************************************************
364b92f8445Sssszwic    */
365cf7d6b7aSMuzi  (0 until (nFetchMshr + nPrefetchMshr)).foreach(i => allMSHRs(i).io.invalid := last_fire_r && (id_r === i.U))
366b92f8445Sssszwic
367b92f8445Sssszwic  /**
368b92f8445Sssszwic    ******************************************************************************
369b92f8445Sssszwic    * response fetch and write SRAM
370b92f8445Sssszwic    ******************************************************************************
371b92f8445Sssszwic    */
372b92f8445Sssszwic  // get request information from MSHRs
373415fcbe2Sxu_zh  private val allMSHRs_resp = VecInit(allMSHRs.map(mshr => mshr.io.resp))
374*602b407cSxu_zh  // select MSHR response 1 cycle before sending response to mainPipe/prefetchPipe for better timing
375*602b407cSxu_zh  private val mshr_resp =
376*602b407cSxu_zh    RegEnable(allMSHRs_resp(io.mem_grant.bits.source).bits, 0.U.asTypeOf(allMSHRs_resp(0).bits), last_fire)
377*602b407cSxu_zh  // we can latch mshr.io.resp.bits since they are set on req.fire or acquire.fire, and keeps unchanged during response
378*602b407cSxu_zh  // however, we should not latch mshr.io.resp.valid, since io.flush/fencei may clear it at any time
379*602b407cSxu_zh  private val mshr_valid = allMSHRs_resp(id_r).valid
380b92f8445Sssszwic
381b92f8445Sssszwic  // get waymask from replacer when acquire fire
3827a63335aSxu_zh  io.victim.vSetIdx.valid := acquireArb.io.out.fire
383b92f8445Sssszwic  io.victim.vSetIdx.bits  := acquireArb.io.out.bits.vSetIdx
384*602b407cSxu_zh  private val waymask = UIntToOH(mshr_resp.way)
385adf97c94Sxu_zh  // NOTE: when flush/fencei, missUnit will still send response to mainPipe/prefetchPipe
386adf97c94Sxu_zh  //       this is intentional to fix timing (io.flush -> mainPipe/prefetchPipe s2_miss -> s2_ready -> ftq ready)
387adf97c94Sxu_zh  //       unnecessary response will be dropped by mainPipe/prefetchPipe/wayLookup since their sx_valid is set to false
388*602b407cSxu_zh  private val fetch_resp_valid = mshr_valid && last_fire_r
389adf97c94Sxu_zh  // NOTE: but we should not write meta/dataArray when flush/fencei
390415fcbe2Sxu_zh  private val write_sram_valid = fetch_resp_valid && !corrupt_r && !io.flush && !io.fencei
391b92f8445Sssszwic
392b92f8445Sssszwic  // write SRAM
393cf7d6b7aSMuzi  io.meta_write.bits.generate(
394*602b407cSxu_zh    tag = getPhyTagFromBlk(mshr_resp.blkPaddr),
395*602b407cSxu_zh    idx = mshr_resp.vSetIdx,
396b92f8445Sssszwic    waymask = waymask,
397*602b407cSxu_zh    bankIdx = mshr_resp.vSetIdx(0),
3986c106319Sxu_zh    poison = false.B
399cf7d6b7aSMuzi  )
400cf7d6b7aSMuzi  io.data_write.bits.generate(
401cf7d6b7aSMuzi    data = respDataReg.asUInt,
402*602b407cSxu_zh    idx = mshr_resp.vSetIdx,
403b92f8445Sssszwic    waymask = waymask,
404*602b407cSxu_zh    bankIdx = mshr_resp.vSetIdx(0),
4056c106319Sxu_zh    poison = false.B
406cf7d6b7aSMuzi  )
407b92f8445Sssszwic
408b92f8445Sssszwic  io.meta_write.valid := write_sram_valid
409b92f8445Sssszwic  io.data_write.valid := write_sram_valid
410b92f8445Sssszwic
411b92f8445Sssszwic  // response fetch
412b92f8445Sssszwic  io.fetch_resp.valid         := fetch_resp_valid
413*602b407cSxu_zh  io.fetch_resp.bits.blkPaddr := mshr_resp.blkPaddr
414*602b407cSxu_zh  io.fetch_resp.bits.vSetIdx  := mshr_resp.vSetIdx
415b92f8445Sssszwic  io.fetch_resp.bits.waymask  := waymask
416b92f8445Sssszwic  io.fetch_resp.bits.data     := respDataReg.asUInt
417b92f8445Sssszwic  io.fetch_resp.bits.corrupt  := corrupt_r
418b92f8445Sssszwic
419b92f8445Sssszwic  /**
420b92f8445Sssszwic    ******************************************************************************
421b92f8445Sssszwic    * performance counter
422b92f8445Sssszwic    ******************************************************************************
423b92f8445Sssszwic    */
424b92f8445Sssszwic  // Duplicate requests will be excluded.
425b92f8445Sssszwic  XSPerfAccumulate("enq_fetch_req", fetchDemux.io.in.fire)
426b92f8445Sssszwic  XSPerfAccumulate("enq_prefetch_req", prefetchDemux.io.in.fire)
427b92f8445Sssszwic
428b92f8445Sssszwic  /**
429b92f8445Sssszwic    ******************************************************************************
430b92f8445Sssszwic    * ChiselDB: record ICache SRAM write log
431b92f8445Sssszwic    ******************************************************************************
432b92f8445Sssszwic    */
433415fcbe2Sxu_zh  private class ICacheSRAMDB(implicit p: Parameters) extends ICacheBundle {
434415fcbe2Sxu_zh    val blkPaddr: UInt = UInt((PAddrBits - blockOffBits).W)
435415fcbe2Sxu_zh    val vSetIdx:  UInt = UInt(idxBits.W)
436415fcbe2Sxu_zh    val waymask:  UInt = UInt(wayBits.W)
437b92f8445Sssszwic  }
438b92f8445Sssszwic
439415fcbe2Sxu_zh  private val isWriteICacheSRAMTable =
440cf7d6b7aSMuzi    WireInit(Constantin.createRecord("isWriteICacheSRAMTable" + p(XSCoreParamsKey).HartId.toString))
441415fcbe2Sxu_zh  private val ICacheSRAMTable =
442415fcbe2Sxu_zh    ChiselDB.createTable("ICacheSRAMTable" + p(XSCoreParamsKey).HartId.toString, new ICacheSRAMDB)
443b92f8445Sssszwic
444415fcbe2Sxu_zh  private val ICacheSRAMDBDumpData = Wire(new ICacheSRAMDB)
445*602b407cSxu_zh  ICacheSRAMDBDumpData.blkPaddr := mshr_resp.blkPaddr
446*602b407cSxu_zh  ICacheSRAMDBDumpData.vSetIdx  := mshr_resp.vSetIdx
447b92f8445Sssszwic  ICacheSRAMDBDumpData.waymask  := OHToUInt(waymask)
448b92f8445Sssszwic  ICacheSRAMTable.log(
449b92f8445Sssszwic    data = ICacheSRAMDBDumpData,
450b92f8445Sssszwic    en = write_sram_valid,
451b92f8445Sssszwic    clock = clock,
452b92f8445Sssszwic    reset = reset
453b92f8445Sssszwic  )
454b92f8445Sssszwic
455b92f8445Sssszwic  /**
456b92f8445Sssszwic    ******************************************************************************
457b92f8445Sssszwic    * Difftest
458b92f8445Sssszwic    ******************************************************************************
459b92f8445Sssszwic    */
460afa866b1Sguohongyu  if (env.EnableDifftest) {
461a0c65233SYinan Xu    val difftest = DifftestModule(new DiffRefillEvent, dontCare = true)
4627d45a146SYinan Xu    difftest.coreid := io.hartId
4637d45a146SYinan Xu    difftest.index  := 0.U
464b92f8445Sssszwic    difftest.valid  := write_sram_valid
465*602b407cSxu_zh    difftest.addr   := Cat(mshr_resp.blkPaddr, 0.U(blockOffBits.W))
466b92f8445Sssszwic    difftest.data   := respDataReg.asTypeOf(difftest.data)
467935edac4STang Haojin    difftest.idtfr  := DontCare
46841cb8b61SJenius  }
4691d8f4dcbSJay}
470