xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/IPrefetch.scala (revision 8891a219bbc84f568e1d134854d8d5ed86d6d560)
17052722fSJay/***************************************************************************************
27052722fSJay  * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
37052722fSJay  * Copyright (c) 2020-2021 Peng Cheng Laboratory
47052722fSJay  *
57052722fSJay  * XiangShan is licensed under Mulan PSL v2.
67052722fSJay  * You can use this software according to the terms and conditions of the Mulan PSL v2.
77052722fSJay  * You may obtain a copy of Mulan PSL v2 at:
87052722fSJay  *          http://license.coscl.org.cn/MulanPSL2
97052722fSJay  *
107052722fSJay  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
117052722fSJay  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
127052722fSJay  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
137052722fSJay  *
147052722fSJay  * See the Mulan PSL v2 for more details.
157052722fSJay  ***************************************************************************************/
167052722fSJay
177052722fSJaypackage xiangshan.frontend.icache
187052722fSJay
19*8891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
207052722fSJayimport chisel3._
217052722fSJayimport chisel3.util._
227d45a146SYinan Xuimport difftest._
237052722fSJayimport freechips.rocketchip.tilelink._
247052722fSJayimport utils._
257052722fSJayimport xiangshan.cache.mmu._
267052722fSJayimport xiangshan.frontend._
27d2b20d1aSTang Haojinimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
28d2b20d1aSTang Haojinimport huancun.PreferCacheKey
29b92c5693STang Haojinimport xiangshan.XSCoreParamsKey
30b1ded4e8Sguohongyuimport utility._
317052722fSJay
327052722fSJay
337052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle
347052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule
357052722fSJay
36b1ded4e8Sguohongyu//TODO: remove this
37b1ded4e8Sguohongyuobject DebugFlags {
38b1ded4e8Sguohongyu  val fdip = false
397052722fSJay}
407052722fSJay
41b1ded4e8Sguohongyuclass PIQData(implicit p: Parameters) extends IPrefetchBundle {
42b1ded4e8Sguohongyu  val ptage = UInt(tagBits.W)
43b1ded4e8Sguohongyu  val vSetIdx = UInt(idxBits.W)
44b1ded4e8Sguohongyu  val cacheline = UInt(blockBits.W)
45b1ded4e8Sguohongyu  val writeBack = Bool()
46b1ded4e8Sguohongyu}
47b1ded4e8Sguohongyu
48b1ded4e8Sguohongyuclass PIQToMainPipe(implicit  p: Parameters) extends IPrefetchBundle{
49b1ded4e8Sguohongyu  val info = DecoupledIO(new PIQData)
50b1ded4e8Sguohongyu}
51b1ded4e8Sguohongyu/* need change name */
52cb6e5d3cSssszwicclass MainPipeMissInfo(implicit p: Parameters) extends IPrefetchBundle {
53b1ded4e8Sguohongyu  val ptage = UInt(tagBits.W)
54b1ded4e8Sguohongyu  val vSetIdx = UInt(idxBits.W)
55b1ded4e8Sguohongyu}
56b1ded4e8Sguohongyu
57cb6e5d3cSssszwicclass PrefetchReq(implicit  p: Parameters) extends IPrefetchBundle{
58cb6e5d3cSssszwic  val paddr     = UInt(PAddrBits.W)
59cb6e5d3cSssszwic  val vSetIdx   = UInt(idxBits.W)
60b1ded4e8Sguohongyu}
617052722fSJay
62cb6e5d3cSssszwicclass PrefetchBufferIO(implicit p: Parameters) extends IPrefetchBundle {
63cb6e5d3cSssszwic  val hartId = Input(UInt(8.W))
64b1ded4e8Sguohongyu  val fencei = Input(Bool())
65cb6e5d3cSssszwic  val IPFFilterRead   = new IPFBufferFilterRead
66cb6e5d3cSssszwic  val IPFBufferRead   = new IPFBufferRead
67cb6e5d3cSssszwic  val IPFBufferWrite  = Flipped(DecoupledIO(new IPFBufferWrite))
68cb6e5d3cSssszwic  val metaWrite       = DecoupledIO(new ICacheMetaWriteBundle)
69cb6e5d3cSssszwic  val dataWrite       = DecoupledIO(new ICacheDataWriteBundle)
70cb6e5d3cSssszwic  val IPFReplacer     = new IPFReplacer
71b1ded4e8Sguohongyu}
72b1ded4e8Sguohongyu
73b1ded4e8Sguohongyuclass PrefetchBuffer(implicit p: Parameters) extends IPrefetchModule
74b1ded4e8Sguohongyu{
75cb6e5d3cSssszwic  val io = IO(new PrefetchBufferIO)
76cb6e5d3cSssszwic
77cb6e5d3cSssszwic  val fromIPrefetch = io.IPFFilterRead.req
78cb6e5d3cSssszwic  val toIPrefetch   = io.IPFFilterRead.resp
79cb6e5d3cSssszwic  val fromMainPipe  = io.IPFBufferRead.req
80cb6e5d3cSssszwic  val toMainPipe    = io.IPFBufferRead.resp
81cb6e5d3cSssszwic  val fromPIQ       = io.IPFBufferWrite
82cb6e5d3cSssszwic  val toICacheMeta  = io.metaWrite
83cb6e5d3cSssszwic  val toICacheData  = io.dataWrite
84cb6e5d3cSssszwic  val fromReplacer  = io.IPFReplacer
85b1ded4e8Sguohongyu
86b1ded4e8Sguohongyu  class IPFBufferEntryMeta(implicit p: Parameters) extends IPrefetchBundle
87b1ded4e8Sguohongyu  {
88b1ded4e8Sguohongyu    val valid         = Bool()
89cb6e5d3cSssszwic    val paddr         = UInt(PAddrBits.W)
90cb6e5d3cSssszwic    val vSetIdx       = UInt(idxBits.W)
91b1ded4e8Sguohongyu    val confidence    = UInt(log2Ceil(maxIPFMoveConf + 1).W)
92b1ded4e8Sguohongyu  }
93b1ded4e8Sguohongyu
94b1ded4e8Sguohongyu  class IPFBufferEntryData(implicit p: Parameters) extends IPrefetchBundle
95b1ded4e8Sguohongyu  {
96cb6e5d3cSssszwic    val cacheline = UInt(blockBits.W)
97b1ded4e8Sguohongyu  }
98b1ded4e8Sguohongyu
99b1ded4e8Sguohongyu  def InitQueue[T <: Data](entry: T, size: Int): Vec[T] ={
100b1ded4e8Sguohongyu    return RegInit(VecInit(Seq.fill(size)(0.U.asTypeOf(entry.cloneType))))
101b1ded4e8Sguohongyu  }
102b1ded4e8Sguohongyu
103b1ded4e8Sguohongyu  val meta_buffer = InitQueue(new IPFBufferEntryMeta, size = nIPFBufferSize)
104b1ded4e8Sguohongyu  val data_buffer = InitQueue(new IPFBufferEntryData, size = nIPFBufferSize)
105b1ded4e8Sguohongyu
106cb6e5d3cSssszwic  /**
107cb6e5d3cSssszwic    ******************************************************************************
108cb6e5d3cSssszwic    * handle look-up request from IPrefetchPipe
109cb6e5d3cSssszwic    * - 1. Receive request from IPrefetch
110cb6e5d3cSssszwic    * - 2. Look up whether hit in meta_buffer
111cb6e5d3cSssszwic    * - 3. Send response to IPrefetch at the same cycle
112cb6e5d3cSssszwic    ******************************************************************************
113cb6e5d3cSssszwic    */
114cb6e5d3cSssszwic  val fr_block  = get_block(fromIPrefetch.paddr)
115cb6e5d3cSssszwic  val fr_hit_oh = meta_buffer.map(e => e.valid && (get_block(e.paddr) === fr_block))
116cb6e5d3cSssszwic  toIPrefetch.ipf_hit := ParallelOR(fr_hit_oh)
117cb6e5d3cSssszwic  // only hit one entry in meta_buffer at the same time
118cb6e5d3cSssszwic  assert(PopCount(fr_hit_oh) <= 1.U, "More than 1 hit in L1 prefetch buffer for filter")
11964d7d412Sguohongyu
120cb6e5d3cSssszwic  /**
121cb6e5d3cSssszwic    ******************************************************************************
122cb6e5d3cSssszwic    * handle read request from ICacheMainPipe
123cb6e5d3cSssszwic    * - 1. Receive request from ICacheMainPipe
124cb6e5d3cSssszwic    * - 2. Look up whether hit in meta_buffer and get hitted data
125cb6e5d3cSssszwic    * - 3. Send response to ICacheMainPipe at the same cycle
126cb6e5d3cSssszwic    ******************************************************************************
127cb6e5d3cSssszwic    */
128cb6e5d3cSssszwic  fromMainPipe.foreach(_.ready := DontCare)
129cb6e5d3cSssszwic  val r_blocks      = fromMainPipe.map (e => get_block(e.bits.paddr))
130cb6e5d3cSssszwic  val r_hit_oh      = r_blocks.map (ptag => meta_buffer.map(e => e.valid && (get_block(e.paddr) === ptag)))
131cb6e5d3cSssszwic  val curr_hit_ptr  = r_hit_oh.map (OHToUInt(_))
132cb6e5d3cSssszwic  val r_hit_data    = r_hit_oh.map (oh => Mux1H(oh, data_buffer.map(_.cacheline)))
133cb6e5d3cSssszwic  val r_hit         = (0 until PortNumber).map (i => ParallelOR(r_hit_oh(i)) && fromMainPipe(i).valid)
134cb6e5d3cSssszwic  (0 until PortNumber).foreach (i => {
135cb6e5d3cSssszwic    toMainPipe(i).ipf_hit   := r_hit(i)
136cb6e5d3cSssszwic    toMainPipe(i).cacheline := r_hit_data(i)
137cb6e5d3cSssszwic    // only hit one entry in meta_buffer
138cb6e5d3cSssszwic    assert(PopCount(r_hit_oh(i)) <= 1.U, "More than 1 hit in L1 prefetch buffer")
139cb6e5d3cSssszwic    XSPerfAccumulate("fdip_mainpipe_hit_in_ipf_" + i, r_hit(i))
140cb6e5d3cSssszwic  })
141d4112e88Sguohongyu
142d4112e88Sguohongyu
143cb6e5d3cSssszwic  /**
144cb6e5d3cSssszwic    ******************************************************************************
145cb6e5d3cSssszwic    * move the entry arriving max confidence to icache
146cb6e5d3cSssszwic    * - 1. Chose a moved entry from the entries that reach max confidence (LSB first)
147cb6e5d3cSssszwic    * - 2. Get victim way of array from replacer of ICacheMainPipe
148cb6e5d3cSssszwic    * - 3. Send write req to metaArray and dataArray and ensure fire together
149cb6e5d3cSssszwic    ******************************************************************************
150cb6e5d3cSssszwic    */
151cb6e5d3cSssszwic  val move_oh   = meta_buffer.map (e => e.confidence === maxIPFMoveConf.U && e.valid)
152cb6e5d3cSssszwic  val move_need = ParallelOR(move_oh)
153cb6e5d3cSssszwic  val curr_move_ptr  = PriorityEncoder(move_oh)
154b1ded4e8Sguohongyu
155cb6e5d3cSssszwic  fromReplacer.vsetIdx := meta_buffer(curr_move_ptr).vSetIdx
156b1ded4e8Sguohongyu
157cb6e5d3cSssszwic  toICacheMeta.valid := move_need
158cb6e5d3cSssszwic  toICacheMeta.bits.generate(
159cb6e5d3cSssszwic    tag     = get_phy_tag(meta_buffer(curr_move_ptr).paddr),
160cb6e5d3cSssszwic    idx     = meta_buffer(curr_move_ptr).vSetIdx,
161cb6e5d3cSssszwic    waymask = fromReplacer.waymask,
162cb6e5d3cSssszwic    bankIdx = meta_buffer(curr_move_ptr).vSetIdx(0))
163b1ded4e8Sguohongyu
164cb6e5d3cSssszwic  toICacheData.valid := move_need
165cb6e5d3cSssszwic  toICacheData.bits.generate(
166cb6e5d3cSssszwic    data    = data_buffer(curr_move_ptr).cacheline,
167cb6e5d3cSssszwic    idx     = meta_buffer(curr_move_ptr).vSetIdx,
168cb6e5d3cSssszwic    waymask = fromReplacer.waymask,
169cb6e5d3cSssszwic    bankIdx = meta_buffer(curr_move_ptr).vSetIdx(0),
170cb6e5d3cSssszwic    paddr   = meta_buffer(curr_move_ptr).paddr)
171b1ded4e8Sguohongyu
172cb6e5d3cSssszwic  // TODO: how to ensure
173cb6e5d3cSssszwic  assert((toICacheMeta.fire && toICacheData.fire) || (!toICacheMeta.fire && !toICacheData.fire),
174b1ded4e8Sguohongyu    "meta and data array need fire at same time")
175b1ded4e8Sguohongyu
176cb6e5d3cSssszwic  XSPerfAccumulate("fdip_move_to_icache", toICacheMeta.fire && toICacheData.fire)
177cb6e5d3cSssszwic
178cb6e5d3cSssszwic  when(toICacheMeta.fire) {
179cb6e5d3cSssszwic    XSDebug(p"PrefetchBuffer: write prefetch data to icache . vSetIdx:${meta_buffer(curr_move_ptr).vSetIdx} " +
180cb6e5d3cSssszwic            p"paddr:${meta_buffer(curr_move_ptr).paddr}")
181cb6e5d3cSssszwic  }
182cb6e5d3cSssszwic
183cb6e5d3cSssszwic  /**
184cb6e5d3cSssszwic    ******************************************************************************
185cb6e5d3cSssszwic    * Prefetch buffer write logic
186cb6e5d3cSssszwic    * Read old data when read and write occur in the same cycle
187cb6e5d3cSssszwic    * There are 4 situations that can cause meta_buffer and data_buffer to be written
188cb6e5d3cSssszwic    * - 1. ICacheMainPipe read hit that need to change some status
189cb6e5d3cSssszwic    * - 2. Move prefetch cacheline to icache
190cb6e5d3cSssszwic    * - 3. Receive write request from ICacheMissUnit
191cb6e5d3cSssszwic    * - 4. Receive fencei req that need to flush all buffer
192cb6e5d3cSssszwic    * Priority: 4 > 3 > 2 > 1
193cb6e5d3cSssszwic    * The order of the code determines the priority, with the following priority being higher
194cb6e5d3cSssszwic    ******************************************************************************
195cb6e5d3cSssszwic    */
196cb6e5d3cSssszwic
197cb6e5d3cSssszwic  /** 1. confidence++ for every ICacheMainPipe hit */
198cb6e5d3cSssszwic  (0 until PortNumber) .map (i =>
199cb6e5d3cSssszwic    when(r_hit(i)) {
200cb6e5d3cSssszwic      // handle overflow
201cb6e5d3cSssszwic      when(meta_buffer(curr_hit_ptr(i)).confidence =/= maxIPFMoveConf.U) {
202cb6e5d3cSssszwic        meta_buffer(curr_hit_ptr(i)).confidence := meta_buffer(curr_hit_ptr(i)).confidence + 1.U
203cb6e5d3cSssszwic      }
204cb6e5d3cSssszwic    }
205cb6e5d3cSssszwic  )
206cb6e5d3cSssszwic
207cb6e5d3cSssszwic  /** 2. set entry invalid after move to icache */
208cb6e5d3cSssszwic  when(toICacheMeta.fire) {
209cb6e5d3cSssszwic    meta_buffer(curr_move_ptr).valid := false.B
210cb6e5d3cSssszwic  }
211cb6e5d3cSssszwic
212cb6e5d3cSssszwic  /** 3. write prefetch data to entry */
213cb6e5d3cSssszwic  // try to get a free entry ptr
214cb6e5d3cSssszwic  val free_oh       = meta_buffer.map (_.valid === false.B)
215cb6e5d3cSssszwic  val has_free      = ParallelOR(free_oh)
216cb6e5d3cSssszwic  val ptr_from_free = PriorityEncoder(free_oh)
217cb6e5d3cSssszwic  // get a ptr from random replacement policy
218cb6e5d3cSssszwic  val replacer = ReplacementPolicy.fromString(Some("random"), nIPFBufferSize)
219cb6e5d3cSssszwic  // write to free entry if has, otherwise random entry
220cb6e5d3cSssszwic  val curr_write_ptr = Mux(has_free, ptr_from_free, replacer.way)
221cb6e5d3cSssszwic  fromPIQ.ready := DontCare
222cb6e5d3cSssszwic  when(fromPIQ.valid) {
223cb6e5d3cSssszwic    meta_buffer(curr_write_ptr).valid         := true.B
224cb6e5d3cSssszwic    meta_buffer(curr_write_ptr).confidence    := fromPIQ.bits.has_hit.asUInt
225cb6e5d3cSssszwic    meta_buffer(curr_write_ptr).paddr         := fromPIQ.bits.paddr
226cb6e5d3cSssszwic    meta_buffer(curr_write_ptr).vSetIdx       := fromPIQ.bits.vSetIdx
227cb6e5d3cSssszwic    data_buffer(curr_write_ptr).cacheline     := fromPIQ.bits.cacheline
228cb6e5d3cSssszwic  }
229b1ded4e8Sguohongyu
230b1ded4e8Sguohongyu  if(DebugFlags.fdip) {
231cb6e5d3cSssszwic    when(fromPIQ.valid) {
232cb6e5d3cSssszwic      printf(p"PrefetchBuffer: receive prefetch data. vSetIdx:${fromPIQ.bits.vSetIdx} paddr:${fromPIQ.bits.paddr}")
233b1ded4e8Sguohongyu    }
234b1ded4e8Sguohongyu  }
235b1ded4e8Sguohongyu
236cb6e5d3cSssszwic  XSPerfAccumulate("fdip_vitcm_used",     !has_free && fromPIQ.valid && (meta_buffer(curr_write_ptr).confidence =/= 0.U))
237cb6e5d3cSssszwic  XSPerfAccumulate("fdip_vitcm_no_used",  !has_free && fromPIQ.valid && (meta_buffer(curr_write_ptr).confidence === 0.U))
238cb6e5d3cSssszwic
239cb6e5d3cSssszwic  /** 4. flush all prefetch buffer when fencei */
240cb6e5d3cSssszwic  when(io.fencei) {
241cb6e5d3cSssszwic    meta_buffer.foreach { b =>
242cb6e5d3cSssszwic      b.valid         := false.B
243cb6e5d3cSssszwic      b.confidence    := 0.U
244cb6e5d3cSssszwic    }
245cb6e5d3cSssszwic  }
246cb6e5d3cSssszwic
247cb6e5d3cSssszwic  XSPerfAccumulate("fdip_fencei_cycle", io.fencei)
248cb6e5d3cSssszwic
249afa866b1Sguohongyu  if (env.EnableDifftest) {
250a0c65233SYinan Xu    val difftest = DifftestModule(new DiffRefillEvent, dontCare = true)
2517d45a146SYinan Xu    difftest.coreid  := io.hartId
2527d45a146SYinan Xu    difftest.index   := 6.U
2537d45a146SYinan Xu    difftest.valid   := toICacheData.fire
2547d45a146SYinan Xu    difftest.addr    := toICacheData.bits.paddr
2557d45a146SYinan Xu    difftest.data    := toICacheData.bits.data.asTypeOf(difftest.data)
256935edac4STang Haojin    difftest.idtfr   := DontCare
25764d7d412Sguohongyu  }
25864d7d412Sguohongyu}
259b1ded4e8Sguohongyu
260cb6e5d3cSssszwicclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle {
261cb6e5d3cSssszwic  val ftqReq            = Flipped(new FtqPrefechBundle)
262cb6e5d3cSssszwic  val iTLBInter         = new TlbRequestIO
263cb6e5d3cSssszwic  val pmp               = new ICachePMPBundle
264cb6e5d3cSssszwic  val metaReadReq       = Decoupled(new ICacheMetaReadReqBundle)
265cb6e5d3cSssszwic  val metaReadResp      = Input(new ICacheMetaReadRespBundle)
266cb6e5d3cSssszwic  val prefetchReq       = DecoupledIO(new PrefetchReq)
267cb6e5d3cSssszwic  val mshrInfo          = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W))))
268cb6e5d3cSssszwic  val IPFFilterRead     = Flipped(new IPFBufferFilterRead)
269cb6e5d3cSssszwic  val PIQFilterRead     = Flipped(new PIQFilterRead)
270cb6e5d3cSssszwic  /** icache main pipe to prefetch pipe */
271cb6e5d3cSssszwic  val mainPipeMissInfo  = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo)))
272cb6e5d3cSssszwic  val fencei            = Input(Bool())
2737052722fSJay}
2747052722fSJay
2757052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends  IPrefetchModule
2767052722fSJay{
2777052722fSJay  val io = IO(new IPredfetchIO)
2787052722fSJay
279a108d429SJay  val enableBit = RegInit(false.B)
280cb6e5d3cSssszwic  enableBit := false.B
281a108d429SJay
282cb6e5d3cSssszwic  val fromFtq = io.ftqReq
283cb6e5d3cSssszwic  val mainPipeMissInfo = io.mainPipeMissInfo
2847052722fSJay  val (toITLB,  fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp)
285cb6e5d3cSssszwic  val (toIMeta, fromIMeta, fromIMetaValid) = (io.metaReadReq, io.metaReadResp.metaData, io.metaReadResp.entryValid)
286cb6e5d3cSssszwic  val (toIPFBuffer, fromIPFBuffer) = (io.IPFFilterRead.req, io.IPFFilterRead.resp)
287cb6e5d3cSssszwic  val (toPIQ, fromPIQ) = (io.PIQFilterRead.req, io.PIQFilterRead.resp)
2887052722fSJay  val (toPMP,  fromPMP)   = (io.pmp.req, io.pmp.resp)
289cb6e5d3cSssszwic  val fromMSHR = io.mshrInfo
290cb6e5d3cSssszwic  val toPIQEnqReq = io.prefetchReq
2917052722fSJay
292cb6e5d3cSssszwic  val p0_fire, p1_fire, p2_fire           = WireInit(false.B)
293cb6e5d3cSssszwic  val p0_discard, p1_discard, p2_discard  = WireInit(false.B)
294cb6e5d3cSssszwic  val p0_ready, p1_ready, p2_ready        = WireInit(false.B)
2957052722fSJay
296cb6e5d3cSssszwic  /**
297cb6e5d3cSssszwic    ******************************************************************************
298cb6e5d3cSssszwic    * IPrefetch Stage 0
299cb6e5d3cSssszwic    * - 1. send req to IMeta
300cb6e5d3cSssszwic    * - 2. send req to ITLB (no blocked)
301cb6e5d3cSssszwic    * - 3. check last req
302cb6e5d3cSssszwic    ******************************************************************************
303cb6e5d3cSssszwic    */
3047052722fSJay  val p0_valid  = fromFtq.req.valid
305cb6e5d3cSssszwic
306d6b06a99SJay  val p0_vaddr  = addrAlign(fromFtq.req.bits.target, blockBytes, VAddrBits)
307cb6e5d3cSssszwic  val p0_vaddr_reg = RegEnable(p0_vaddr, p0_fire)
308cb6e5d3cSssszwic  val p0_req_cancel = Wire(Bool())
3097052722fSJay
310cb6e5d3cSssszwic  /** 1. send req to IMeta */
3119bba777eSssszwic  toIMeta.valid     := p0_valid && !p0_req_cancel
3120c26d810Sguohongyu  toIMeta.bits.idx  := get_idx(p0_vaddr)
3137052722fSJay
314cb6e5d3cSssszwic  /** 2. send req to ITLB (no blocked) */
3159bba777eSssszwic  toITLB.valid                    := p0_valid && !p0_req_cancel
3167052722fSJay  toITLB.bits.size                := 3.U // TODO: fix the size
3177052722fSJay  toITLB.bits.vaddr               := p0_vaddr
3187052722fSJay  toITLB.bits.debug.pc            := p0_vaddr
319f1fe8698SLemover  toITLB.bits.kill                := DontCare
3207052722fSJay  toITLB.bits.cmd                 := TlbCmd.exec
321f1fe8698SLemover  toITLB.bits.debug.robIdx        := DontCare
3227052722fSJay  toITLB.bits.debug.isFirstIssue  := DontCare
323b1ded4e8Sguohongyu  toITLB.bits.memidx              := DontCare
324b1ded4e8Sguohongyu  toITLB.bits.no_translate        := false.B
3257052722fSJay  fromITLB.ready                  := true.B
326cb6e5d3cSssszwic  // TODO: whether to handle tlb miss for prefetch
327cb6e5d3cSssszwic  io.iTLBInter.req_kill           := false.B
3287052722fSJay
329cb6e5d3cSssszwic  /** FTQ request port */
330cb6e5d3cSssszwic  fromFtq.req.ready := p0_ready
3317052722fSJay
332cb6e5d3cSssszwic  /** 3. Check last req: request from FTQ is same as last time or behind */
333cb6e5d3cSssszwic  val p0_hit_behind = Wire(Bool())
334cb6e5d3cSssszwic
335cb6e5d3cSssszwic  /** stage 0 control */
336cb6e5d3cSssszwic  // Cancel request when prefetch not enable or the request from FTQ is same as last time
337cb6e5d3cSssszwic  p0_req_cancel := !enableBit || p0_hit_behind || io.fencei
338cb6e5d3cSssszwic  p0_ready      := p0_req_cancel || p1_ready && toITLB.ready && toIMeta.ready
339cb6e5d3cSssszwic  p0_fire       := p0_valid && p1_ready && toITLB.ready && toIMeta.ready && enableBit && !p0_req_cancel
340cb6e5d3cSssszwic  p0_discard    := p0_valid && p0_req_cancel
341cb6e5d3cSssszwic
342cb6e5d3cSssszwic  if(DebugFlags.fdip) {
343cb6e5d3cSssszwic    when(p0_discard) {
344cb6e5d3cSssszwic      printf(p"IPrefetchPipe: discard req in s0.")
345cb6e5d3cSssszwic    }
346cb6e5d3cSssszwic  }
347cb6e5d3cSssszwic
348cb6e5d3cSssszwic  /**
349cb6e5d3cSssszwic    ******************************************************************************
350cb6e5d3cSssszwic    * IPrefetch Stage 1
351cb6e5d3cSssszwic    * - 1. Receive resp from ITLB (no blocked)
352cb6e5d3cSssszwic    * - 2. Receive resp from IMeta
353cb6e5d3cSssszwic    * - 3. Check MSHR
354cb6e5d3cSssszwic    ******************************************************************************
355cb6e5d3cSssszwic    */
3567052722fSJay  val p1_valid  = generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B)
357cb6e5d3cSssszwic
358005e809bSJiuyang Liu  val p1_vaddr      = RegEnable(p0_vaddr, p0_fire)
359cb6e5d3cSssszwic  val p1_req_cancel = Wire(Bool())
3607052722fSJay
361cb6e5d3cSssszwic  /** 1. Receive resp from ITLB (no blocked) */
362cb6e5d3cSssszwic  val p1_tlb_resp_miss  = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.miss)
363cb6e5d3cSssszwic  val p1_tlb_resp_paddr = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.paddr(0))
364cb6e5d3cSssszwic  val p1_tlb_resp_pf    = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).pf.instr)
365cb6e5d3cSssszwic  val p1_tlb_resp_af    = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).af.instr)
366cb6e5d3cSssszwic  val p1_exception      = VecInit(Seq(p1_tlb_resp_pf, p1_tlb_resp_af))
3677052722fSJay  val p1_has_except     = p1_exception.reduce(_ || _)
368cb6e5d3cSssszwic  val p1_paddr          = p1_tlb_resp_paddr
3697052722fSJay
370cb6e5d3cSssszwic  /** 2. Receive resp from IMeta. Register the data first because of strict timing. */
3719bba777eSssszwic  val p1_meta_ptags_reg   = RegEnable(VecInit(fromIMeta.map(way => way.tag)), RegNext(p0_fire))
3729bba777eSssszwic  val p1_meta_valids_reg  = RegEnable(fromIMetaValid, RegNext(p0_fire))
3737052722fSJay
374cb6e5d3cSssszwic  /** 3. Check MSHR */
375cb6e5d3cSssszwic  val p1_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p1_paddr, blockBytes, PAddrBits))).reduce(_||_)
376b1ded4e8Sguohongyu
377cb6e5d3cSssszwic  /** Stage 1 control */
378cb6e5d3cSssszwic  p1_req_cancel := p1_check_in_mshr || p1_tlb_resp_miss || p1_has_except || io.fencei
3799bba777eSssszwic  p1_ready      := p1_valid && p2_ready || !p1_valid
3809bba777eSssszwic  p1_fire       := p1_valid && !p1_req_cancel && p2_ready && enableBit
3819bba777eSssszwic  p1_discard    := p1_valid && p1_req_cancel
3827052722fSJay
383cb6e5d3cSssszwic  when(p1_discard) {
384cb6e5d3cSssszwic    XSDebug(p"IPrefetchPipe: discard req in s1. vaddr:${p1_vaddr}")
385cb6e5d3cSssszwic  }
386cb6e5d3cSssszwic
387cb6e5d3cSssszwic  /**
388cb6e5d3cSssszwic    ******************************************************************************
389cb6e5d3cSssszwic    * IPrefetch Stage 2
390cb6e5d3cSssszwic    * - 1. IMeta Check: check whether req hit in icache
391cb6e5d3cSssszwic    * - 2. PMP Check: send req and receive resq in the same cycle
392cb6e5d3cSssszwic    * - 3. Check miss handling by main pipe
393cb6e5d3cSssszwic    * - 4. Prefetch buffer Check
394cb6e5d3cSssszwic    * - 5. Prefetch Queue Check
395cb6e5d3cSssszwic    * - 6. MSHR check
396cb6e5d3cSssszwic    * - 7. send req to piq
397cb6e5d3cSssszwic    ******************************************************************************
398cb6e5d3cSssszwic    */
3997052722fSJay  val p2_valid  = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B)
400cb6e5d3cSssszwic
4019bba777eSssszwic  val p2_paddr      = RegEnable(p1_paddr, p1_fire)
4029bba777eSssszwic  val p2_vaddr      = RegEnable(p1_vaddr, p1_fire)
403cb6e5d3cSssszwic  val p2_req_cancel = Wire(Bool())
404cb6e5d3cSssszwic  val p2_vidx       = get_idx(p2_vaddr)
4059bba777eSssszwic
406cb6e5d3cSssszwic  p0_hit_behind := (p0_vaddr === p1_vaddr) || (p0_vaddr === p2_vaddr)
407cb6e5d3cSssszwic
408cb6e5d3cSssszwic  /** 1. IMeta Check */
4099bba777eSssszwic  val p2_ptag           = get_phy_tag(p2_paddr)
4109bba777eSssszwic  val p2_tag_eq_vec     = VecInit(p1_meta_ptags_reg.map(_  ===  p2_ptag ))
4119bba777eSssszwic  val p2_tag_match_vec  = VecInit(p2_tag_eq_vec.zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && p1_meta_valids_reg(w)})
4129bba777eSssszwic  val p2_tag_match      = DataHoldBypass(ParallelOR(p2_tag_match_vec), RegNext(p1_fire))
4139bba777eSssszwic
414cb6e5d3cSssszwic  /** 2. PMP Check */
415cb6e5d3cSssszwic  // TODO: When fromPMP.mmio is low but fromPMP.instr is high, which is a except?
416cb6e5d3cSssszwic  val p2_exception  = DataHoldBypass((fromPMP.mmio && !fromPMP.instr) || fromPMP.instr, RegNext(p1_fire))
417cb6e5d3cSssszwic  // PMP request
418cb6e5d3cSssszwic  toPMP.valid     := p2_valid
4199bba777eSssszwic  toPMP.bits.addr := p2_paddr
4209bba777eSssszwic  toPMP.bits.size := 3.U
4219bba777eSssszwic  toPMP.bits.cmd  := TlbCmd.exec
422b1ded4e8Sguohongyu
423cb6e5d3cSssszwic  /** 3. Check miss handling by main pipe */
424cb6e5d3cSssszwic  val p2_hit_mp_miss = VecInit((0 until PortNumber).map(i =>
425cb6e5d3cSssszwic    mainPipeMissInfo(i).valid && (mainPipeMissInfo(i).bits.ptage === p2_ptag &&
426cb6e5d3cSssszwic    (mainPipeMissInfo(i).bits.vSetIdx === p2_vidx)))).reduce(_||_)
42700240ba6SJay
428cb6e5d3cSssszwic  /** 4. Prefetch buffer Check */
429cb6e5d3cSssszwic  toIPFBuffer.paddr := p2_paddr
430cb6e5d3cSssszwic  val p2_hit_buffer = fromIPFBuffer.ipf_hit
431cb6e5d3cSssszwic
432cb6e5d3cSssszwic  /** 5. Prefetch Queue Check */
433cb6e5d3cSssszwic  toPIQ.paddr := p2_paddr
434cb6e5d3cSssszwic  val p2_hit_piq = fromPIQ.piq_hit
435cb6e5d3cSssszwic
436cb6e5d3cSssszwic  /** 6. MSHR check */
437cb6e5d3cSssszwic  val p2_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p2_paddr, blockBytes, PAddrBits))).reduce(_||_)
438cb6e5d3cSssszwic
439cb6e5d3cSssszwic  /** 7. send req to piq */
440cb6e5d3cSssszwic  toPIQEnqReq.valid := p2_valid && !p2_req_cancel
441cb6e5d3cSssszwic  toPIQEnqReq.bits.paddr := p2_paddr
442cb6e5d3cSssszwic  toPIQEnqReq.bits.vSetIdx := p2_vidx
443cb6e5d3cSssszwic
444cb6e5d3cSssszwic  /** Stage 2 control */
445cb6e5d3cSssszwic  p2_req_cancel := p2_tag_match || p2_exception || p2_hit_mp_miss || p2_hit_buffer || p2_hit_piq || p2_check_in_mshr || io.fencei
446cb6e5d3cSssszwic  p2_ready      := p2_valid && toPIQEnqReq.ready || !p2_valid
447935edac4STang Haojin  p2_fire       := toPIQEnqReq.fire
4489bba777eSssszwic  p2_discard    := p2_valid && p2_req_cancel
449b1ded4e8Sguohongyu
450cb6e5d3cSssszwic  when(p2_discard) {
451cb6e5d3cSssszwic    XSDebug(p"IPrefetchPipe: discard req in s2. vaddr:${p2_vaddr}")
452cb6e5d3cSssszwic  }
4539bba777eSssszwic
454cb6e5d3cSssszwic  when(p2_fire) {
455cb6e5d3cSssszwic    XSDebug(p"IPrefetchPipe: send req to PIQ. vaddr:${p2_vaddr} paddr:${p2_paddr}")
456cb6e5d3cSssszwic  }
4579bba777eSssszwic
458cb6e5d3cSssszwic  /** PerfAccumulate */
459cb6e5d3cSssszwic  // the number of prefetch request received from ftq
460935edac4STang Haojin  XSPerfAccumulate("prefetch_req_receive", fromFtq.req.fire)
461cb6e5d3cSssszwic  // the number of prefetch request sent to PIQ
462935edac4STang Haojin  XSPerfAccumulate("prefetch_req_send", toPIQEnqReq.fire)
463cb6e5d3cSssszwic  /**
464cb6e5d3cSssszwic    * Count the number of requests that are filtered for various reasons.
465cb6e5d3cSssszwic    * The number of prefetch discard in Performance Accumulator may be
466cb6e5d3cSssszwic    * a littel larger the number of really discarded. Because there can
467cb6e5d3cSssszwic    * be multiple reasons for a canceled request at the same time.
468cb6e5d3cSssszwic    */
469cb6e5d3cSssszwic  // discard prefetch request by fencei instruction
470cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_fencei",      (p0_discard || p1_discard || p2_discard) && io.fencei)
471cb6e5d3cSssszwic  // discard prefetch request by hit hit MSHR
472cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_mshr",        (p1_discard && p1_check_in_mshr) || (p2_discard && p2_check_in_mshr))
473cb6e5d3cSssszwic  // discard prefetch request by the request is same as pipeline behind
474cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_behind",      p0_discard && p0_hit_behind)
475cb6e5d3cSssszwic  // discard prefetch request by tlb miss
476cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_tlb_miss",    p1_discard && p1_tlb_resp_miss)
477cb6e5d3cSssszwic  // discard prefetch request by tlb except
478cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_tlb_except",  p1_discard && p1_has_except)
479cb6e5d3cSssszwic  // discard prefetch request by hit icache
480cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_hit_cache",   p2_discard && p2_tag_match)
481cb6e5d3cSssszwic  // discard prefetch request by pmp except or mmio
482cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_pmp",         p2_discard && p2_exception)
483cb6e5d3cSssszwic  // discard prefetch request by req is handling by icache mainpipe
484cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_hit_mp",      p2_discard && p2_hit_mp_miss)
485cb6e5d3cSssszwic  // discard prefetch request by hit in prefetch buffer
486cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_hit_pf",      p2_discard && p2_hit_buffer)
487cb6e5d3cSssszwic  // discard prefetch request by hit in prefetch queue
488cb6e5d3cSssszwic  XSPerfAccumulate("fdip_prefetch_discard_by_hit_piq",     p2_discard && p2_hit_piq)
489cb6e5d3cSssszwic}
4907052722fSJay
491cb6e5d3cSssszwic// class PIQEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends IPrefetchModule
492cb6e5d3cSssszwic// {
493cb6e5d3cSssszwic//   val io = IO(new Bundle{
494cb6e5d3cSssszwic//     val id          = Input(UInt((log2Ceil(nPrefetchEntries + PortNumber)).W))
4959bba777eSssszwic
496cb6e5d3cSssszwic//     val req         = Flipped(DecoupledIO(new PIQReq))
497a108d429SJay
498cb6e5d3cSssszwic//     val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
499cb6e5d3cSssszwic//     val mem_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
5007052722fSJay
501cb6e5d3cSssszwic//     // write back to Prefetch Buffer
502cb6e5d3cSssszwic//     val piq_write_ipbuffer = DecoupledIO(new IPFBufferWrite)
5039bba777eSssszwic
504cb6e5d3cSssszwic//     val fencei      = Input(Bool())
505cb6e5d3cSssszwic
506cb6e5d3cSssszwic//     val prefetch_entry_data = DecoupledIO(new PIQData)
507cb6e5d3cSssszwic
508cb6e5d3cSssszwic//     val ongoing_req    = ValidIO(UInt(PAddrBits.W))
509cb6e5d3cSssszwic//   })
510cb6e5d3cSssszwic
511cb6e5d3cSssszwic//   val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: s_finish:: Nil = Enum(5)
512cb6e5d3cSssszwic//   val state = RegInit(s_idle)
513cb6e5d3cSssszwic
514cb6e5d3cSssszwic//   //req register
515cb6e5d3cSssszwic//   val req = Reg(new PIQReq)
516cb6e5d3cSssszwic//   val req_idx = req.vSetIdx                     //virtual index
517cb6e5d3cSssszwic//   val req_tag = get_phy_tag(req.paddr)           //physical tag
518cb6e5d3cSssszwic
519cb6e5d3cSssszwic//   val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
520cb6e5d3cSssszwic
521cb6e5d3cSssszwic//   //8 for 64 bits bus and 2 for 256 bits
522cb6e5d3cSssszwic//   val readBeatCnt = Reg(UInt(log2Up(refillCycles).W))
523cb6e5d3cSssszwic//   val respDataReg = Reg(Vec(refillCycles,UInt(beatBits.W)))
524cb6e5d3cSssszwic
525cb6e5d3cSssszwic//   //to main pipe s1
526cb6e5d3cSssszwic//   io.prefetch_entry_data.valid := state =/= s_idle
527cb6e5d3cSssszwic//   io.prefetch_entry_data.bits.vSetIdx := req_idx
528cb6e5d3cSssszwic//   io.prefetch_entry_data.bits.ptage := req_tag
529cb6e5d3cSssszwic//   io.prefetch_entry_data.bits.cacheline := respDataReg.asUInt
530cb6e5d3cSssszwic//   io.prefetch_entry_data.bits.writeBack := state === s_write_back
531cb6e5d3cSssszwic
532cb6e5d3cSssszwic//   //initial
533cb6e5d3cSssszwic//   io.mem_acquire.bits := DontCare
534cb6e5d3cSssszwic//   io.mem_grant.ready := true.B
535cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits:= DontCare
536cb6e5d3cSssszwic
537cb6e5d3cSssszwic//   io.req.ready := state === s_idle
538cb6e5d3cSssszwic//   io.mem_acquire.valid := state === s_memReadReq
539cb6e5d3cSssszwic
540cb6e5d3cSssszwic//   val needflush_r = RegInit(false.B)
541cb6e5d3cSssszwic//   when (state === s_idle) { needflush_r := false.B }
542cb6e5d3cSssszwic//   when (state =/= s_idle && io.fencei) { needflush_r := true.B }
543cb6e5d3cSssszwic//   val needflush = needflush_r | io.fencei
544cb6e5d3cSssszwic
545cb6e5d3cSssszwic//   //state change
546cb6e5d3cSssszwic//   switch(state){
547cb6e5d3cSssszwic//     is(s_idle){
548cb6e5d3cSssszwic//       when(io.req.fire()){
549cb6e5d3cSssszwic//         readBeatCnt := 0.U
550cb6e5d3cSssszwic//         state := s_memReadReq
551cb6e5d3cSssszwic//         req := io.req.bits
552974a902cSguohongyu//       }
553cb6e5d3cSssszwic//     }
5547052722fSJay
555cb6e5d3cSssszwic//     // memory request
556cb6e5d3cSssszwic//     is(s_memReadReq){
557cb6e5d3cSssszwic//       when(io.mem_acquire.fire()){
558cb6e5d3cSssszwic//         state := s_memReadResp
559cb6e5d3cSssszwic//       }
560cb6e5d3cSssszwic//     }
5617052722fSJay
562cb6e5d3cSssszwic//     is(s_memReadResp){
563cb6e5d3cSssszwic//       when (edge.hasData(io.mem_grant.bits)) {
564cb6e5d3cSssszwic//         when (io.mem_grant.fire()) {
565cb6e5d3cSssszwic//           readBeatCnt := readBeatCnt + 1.U
566cb6e5d3cSssszwic//           respDataReg(readBeatCnt) := io.mem_grant.bits.data
567cb6e5d3cSssszwic//           when (readBeatCnt === (refillCycles - 1).U) {
568cb6e5d3cSssszwic//             assert(refill_done, "refill not done!")
569cb6e5d3cSssszwic//             state := s_write_back
570cb6e5d3cSssszwic//           }
571cb6e5d3cSssszwic//         }
572cb6e5d3cSssszwic//       }
573cb6e5d3cSssszwic//     }
5747052722fSJay
575cb6e5d3cSssszwic//     is(s_write_back){
576cb6e5d3cSssszwic//       state := Mux(io.piq_write_ipbuffer.fire() || needflush, s_finish, s_write_back)
577cb6e5d3cSssszwic//     }
578cb6e5d3cSssszwic
579cb6e5d3cSssszwic//     is(s_finish){
580cb6e5d3cSssszwic//       state := s_idle
581cb6e5d3cSssszwic//     }
582cb6e5d3cSssszwic//   }
583cb6e5d3cSssszwic
584cb6e5d3cSssszwic//   //refill write and meta write
585cb6e5d3cSssszwic//   //WARNING: Maybe could not finish refill in 1 cycle
586cb6e5d3cSssszwic//   io.piq_write_ipbuffer.valid := (state === s_write_back) && !needflush
587cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits.meta.tag := req_tag
588cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits.meta.index := req_idx
589cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits.meta.paddr := req.paddr
590cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits.data := respDataReg.asUInt
591cb6e5d3cSssszwic//   io.piq_write_ipbuffer.bits.buffIdx := io.id - PortNumber.U
592cb6e5d3cSssszwic
593cb6e5d3cSssszwic//   io.ongoing_req.valid := state =/= s_idle
594cb6e5d3cSssszwic//   io.ongoing_req.bits := addrAlign(req.paddr, blockBytes, PAddrBits)
595cb6e5d3cSssszwic
596cb6e5d3cSssszwic//   XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire())
597cb6e5d3cSssszwic
598cb6e5d3cSssszwic//   //mem request
599cb6e5d3cSssszwic//   io.mem_acquire.bits  := edge.Get(
600cb6e5d3cSssszwic//     fromSource      = io.id,
601cb6e5d3cSssszwic//     toAddress       = Cat(req.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)),
602cb6e5d3cSssszwic//     lgSize          = (log2Up(cacheParams.blockBytes)).U)._2
603cb6e5d3cSssszwic//   io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B)
604cb6e5d3cSssszwic//   io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U)
605cb6e5d3cSssszwic// }
606cb6e5d3cSssszwic
607cb6e5d3cSssszwicclass PrefetchQueueIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle {
608cb6e5d3cSssszwic  val hartId              = Input(UInt(8.W))
609cb6e5d3cSssszwic  val prefetchReq         = Flipped(DecoupledIO(new PrefetchReq))
610cb6e5d3cSssszwic  val PIQFilterRead       = new PIQFilterRead
611cb6e5d3cSssszwic  val PIQRead             = new PIQRead
612cb6e5d3cSssszwic  val IPFBufferWrite      = DecoupledIO(new IPFBufferWrite)
613cb6e5d3cSssszwic  /** TileLink Port */
614b1ded4e8Sguohongyu  val mem_acquire         = DecoupledIO(new TLBundleA(edge.bundle))
615b1ded4e8Sguohongyu  val mem_grant           = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
616b1ded4e8Sguohongyu  val fencei              = Input(Bool())
617cb6e5d3cSssszwic}
618b1ded4e8Sguohongyu
619cb6e5d3cSssszwicclass PrefetchQueue(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule {
620cb6e5d3cSssszwic  val io = IO(new PrefetchQueueIO(edge))
621974a902cSguohongyu
622cb6e5d3cSssszwic  val enqueReq          = io.prefetchReq
623cb6e5d3cSssszwic  val fromIPrefetch     = io.PIQFilterRead.req
624cb6e5d3cSssszwic  val toIPrefetch       = io.PIQFilterRead.resp
625cb6e5d3cSssszwic  val fromMainPipe      = io.PIQRead.req
626cb6e5d3cSssszwic  val toMainPipe        = io.PIQRead.resp
627cb6e5d3cSssszwic  val toIPF             = io.IPFBufferWrite
628cb6e5d3cSssszwic
629cb6e5d3cSssszwic  /** Define entryt content and initial FIFO queue */
630cb6e5d3cSssszwic  class PrefetchEntry(implicit p: Parameters) extends IPrefetchBundle {
631cb6e5d3cSssszwic    val valid   = Bool()
632cb6e5d3cSssszwic    val paddr   = UInt(PAddrBits.W)
633cb6e5d3cSssszwic    val vSetIdx = UInt(idxBits.W)
634cb6e5d3cSssszwic  }
635cb6e5d3cSssszwic  val PIQ = RegInit(VecInit(Seq.fill(nPrefetchEntries)(0.U.asTypeOf((new PrefetchEntry).cloneType))))
636cb6e5d3cSssszwic
637cb6e5d3cSssszwic  class HandleEntry(implicit p: Parameters) extends IPrefetchBundle {
638cb6e5d3cSssszwic    val valid       = Bool()
639cb6e5d3cSssszwic    val paddr       = UInt(PAddrBits.W)
640cb6e5d3cSssszwic    val vSetIdx     = UInt(idxBits.W)
641cb6e5d3cSssszwic    val issue       = Bool()
642cb6e5d3cSssszwic    val finish      = Bool()
643cb6e5d3cSssszwic    val flash       = Bool()
644cb6e5d3cSssszwic    val readBeatCnt = UInt(log2Up(refillCycles).W)
645cb6e5d3cSssszwic    val respData    = Vec(refillCycles, UInt(beatBits.W))
646cb6e5d3cSssszwic
647cb6e5d3cSssszwic    def cacheline = respData.asUInt
648cb6e5d3cSssszwic  }
649cb6e5d3cSssszwic  val handleEntry = RegInit(0.U.asTypeOf((new HandleEntry).cloneType))
650cb6e5d3cSssszwic
651cb6e5d3cSssszwic  /**
652cb6e5d3cSssszwic    ******************************************************************************
653cb6e5d3cSssszwic    * handle look-up request from IPrefetchPipe
654cb6e5d3cSssszwic    * - 1. Receive request from IPrefetch
655cb6e5d3cSssszwic    * - 2. Look up whether hit in PIQ and handleEntry
656cb6e5d3cSssszwic    * - 3. Send response to IPrefetch at the same cycle
657cb6e5d3cSssszwic    ******************************************************************************
658cb6e5d3cSssszwic    */
659cb6e5d3cSssszwic  val fr_block  = get_block(fromIPrefetch.paddr)
660cb6e5d3cSssszwic  val fr_hit_oh = PIQ.map(e => e.valid && (get_block(e.paddr) === fr_block)) :+
661cb6e5d3cSssszwic                    (handleEntry.valid && (get_block(handleEntry.paddr) === fr_block))
662cb6e5d3cSssszwic  val fr_hit    = ParallelOR(fr_hit_oh)
663cb6e5d3cSssszwic  toIPrefetch.piq_hit := fr_hit
664cb6e5d3cSssszwic  // only hit one entry in PIQ
665cb6e5d3cSssszwic  assert(PopCount(fr_hit_oh) <= 1.U, "More than 1 hit in L1 PIQ for filter")
666cb6e5d3cSssszwic
667cb6e5d3cSssszwic
668cb6e5d3cSssszwic  /**
669cb6e5d3cSssszwic    ******************************************************************************
670cb6e5d3cSssszwic    * handle read request from ICacheMainPipe
671cb6e5d3cSssszwic    * - 1. Receive request from ICacheMainPipe
672cb6e5d3cSssszwic    * - 2. Look up PIQ and handleEntry
673cb6e5d3cSssszwic    * - 3. Send response to ICacheMainPipe at the same cycle
674cb6e5d3cSssszwic    ******************************************************************************
675cb6e5d3cSssszwic    */
676cb6e5d3cSssszwic  fromMainPipe.foreach(_.ready := DontCare)
677cb6e5d3cSssszwic  val r_blocks      = fromMainPipe.map (e => get_block(e.bits.paddr))
678cb6e5d3cSssszwic  /** When hit in PIQ, invalid hitted entry */
679cb6e5d3cSssszwic  val r_hit_oh      = r_blocks.map (block => PIQ.map(e => e.valid && (get_block(e.paddr) === block)))
680cb6e5d3cSssszwic  val curr_hit_ptr  = r_hit_oh.map (OHToUInt(_))
681cb6e5d3cSssszwic  val r_hit_PIQ     = (0 until PortNumber).map (i => ParallelOR(r_hit_oh(i)) && fromMainPipe(i).valid)
682cb6e5d3cSssszwic  // only hit one entry in PIQ
683cb6e5d3cSssszwic  (0 until PortNumber).map (i =>
684cb6e5d3cSssszwic    assert(PopCount(r_hit_oh(i)) <= 1.U, "More than 1 hit in L1 PIQ")
685cb6e5d3cSssszwic  )
686cb6e5d3cSssszwic
687cb6e5d3cSssszwic  /** When hit in handleEntry has't been issued, cancel it and return not hit at the same cycle.
688cb6e5d3cSssszwic   * When hit in handleEntry has been issued return hit at the same cycle, then return data when transiton finish.
689cb6e5d3cSssszwic   * ICacheMainPipe should be blocked during handle handleEntry.
690cb6e5d3cSssszwic  */
691cb6e5d3cSssszwic  val r_hit_handle = r_blocks.map(block => handleEntry.valid && (block === get_block(handleEntry.paddr)))
692cb6e5d3cSssszwic  val cancelHandleEntry = (((0 until PortNumber).map(i=> fromMainPipe(i).valid && r_hit_handle(i))).reduce(_||_) || io.fencei) && !handleEntry.issue
693cb6e5d3cSssszwic  val piq_hit = (0 until PortNumber).map(i => r_hit_handle(i) && handleEntry.issue && !handleEntry.flash && !io.fencei)
694cb6e5d3cSssszwic  (0 until PortNumber).foreach (i => {
695cb6e5d3cSssszwic    toMainPipe(i).piq_hit     := piq_hit(i)
696cb6e5d3cSssszwic    toMainPipe(i).cacheline   := handleEntry.cacheline
697cb6e5d3cSssszwic    toMainPipe(i).data_valid  := handleEntry.valid && handleEntry.finish
6987052722fSJay  })
699cb6e5d3cSssszwic  val piq_hit_req = RegEnable(piq_hit.reduce(_||_), fromMainPipe.map(_.valid).reduce(_||_))
7007052722fSJay
701cb6e5d3cSssszwic  /**
702cb6e5d3cSssszwic    ******************************************************************************
703cb6e5d3cSssszwic    * Manage prefetch requests by queue
704cb6e5d3cSssszwic    * - 1. Shift: entry shift when there are free entries behind
705cb6e5d3cSssszwic    * - 2. Enqueue: receive prefetch request when first entry free
706cb6e5d3cSssszwic    * - 3. Free: invalid the entry hitted mainpipe look up
707cb6e5d3cSssszwic    * - 4. Fencei PIQ: invalid all PIQ entry when fencei
708cb6e5d3cSssszwic    * - 5. Dequeue: move prefetch request from last entry to handle entry
709cb6e5d3cSssszwic    * - 6. Cancel handleEntry hitted mainpipe if hasn't been issued
710cb6e5d3cSssszwic    * - 7. Valid flash of handleEntry when fencei if has been issued
711cb6e5d3cSssszwic    ******************************************************************************
712cb6e5d3cSssszwic    */
713cb6e5d3cSssszwic  /** 1. Shift: entry shift when there are free entries behind */
714cb6e5d3cSssszwic  val move = Wire(Vec(nPrefetchEntries, Bool()))
715cb6e5d3cSssszwic  (0 until nPrefetchEntries).map (i =>
716cb6e5d3cSssszwic    // shift when there are invalid (free) entry behind
717cb6e5d3cSssszwic    move(i) := ParallelOR((i+1 until nPrefetchEntries).map(!PIQ(_).valid) :+ !handleEntry.valid)
718cb6e5d3cSssszwic  )
719cb6e5d3cSssszwic  (1 until nPrefetchEntries).map (i =>
720cb6e5d3cSssszwic    when(move(i-1)) {
721cb6e5d3cSssszwic      PIQ(i) := PIQ(i-1)
722cb6e5d3cSssszwic    }
723cb6e5d3cSssszwic  )
7247052722fSJay
725cb6e5d3cSssszwic  /** 2. Enqueue: receive prefetch request to PIQ(0) when move(0) otherwise blocked*/
726cb6e5d3cSssszwic  enqueReq.ready := move(0)
727cb6e5d3cSssszwic  when(move(0)) {
728cb6e5d3cSssszwic    when(enqueReq.valid) {
729cb6e5d3cSssszwic      PIQ(0).valid    := true.B
730cb6e5d3cSssszwic      PIQ(0).vSetIdx  := enqueReq.bits.vSetIdx
731cb6e5d3cSssszwic      PIQ(0).paddr    := enqueReq.bits.paddr
732cb6e5d3cSssszwic    }.otherwise {
733cb6e5d3cSssszwic      PIQ(0).valid    := false.B
734cb6e5d3cSssszwic    }
735cb6e5d3cSssszwic  }
736b1ded4e8Sguohongyu
737cb6e5d3cSssszwic  /** 3. Free: invalid the entry hitted mainpipe */
738cb6e5d3cSssszwic  (0 until PortNumber) .map (i =>
739cb6e5d3cSssszwic    when(r_hit_PIQ(i)) {
740cb6e5d3cSssszwic      when(move(curr_hit_ptr(i)) && (curr_hit_ptr(i) =/= (nPrefetchEntries-1).U)) {
741cb6e5d3cSssszwic        // the hitted entry will be shifted, so invalid next entry
742cb6e5d3cSssszwic        PIQ(curr_hit_ptr(i) + 1.U).valid := false.B
743cb6e5d3cSssszwic      }.otherwise {
744cb6e5d3cSssszwic        PIQ(curr_hit_ptr(i)).valid := false.B
745cb6e5d3cSssszwic      }
746cb6e5d3cSssszwic    }
747cb6e5d3cSssszwic  )
748cb6e5d3cSssszwic
749cb6e5d3cSssszwic  /** 4. Fencei: invalid all PIQ entry when fencei */
750cb6e5d3cSssszwic  when(io.fencei) {
751cb6e5d3cSssszwic    PIQ.map (
752cb6e5d3cSssszwic      _.valid := false.B
753cb6e5d3cSssszwic    )
754cb6e5d3cSssszwic  }
755cb6e5d3cSssszwic
756cb6e5d3cSssszwic  /** 5. Dequeue: move PIQ.last to handle entry when handle entry is free */
757cb6e5d3cSssszwic  // cancel entry when PIQ.last is hitted by mainpipe
758cb6e5d3cSssszwic  val cancel = (0 until PortNumber).map (i => r_hit_PIQ(i) && (curr_hit_ptr(i) === (nPrefetchEntries-1).U)).reduce(_||_)
759cb6e5d3cSssszwic  when(move(nPrefetchEntries - 1) && !cancel) {
760cb6e5d3cSssszwic    handleEntry.valid       := PIQ(nPrefetchEntries - 1).valid
761cb6e5d3cSssszwic    handleEntry.paddr       := PIQ(nPrefetchEntries - 1).paddr
762cb6e5d3cSssszwic    handleEntry.vSetIdx     := PIQ(nPrefetchEntries - 1).vSetIdx
763cb6e5d3cSssszwic    handleEntry.issue       := false.B
764cb6e5d3cSssszwic    handleEntry.finish      := false.B
765cb6e5d3cSssszwic    handleEntry.flash       := false.B
766cb6e5d3cSssszwic    handleEntry.readBeatCnt := 0.U
767cb6e5d3cSssszwic  }
768cb6e5d3cSssszwic
769cb6e5d3cSssszwic  /** 6. Cancel handleEntry hitted mainpipe or receive fencei if hasn't been issued */
770cb6e5d3cSssszwic  when(cancelHandleEntry) {
771cb6e5d3cSssszwic    handleEntry.valid := false.B
772cb6e5d3cSssszwic  }
773cb6e5d3cSssszwic
774cb6e5d3cSssszwic  /** 7. Valid flash of handleEntry when fencei. Drop data from TileLink port */
775cb6e5d3cSssszwic  when(io.fencei) {
776cb6e5d3cSssszwic    handleEntry.flash := true.B
777cb6e5d3cSssszwic  }
778cb6e5d3cSssszwic
779cb6e5d3cSssszwic
780cb6e5d3cSssszwic  /**
781cb6e5d3cSssszwic    ******************************************************************************
782cb6e5d3cSssszwic    * Write Prefetch Data to Prefetch Buffer
783cb6e5d3cSssszwic    * - valid signal only hold one cycle
784cb6e5d3cSssszwic    ******************************************************************************
785cb6e5d3cSssszwic    */
786cb6e5d3cSssszwic  toIPF.valid          := handleEntry.valid && handleEntry.finish
787cb6e5d3cSssszwic  toIPF.bits.paddr     := handleEntry.paddr
788cb6e5d3cSssszwic  toIPF.bits.vSetIdx   := handleEntry.vSetIdx
789cb6e5d3cSssszwic  toIPF.bits.cacheline := handleEntry.cacheline
790cb6e5d3cSssszwic  toIPF.bits.has_hit   := piq_hit_req
791cb6e5d3cSssszwic
792cb6e5d3cSssszwic
793cb6e5d3cSssszwic  /**
794cb6e5d3cSssszwic    ******************************************************************************
795cb6e5d3cSssszwic    * Tilelink Transition
796cb6e5d3cSssszwic    * - 1. Send acquire to L2Cache, after which the request cannot be canceled (issue valid)
797cb6e5d3cSssszwic    * - 2. Wait data response from Tilelink
798cb6e5d3cSssszwic    * - 3. Get data, valid finish (only one cycle) and invalid issue
799cb6e5d3cSssszwic    ******************************************************************************
800cb6e5d3cSssszwic    */
801b1ded4e8Sguohongyu  val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
802b1ded4e8Sguohongyu
803cb6e5d3cSssszwic  val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: Nil = Enum(4)
804cb6e5d3cSssszwic  val state = RegInit(s_idle)
805b1ded4e8Sguohongyu
806cb6e5d3cSssszwic  // acquire port
807b1ded4e8Sguohongyu  io.mem_acquire.bits := edge.Get(
808cb6e5d3cSssszwic    fromSource      = PortNumber.U,
809cb6e5d3cSssszwic    toAddress       = Cat(handleEntry.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)),
810b1ded4e8Sguohongyu    lgSize          = (log2Up(cacheParams.blockBytes)).U)._2
811d2b20d1aSTang Haojin  io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B)
812d2b20d1aSTang Haojin  io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U)
813b1ded4e8Sguohongyu
814cb6e5d3cSssszwic  // grant port
815cb6e5d3cSssszwic  io.mem_grant.ready    := true.B
816cb6e5d3cSssszwic  io.mem_acquire.valid  := (state === s_memReadReq)
817cb6e5d3cSssszwic
818cb6e5d3cSssszwic  switch(state) {
819cb6e5d3cSssszwic    is(s_idle) {
820cb6e5d3cSssszwic      when(handleEntry.valid && !cancelHandleEntry) {
821cb6e5d3cSssszwic        handleEntry.issue := true.B
822cb6e5d3cSssszwic        state             := s_memReadReq
823cb6e5d3cSssszwic      }
824cb6e5d3cSssszwic    }
825cb6e5d3cSssszwic    is(s_memReadReq) {
826935edac4STang Haojin      state := Mux(io.mem_acquire.fire, s_memReadResp, s_memReadReq)
827cb6e5d3cSssszwic    }
828cb6e5d3cSssszwic    is(s_memReadResp) {
829935edac4STang Haojin      when (edge.hasData(io.mem_grant.bits) && io.mem_grant.fire) {
830cb6e5d3cSssszwic        handleEntry.readBeatCnt := handleEntry.readBeatCnt + 1.U
831cb6e5d3cSssszwic        handleEntry.respData(handleEntry.readBeatCnt) := io.mem_grant.bits.data
832cb6e5d3cSssszwic        when (handleEntry.readBeatCnt === (refillCycles - 1).U) {
833cb6e5d3cSssszwic          assert(refill_done, "refill not done!")
834cb6e5d3cSssszwic          state := s_write_back
835cb6e5d3cSssszwic          when (!io.fencei && !handleEntry.flash) {
836cb6e5d3cSssszwic            handleEntry.issue   := false.B
837cb6e5d3cSssszwic            handleEntry.finish  := true.B
838cb6e5d3cSssszwic          }
839cb6e5d3cSssszwic        }
840cb6e5d3cSssszwic      }
841cb6e5d3cSssszwic    }
842cb6e5d3cSssszwic    is(s_write_back) {
843cb6e5d3cSssszwic      state             := s_idle
844cb6e5d3cSssszwic      handleEntry.valid := false.B
845cb6e5d3cSssszwic    }
846cb6e5d3cSssszwic  }
847cb6e5d3cSssszwic
848cb6e5d3cSssszwic  if (env.EnableDifftest) {
849a0c65233SYinan Xu    val diffipfrefill = DifftestModule(new DiffRefillEvent, dontCare = true)
8507d45a146SYinan Xu    diffipfrefill.coreid   := io.hartId
8517d45a146SYinan Xu    diffipfrefill.index    := 3.U
8527d45a146SYinan Xu    diffipfrefill.valid    := handleEntry.valid && handleEntry.finish
8537d45a146SYinan Xu    diffipfrefill.addr     := handleEntry.paddr
8547d45a146SYinan Xu    diffipfrefill.data     := handleEntry.cacheline.asTypeOf(diffipfrefill.data)
855935edac4STang Haojin    diffipfrefill.idtfr    := DontCare
856cb6e5d3cSssszwic  }
857cb6e5d3cSssszwic}
858cb6e5d3cSssszwic
859cb6e5d3cSssszwicclass FDIPPrefetchIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle {
860cb6e5d3cSssszwic  /** commen */
861cb6e5d3cSssszwic  val fencei = Input(Bool())
862cb6e5d3cSssszwic  val hartId = Input(UInt(8.W))
863cb6e5d3cSssszwic
864cb6e5d3cSssszwic  /** Prefetch Mainpipe IO */
865cb6e5d3cSssszwic  val ftqReq            = Flipped(new FtqPrefechBundle)
866cb6e5d3cSssszwic  val iTLBInter         = new TlbRequestIO
867cb6e5d3cSssszwic  val pmp               = new ICachePMPBundle
868cb6e5d3cSssszwic  val metaReadReq       = Decoupled(new ICacheMetaReadReqBundle)
869cb6e5d3cSssszwic  val metaReadResp      = Input(new ICacheMetaReadRespBundle)
870cb6e5d3cSssszwic  val mshrInfo          = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W))))
871cb6e5d3cSssszwic  val mainPipeMissInfo  = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo)))
872cb6e5d3cSssszwic
873cb6e5d3cSssszwic  /** Prefetch Buffer IO */
874cb6e5d3cSssszwic  val IPFBufferRead   = new IPFBufferRead
875cb6e5d3cSssszwic  val metaWrite       = DecoupledIO(new ICacheMetaWriteBundle)
876cb6e5d3cSssszwic  val dataWrite       = DecoupledIO(new ICacheDataWriteBundle)
877cb6e5d3cSssszwic  val IPFReplacer     = new IPFReplacer
878cb6e5d3cSssszwic
879cb6e5d3cSssszwic  /** Prefetch Queue IO */
880cb6e5d3cSssszwic  val PIQRead         = new PIQRead
881cb6e5d3cSssszwic  val mem_acquire     = new DecoupledIO(new TLBundleA(edge.bundle))
882cb6e5d3cSssszwic  val mem_grant       = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
883cb6e5d3cSssszwic}
884cb6e5d3cSssszwic
885cb6e5d3cSssszwicclass FDIPPrefetch(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule
886cb6e5d3cSssszwic{
887cb6e5d3cSssszwic  val io = IO(new FDIPPrefetchIO(edge))
888cb6e5d3cSssszwic
889cb6e5d3cSssszwic  val prefetchPipe    = Module(new IPrefetchPipe)
890cb6e5d3cSssszwic  val prefetchQueue   = Module(new PrefetchQueue(edge))
891cb6e5d3cSssszwic  val prefetchBuffer  = Module(new PrefetchBuffer)
892cb6e5d3cSssszwic
893cb6e5d3cSssszwic  io.metaReadReq    <> prefetchPipe.io.metaReadReq
894cb6e5d3cSssszwic  io.metaWrite      <> prefetchBuffer.io.metaWrite
895cb6e5d3cSssszwic  io.dataWrite      <> prefetchBuffer.io.dataWrite
896cb6e5d3cSssszwic  io.IPFReplacer    <> prefetchBuffer.io.IPFReplacer
897cb6e5d3cSssszwic  io.mem_acquire    <> prefetchQueue.io.mem_acquire
898cb6e5d3cSssszwic  io.mem_grant      <> prefetchQueue.io.mem_grant
899cb6e5d3cSssszwic
900cb6e5d3cSssszwic  // outside
901cb6e5d3cSssszwic  prefetchPipe.io.fencei            <> io.fencei
902cb6e5d3cSssszwic  prefetchPipe.io.ftqReq            <> io.ftqReq
903cb6e5d3cSssszwic  prefetchPipe.io.iTLBInter         <> io.iTLBInter
904cb6e5d3cSssszwic  prefetchPipe.io.pmp               <> io.pmp
905cb6e5d3cSssszwic  prefetchPipe.io.metaReadResp      <> io.metaReadResp
906cb6e5d3cSssszwic  prefetchPipe.io.mshrInfo          <> io.mshrInfo
907cb6e5d3cSssszwic  prefetchPipe.io.mainPipeMissInfo  <> io.mainPipeMissInfo
908cb6e5d3cSssszwic
909cb6e5d3cSssszwic  // outside
910cb6e5d3cSssszwic  prefetchBuffer.io.hartId         <> io.hartId
911cb6e5d3cSssszwic  prefetchBuffer.io.fencei         <> io.fencei
912cb6e5d3cSssszwic  prefetchBuffer.io.IPFBufferRead  <> io.IPFBufferRead
913cb6e5d3cSssszwic  // inside
914cb6e5d3cSssszwic  prefetchBuffer.io.IPFFilterRead  <> prefetchPipe.io.IPFFilterRead
915cb6e5d3cSssszwic  prefetchBuffer.io.IPFBufferWrite <> prefetchQueue.io.IPFBufferWrite
916cb6e5d3cSssszwic
917cb6e5d3cSssszwic  // outside
918cb6e5d3cSssszwic  prefetchQueue.io.hartId         <> io.hartId
919cb6e5d3cSssszwic  prefetchQueue.io.fencei         <> io.fencei
920cb6e5d3cSssszwic  prefetchQueue.io.PIQRead        <> io.PIQRead
921cb6e5d3cSssszwic  // inside
922cb6e5d3cSssszwic  prefetchQueue.io.prefetchReq    <> prefetchPipe.io.prefetchReq
923cb6e5d3cSssszwic  prefetchQueue.io.PIQFilterRead  <> prefetchPipe.io.PIQFilterRead
9247052722fSJay}
925