xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/IPrefetch.scala (revision c3b763d06258ce632f3eb5ffd9ad985607c041fb)
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
197052722fSJayimport chipsalliance.rocketchip.config.Parameters
207052722fSJayimport chisel3._
217052722fSJayimport chisel3.util._
227052722fSJayimport freechips.rocketchip.tilelink._
237052722fSJayimport utils._
247052722fSJayimport xiangshan.cache.mmu._
257052722fSJayimport xiangshan.frontend._
267052722fSJayimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
27de7689fcSJayimport huancun.{PreferCacheKey}
287052722fSJay
297052722fSJay
307052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle
317052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule
327052722fSJay
337052722fSJayclass PIQReq(implicit p: Parameters) extends IPrefetchBundle {
347052722fSJay  val paddr      = UInt(PAddrBits.W)
357052722fSJay}
367052722fSJay
377052722fSJay
387052722fSJayclass IPrefetchToMissUnit(implicit  p: Parameters) extends IPrefetchBundle{
397052722fSJay  val enqReq  = DecoupledIO(new PIQReq)
407052722fSJay}
417052722fSJay
427052722fSJayclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle {
437052722fSJay  val fromFtq         = Flipped(new FtqPrefechBundle)
44f1fe8698SLemover  val iTLBInter       = new TlbRequestIO
4561e1db30SJay  val pmp             =   new ICachePMPBundle
467052722fSJay  val toIMeta         = Decoupled(new ICacheReadBundle)
477052722fSJay  val fromIMeta       = Input(new ICacheMetaRespBundle)
487052722fSJay  val toMissUnit      = new IPrefetchToMissUnit
4900240ba6SJay  val fromMSHR        = Flipped(Vec(PortNumber,ValidIO(UInt(PAddrBits.W))))
50a108d429SJay
51a108d429SJay  val prefetchEnable = Input(Bool())
52a108d429SJay  val prefetchDisable = Input(Bool())
537052722fSJay}
547052722fSJay
557052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends  IPrefetchModule
567052722fSJay{
577052722fSJay  val io = IO(new IPredfetchIO)
587052722fSJay
59a108d429SJay  val enableBit = RegInit(false.B)
60a108d429SJay  val maxPrefetchCoutner = RegInit(0.U(log2Ceil(nPrefetchEntries + 1).W))
61a108d429SJay
62a108d429SJay  val reachMaxSize = maxPrefetchCoutner === nPrefetchEntries.U
63a108d429SJay
64a108d429SJay  when(io.prefetchEnable){
65a108d429SJay    enableBit := true.B
66a108d429SJay  }.elsewhen((enableBit && io.prefetchDisable) || (enableBit && reachMaxSize)){
67a108d429SJay    enableBit := false.B
68a108d429SJay  }
69a108d429SJay
70a108d429SJay  class PrefetchDir(implicit  p: Parameters) extends IPrefetchBundle
71a108d429SJay  {
72a108d429SJay    val valid = Bool()
73a108d429SJay    val paddr = UInt(PAddrBits.W)
74a108d429SJay  }
75a108d429SJay
76a108d429SJay  val prefetch_dir = RegInit(VecInit(Seq.fill(nPrefetchEntries)(0.U.asTypeOf(new PrefetchDir))))
77a108d429SJay
787052722fSJay  val fromFtq = io.fromFtq
797052722fSJay  val (toITLB,  fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp)
80*c3b763d0SYinan Xu  io.iTLBInter.req_kill := false.B
817052722fSJay  val (toIMeta, fromIMeta) = (io.toIMeta, io.fromIMeta.metaData(0))
827052722fSJay  val (toPMP,  fromPMP)   = (io.pmp.req, io.pmp.resp)
837052722fSJay  val toMissUnit = io.toMissUnit
847052722fSJay
857052722fSJay  val p0_fire, p1_fire, p2_fire, p3_fire =  WireInit(false.B)
867052722fSJay  val p1_discard, p2_discard, p3_discard = WireInit(false.B)
877052722fSJay  val p0_ready, p1_ready, p2_ready, p3_ready = WireInit(false.B)
887052722fSJay
897052722fSJay  /** Prefetch Stage 0: req from Ftq */
907052722fSJay  val p0_valid  =   fromFtq.req.valid
91d6b06a99SJay  val p0_vaddr  =   addrAlign(fromFtq.req.bits.target, blockBytes, VAddrBits)
92a108d429SJay  p0_fire   :=   p0_valid && p1_ready && toITLB.fire() && !fromITLB.bits.miss && toIMeta.ready && enableBit
93e8747464SJenius  //discard req when source not ready
94e8747464SJenius  // p0_discard := p0_valid && ((toITLB.fire() && fromITLB.bits.miss) || !toIMeta.ready || !enableBit)
957052722fSJay
967052722fSJay  toIMeta.valid     := p0_valid
977052722fSJay  toIMeta.bits.vSetIdx(0) := get_idx(p0_vaddr)
987052722fSJay
997052722fSJay  toIMeta.bits.vSetIdx(1) := DontCare
1007052722fSJay  toIMeta.bits.isDoubleLine := false.B
1017052722fSJay
1027052722fSJay  toITLB.valid         := p0_valid
1037052722fSJay  toITLB.bits.size     := 3.U // TODO: fix the size
1047052722fSJay  toITLB.bits.vaddr    := p0_vaddr
1057052722fSJay  toITLB.bits.debug.pc := p0_vaddr
1067052722fSJay
107f1fe8698SLemover  toITLB.bits.kill                := DontCare
1087052722fSJay  toITLB.bits.cmd                 := TlbCmd.exec
109f1fe8698SLemover  toITLB.bits.debug.robIdx        := DontCare
1107052722fSJay  toITLB.bits.debug.isFirstIssue  := DontCare
1117052722fSJay
1127052722fSJay
1137052722fSJay  fromITLB.ready := true.B
1147052722fSJay
115e8747464SJenius  fromFtq.req.ready :=  true.B //(!enableBit || (enableBit && p3_ready)) && toIMeta.ready //&& GTimer() > 500.U
1167052722fSJay
1177052722fSJay  /** Prefetch Stage 1: cache probe filter */
1187052722fSJay  val p1_valid =  generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B)
1197052722fSJay
120005e809bSJiuyang Liu  val p1_vaddr   =  RegEnable(p0_vaddr,    p0_fire)
1217052722fSJay
1227052722fSJay  //tlb resp
123de7689fcSJay  val tlb_resp_valid = RegInit(false.B)
124de7689fcSJay  when(p0_fire) {tlb_resp_valid := true.B}
125de7689fcSJay  .elsewhen(tlb_resp_valid && (p1_fire || p1_discard)) {tlb_resp_valid := false.B}
1267052722fSJay
127de7689fcSJay  val tlb_resp_paddr = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.paddr)
128de7689fcSJay  val tlb_resp_pf    = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp.pf.instr && tlb_resp_valid)
129de7689fcSJay  val tlb_resp_af    = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp.af.instr && tlb_resp_valid)
1307052722fSJay
1317052722fSJay  val p1_exception  = VecInit(Seq(tlb_resp_pf, tlb_resp_af))
1327052722fSJay  val p1_has_except =  p1_exception.reduce(_ || _)
1337052722fSJay
1347052722fSJay  val p1_ptag = get_phy_tag(tlb_resp_paddr)
1357052722fSJay
1367052722fSJay  val p1_meta_ptags       = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.tag)),valid = RegNext(p0_fire))
1377052722fSJay  val p1_meta_cohs        = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.coh)),valid = RegNext(p0_fire))
1387052722fSJay
1397052722fSJay  val p1_tag_eq_vec       =  VecInit(p1_meta_ptags.map(_  ===  p1_ptag ))
1407052722fSJay  val p1_tag_match_vec    =  VecInit(p1_tag_eq_vec.zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && p1_meta_cohs(w).isValid()})
1417052722fSJay  val p1_tag_match        =  ParallelOR(p1_tag_match_vec)
1427052722fSJay  val (p1_hit, p1_miss)   =  (p1_valid && p1_tag_match && !p1_has_except, p1_valid && !p1_tag_match && !p1_has_except)
1437052722fSJay
1447052722fSJay  //overriding the invalid req
1457052722fSJay  val p1_req_cancle = (p1_hit || (tlb_resp_valid && p1_exception.reduce(_ || _))) && p1_valid
1467052722fSJay  val p1_req_accept   = p1_valid && tlb_resp_valid && p1_miss
1477052722fSJay
1487052722fSJay  p1_ready    :=   p1_fire || p1_req_cancle || !p1_valid
149a108d429SJay  p1_fire     :=   p1_valid && p1_req_accept && p2_ready && enableBit
1507052722fSJay  p1_discard  :=   p1_valid && p1_req_cancle
1517052722fSJay
1527052722fSJay  /** Prefetch Stage 2: filtered req PIQ enqueue */
1537052722fSJay  val p2_valid =  generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B)
15461e1db30SJay  val p2_pmp_fire = p2_valid
1557052722fSJay  val pmpExcpAF = fromPMP.instr
1567052722fSJay
157005e809bSJiuyang Liu  val p2_paddr     = RegEnable(tlb_resp_paddr,  p1_fire)
158005e809bSJiuyang Liu  val p2_except_pf = RegEnable(tlb_resp_pf, p1_fire)
159005e809bSJiuyang Liu  val p2_except_af = DataHoldBypass(pmpExcpAF, p2_pmp_fire) || RegEnable(tlb_resp_af, p1_fire)
1607052722fSJay  val p2_mmio      = DataHoldBypass(io.pmp.resp.mmio && !p2_except_af && !p2_except_pf, p2_pmp_fire)
1617052722fSJay
16200240ba6SJay  /*when a prefetch req meet with a miss req in MSHR cancle the prefetch req */
16300240ba6SJay  val p2_check_in_mshr = VecInit(io.fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p2_paddr, blockBytes, PAddrBits))).reduce(_||_)
16400240ba6SJay
1657052722fSJay  //TODO wait PMP logic
1667052722fSJay  val p2_exception  = VecInit(Seq(pmpExcpAF, p2_mmio)).reduce(_||_)
1677052722fSJay
1687052722fSJay  io.pmp.req.valid      := p2_pmp_fire
1697052722fSJay  io.pmp.req.bits.addr  := p2_paddr
1707052722fSJay  io.pmp.req.bits.size  := 3.U
1717052722fSJay  io.pmp.req.bits.cmd   := TlbCmd.exec
1727052722fSJay
1737052722fSJay  p2_ready :=   p2_fire || p2_discard || !p2_valid
1747052722fSJay  p2_fire  :=   p2_valid && !p2_exception && p3_ready && p2_pmp_fire
17561e1db30SJay  p2_discard := p2_valid && (p2_exception && p2_pmp_fire)
1767052722fSJay
1777052722fSJay  /** Prefetch Stage 2: filtered req PIQ enqueue */
178a108d429SJay  val p3_valid =  generatePipeControl(lastFire = p2_fire, thisFire = p3_fire || p3_discard, thisFlush = false.B, lastFlush = false.B)
1797052722fSJay
180005e809bSJiuyang Liu  val p3_paddr = RegEnable(p2_paddr,  p2_fire)
181005e809bSJiuyang Liu  val p3_check_in_mshr = RegEnable(p2_check_in_mshr,  p2_fire)
1827052722fSJay
183a108d429SJay  val p3_hit_dir = VecInit((0 until nPrefetchEntries).map(i => prefetch_dir(i).valid && prefetch_dir(i).paddr === p3_paddr )).reduce(_||_)
184a108d429SJay
185e8747464SJenius  p3_discard := p3_hit_dir || p3_check_in_mshr || (p3_valid && enableBit && !toMissUnit.enqReq.ready)
186a108d429SJay
187a108d429SJay  toMissUnit.enqReq.valid             := p3_valid && enableBit && !p3_discard
1887052722fSJay  toMissUnit.enqReq.bits.paddr        := p3_paddr
1897052722fSJay
190a108d429SJay  when(reachMaxSize){
191a108d429SJay    maxPrefetchCoutner := 0.U
192a108d429SJay
193a108d429SJay    prefetch_dir.foreach(_.valid := false.B)
194a108d429SJay  }.elsewhen(toMissUnit.enqReq.fire()){
195a108d429SJay    maxPrefetchCoutner := maxPrefetchCoutner + 1.U
196a108d429SJay
197a108d429SJay    prefetch_dir(maxPrefetchCoutner).valid := true.B
198a108d429SJay    prefetch_dir(maxPrefetchCoutner).paddr := p3_paddr
199a108d429SJay  }
200a108d429SJay
201a108d429SJay  p3_ready := toMissUnit.enqReq.ready || !enableBit
2027052722fSJay  p3_fire  := toMissUnit.enqReq.fire()
2037052722fSJay
2047052722fSJay}
2057052722fSJay
2067052722fSJayclass IPrefetchEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule
2077052722fSJay{
2087052722fSJay  val io = IO(new Bundle {
2095e649ad5SJay    val id = Input(UInt(log2Ceil(PortNumber + nPrefetchEntries).W))
2107052722fSJay
2117052722fSJay    val req = Flipped(DecoupledIO(new PIQReq))
2127052722fSJay
2137052722fSJay    //tilelink channel
2147052722fSJay    val mem_hint = DecoupledIO(new TLBundleA(edge.bundle))
2157052722fSJay    val mem_hint_ack = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
2167052722fSJay
2177052722fSJay  })
2187052722fSJay
2197052722fSJay  /** default value for control signals */
2207052722fSJay  io.mem_hint.bits := DontCare
2217052722fSJay  io.mem_hint_ack.ready := true.B
2227052722fSJay
2237052722fSJay
2247052722fSJay  val s_idle  :: s_send_hint :: s_wait_hint_ack :: Nil = Enum(3)
2257052722fSJay  val state = RegInit(s_idle)
2267052722fSJay  /** control logic transformation */
2277052722fSJay  //request register
2287052722fSJay  val req = Reg(new PIQReq)
2297052722fSJay  //initial
2307052722fSJay  io.mem_hint.bits := DontCare
2317052722fSJay  io.mem_hint_ack.ready := true.B
2327052722fSJay
2337052722fSJay  io.req.ready := (state === s_idle)
2347052722fSJay  io.mem_hint.valid := (state === s_send_hint)
2357052722fSJay
2367052722fSJay  //state change
2377052722fSJay  switch(state) {
2387052722fSJay    is(s_idle) {
2397052722fSJay      when(io.req.fire()) {
2407052722fSJay        state := s_send_hint
2417052722fSJay        req := io.req.bits
2427052722fSJay      }
2437052722fSJay    }
2447052722fSJay
2457052722fSJay    // memory request
2467052722fSJay    is(s_send_hint) {
2477052722fSJay      when(io.mem_hint.fire()) {
2487052722fSJay        state := s_idle
2497052722fSJay      }
2507052722fSJay    }
2517052722fSJay  }
2527052722fSJay
2537052722fSJay  /** refill write and meta write */
2547052722fSJay  val hint = edge.Hint(
2557052722fSJay    fromSource = io.id,
2567052722fSJay    toAddress = addrAlign(req.paddr, blockBytes, PAddrBits) + blockBytes.U,
2577052722fSJay    lgSize = (log2Up(cacheParams.blockBytes)).U,
2587052722fSJay    param = TLHints.PREFETCH_READ
2597052722fSJay  )._2
2607052722fSJay  io.mem_hint.bits := hint
261de7689fcSJay  io.mem_hint.bits.user.lift(PreferCacheKey).foreach(_ := true.B)
2627052722fSJay
2637052722fSJay
2647052722fSJay  XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire())
2657052722fSJay
2667052722fSJay}
267