xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/IPrefetch.scala (revision 7052722fe6b20ae8f36e9d1d0107febde0e79dec)
1*7052722fSJay/***************************************************************************************
2*7052722fSJay  * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*7052722fSJay  * Copyright (c) 2020-2021 Peng Cheng Laboratory
4*7052722fSJay  *
5*7052722fSJay  * XiangShan is licensed under Mulan PSL v2.
6*7052722fSJay  * You can use this software according to the terms and conditions of the Mulan PSL v2.
7*7052722fSJay  * You may obtain a copy of Mulan PSL v2 at:
8*7052722fSJay  *          http://license.coscl.org.cn/MulanPSL2
9*7052722fSJay  *
10*7052722fSJay  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*7052722fSJay  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*7052722fSJay  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*7052722fSJay  *
14*7052722fSJay  * See the Mulan PSL v2 for more details.
15*7052722fSJay  ***************************************************************************************/
16*7052722fSJay
17*7052722fSJaypackage xiangshan.frontend.icache
18*7052722fSJay
19*7052722fSJayimport chipsalliance.rocketchip.config.Parameters
20*7052722fSJayimport chisel3._
21*7052722fSJayimport chisel3.util._
22*7052722fSJayimport freechips.rocketchip.tilelink._
23*7052722fSJayimport utils._
24*7052722fSJayimport xiangshan.cache.mmu._
25*7052722fSJayimport xiangshan.frontend._
26*7052722fSJayimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
27*7052722fSJay
28*7052722fSJay
29*7052722fSJay
30*7052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle
31*7052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule
32*7052722fSJay
33*7052722fSJayclass PIQReq(implicit p: Parameters) extends IPrefetchBundle {
34*7052722fSJay  val paddr      = UInt(PAddrBits.W)
35*7052722fSJay}
36*7052722fSJay
37*7052722fSJayclass IPrefetchPMPBundle(implicit p: Parameters) extends ICacheBundle{
38*7052722fSJay  val req  = DecoupledIO(new PMPReqBundle())
39*7052722fSJay  val resp = Input(new PMPRespBundle())
40*7052722fSJay}
41*7052722fSJay
42*7052722fSJay
43*7052722fSJayclass IPrefetchToMissUnit(implicit  p: Parameters) extends IPrefetchBundle{
44*7052722fSJay  val enqReq  = DecoupledIO(new PIQReq)
45*7052722fSJay}
46*7052722fSJay
47*7052722fSJayclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle {
48*7052722fSJay  val fromFtq         = Flipped(new FtqPrefechBundle)
49*7052722fSJay  val iTLBInter       = new BlockTlbRequestIO
50*7052722fSJay  val pmp             =   new IPrefetchPMPBundle
51*7052722fSJay  val toIMeta         = Decoupled(new ICacheReadBundle)
52*7052722fSJay  val fromIMeta       = Input(new ICacheMetaRespBundle)
53*7052722fSJay  val toMissUnit     = new IPrefetchToMissUnit
54*7052722fSJay}
55*7052722fSJay
56*7052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends  IPrefetchModule
57*7052722fSJay{
58*7052722fSJay  val io = IO(new IPredfetchIO)
59*7052722fSJay
60*7052722fSJay  val fromFtq = io.fromFtq
61*7052722fSJay  val (toITLB,  fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp)
62*7052722fSJay  val (toIMeta, fromIMeta) = (io.toIMeta, io.fromIMeta.metaData(0))
63*7052722fSJay  val (toPMP,  fromPMP)   = (io.pmp.req, io.pmp.resp)
64*7052722fSJay  val toMissUnit = io.toMissUnit
65*7052722fSJay
66*7052722fSJay  val p0_fire, p1_fire, p2_fire, p3_fire =  WireInit(false.B)
67*7052722fSJay  val p1_discard, p2_discard, p3_discard = WireInit(false.B)
68*7052722fSJay  val p0_ready, p1_ready, p2_ready, p3_ready = WireInit(false.B)
69*7052722fSJay
70*7052722fSJay  /** Prefetch Stage 0: req from Ftq */
71*7052722fSJay  val p0_valid  =   fromFtq.req.valid
72*7052722fSJay  val p0_vaddr  =   addrAlign(fromFtq.req.bits.target, blockBytes, PAddrBits)
73*7052722fSJay  p0_fire   :=   p0_valid && p1_ready && toITLB.fire() && !fromITLB.bits.miss && toIMeta.ready
74*7052722fSJay
75*7052722fSJay  toIMeta.valid     := p0_valid
76*7052722fSJay  toIMeta.bits.vSetIdx(0) := get_idx(p0_vaddr)
77*7052722fSJay
78*7052722fSJay  toIMeta.bits.vSetIdx(1) := DontCare
79*7052722fSJay  toIMeta.bits.isDoubleLine := false.B
80*7052722fSJay
81*7052722fSJay  toITLB.valid         := p0_valid
82*7052722fSJay  toITLB.bits.size     := 3.U // TODO: fix the size
83*7052722fSJay  toITLB.bits.vaddr    := p0_vaddr
84*7052722fSJay  toITLB.bits.debug.pc := p0_vaddr
85*7052722fSJay
86*7052722fSJay  toITLB.bits.cmd                 := TlbCmd.exec
87*7052722fSJay  toITLB.bits.robIdx              := DontCare
88*7052722fSJay  toITLB.bits.debug.isFirstIssue  := DontCare
89*7052722fSJay
90*7052722fSJay
91*7052722fSJay  fromITLB.ready := true.B
92*7052722fSJay
93*7052722fSJay  fromFtq.req.ready :=  p1_ready && GTimer() > 500.U
94*7052722fSJay
95*7052722fSJay  /** Prefetch Stage 1: cache probe filter */
96*7052722fSJay  val p1_valid =  generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B)
97*7052722fSJay
98*7052722fSJay  val p1_vaddr   =  RegEnable(next = p0_vaddr,    enable=p0_fire)
99*7052722fSJay
100*7052722fSJay  //tlb resp
101*7052722fSJay  val tlb_resp_valid = RegNext(p0_fire)
102*7052722fSJay
103*7052722fSJay  val tlb_resp_paddr = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.paddr)
104*7052722fSJay  val tlb_resp_pf    = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.excp.pf.instr && tlb_resp_valid)
105*7052722fSJay  val tlb_resp_af    = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.excp.af.instr && tlb_resp_valid)
106*7052722fSJay
107*7052722fSJay  val p1_exception  = VecInit(Seq(tlb_resp_pf, tlb_resp_af))
108*7052722fSJay  val p1_has_except =  p1_exception.reduce(_ || _)
109*7052722fSJay
110*7052722fSJay  val p1_ptag = get_phy_tag(tlb_resp_paddr)
111*7052722fSJay
112*7052722fSJay  val p1_meta_ptags       = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.tag)),valid = RegNext(p0_fire))
113*7052722fSJay  val p1_meta_cohs        = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.coh)),valid = RegNext(p0_fire))
114*7052722fSJay
115*7052722fSJay  val p1_tag_eq_vec       =  VecInit(p1_meta_ptags.map(_  ===  p1_ptag ))
116*7052722fSJay  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()})
117*7052722fSJay  val p1_tag_match        =  ParallelOR(p1_tag_match_vec)
118*7052722fSJay  val (p1_hit, p1_miss)   =  (p1_valid && p1_tag_match && !p1_has_except, p1_valid && !p1_tag_match && !p1_has_except)
119*7052722fSJay
120*7052722fSJay  //overriding the invalid req
121*7052722fSJay  val p1_req_cancle = (p1_hit || (tlb_resp_valid && p1_exception.reduce(_ || _))) && p1_valid
122*7052722fSJay  val p1_req_accept   = p1_valid && tlb_resp_valid && p1_miss
123*7052722fSJay
124*7052722fSJay  p1_ready    :=   p1_fire || p1_req_cancle || !p1_valid
125*7052722fSJay  p1_fire     :=   p1_valid && p1_req_accept && p2_ready
126*7052722fSJay  p1_discard  :=   p1_valid && p1_req_cancle
127*7052722fSJay
128*7052722fSJay  /** Prefetch Stage 2: filtered req PIQ enqueue */
129*7052722fSJay  val p2_valid =  generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B)
130*7052722fSJay  val p2_pmp_fire = p2_valid && io.pmp.req.ready
131*7052722fSJay  val pmpExcpAF = fromPMP.instr
132*7052722fSJay
133*7052722fSJay  val p2_paddr     = RegEnable(next = tlb_resp_paddr,  enable = p1_fire)
134*7052722fSJay  val p2_except_pf = RegEnable(next =tlb_resp_pf, enable = p1_fire)
135*7052722fSJay  val p2_except_af = DataHoldBypass(pmpExcpAF, p2_pmp_fire) || RegEnable(next = tlb_resp_af, enable = p1_fire)
136*7052722fSJay  val p2_mmio      = DataHoldBypass(io.pmp.resp.mmio && !p2_except_af && !p2_except_pf, p2_pmp_fire)
137*7052722fSJay
138*7052722fSJay  //TODO wait PMP logic
139*7052722fSJay  val p2_exception  = VecInit(Seq(pmpExcpAF, p2_mmio)).reduce(_||_)
140*7052722fSJay
141*7052722fSJay  io.pmp.req.valid      := p2_pmp_fire
142*7052722fSJay  io.pmp.req.bits.addr  := p2_paddr
143*7052722fSJay  io.pmp.req.bits.size  := 3.U
144*7052722fSJay  io.pmp.req.bits.cmd   := TlbCmd.exec
145*7052722fSJay
146*7052722fSJay  p2_ready :=   p2_fire || p2_discard || !p2_valid
147*7052722fSJay  p2_fire  :=   p2_valid && !p2_exception && p3_ready && p2_pmp_fire
148*7052722fSJay  p2_discard := p2_valid && ((p2_exception && p2_pmp_fire) || !io.pmp.req.ready)
149*7052722fSJay
150*7052722fSJay  /** Prefetch Stage 2: filtered req PIQ enqueue */
151*7052722fSJay  val p3_valid =  generatePipeControl(lastFire = p2_fire, thisFire = p3_fire, thisFlush = false.B, lastFlush = false.B)
152*7052722fSJay
153*7052722fSJay  val p3_paddr = RegEnable(next = tlb_resp_paddr,  enable = p1_fire)
154*7052722fSJay
155*7052722fSJay  toMissUnit.enqReq.valid             := p3_valid
156*7052722fSJay  toMissUnit.enqReq.bits.paddr        := p3_paddr
157*7052722fSJay
158*7052722fSJay  p3_ready := toMissUnit.enqReq.ready
159*7052722fSJay  p3_fire  := toMissUnit.enqReq.fire()
160*7052722fSJay
161*7052722fSJay}
162*7052722fSJay
163*7052722fSJayclass IPrefetchEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule
164*7052722fSJay{
165*7052722fSJay  val io = IO(new Bundle {
166*7052722fSJay    val id = Input(UInt(log2Ceil(nPrefetchEntries).W))
167*7052722fSJay
168*7052722fSJay    val req = Flipped(DecoupledIO(new PIQReq))
169*7052722fSJay
170*7052722fSJay    //tilelink channel
171*7052722fSJay    val mem_hint = DecoupledIO(new TLBundleA(edge.bundle))
172*7052722fSJay    val mem_hint_ack = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
173*7052722fSJay
174*7052722fSJay  })
175*7052722fSJay
176*7052722fSJay  /** default value for control signals */
177*7052722fSJay  io.mem_hint.bits := DontCare
178*7052722fSJay  io.mem_hint_ack.ready := true.B
179*7052722fSJay
180*7052722fSJay
181*7052722fSJay  val s_idle  :: s_send_hint :: s_wait_hint_ack :: Nil = Enum(3)
182*7052722fSJay  val state = RegInit(s_idle)
183*7052722fSJay  /** control logic transformation */
184*7052722fSJay  //request register
185*7052722fSJay  val req = Reg(new PIQReq)
186*7052722fSJay  //initial
187*7052722fSJay  io.mem_hint.bits := DontCare
188*7052722fSJay  io.mem_hint_ack.ready := true.B
189*7052722fSJay
190*7052722fSJay  io.req.ready := (state === s_idle)
191*7052722fSJay  io.mem_hint.valid := (state === s_send_hint)
192*7052722fSJay
193*7052722fSJay  //state change
194*7052722fSJay  switch(state) {
195*7052722fSJay    is(s_idle) {
196*7052722fSJay      when(io.req.fire()) {
197*7052722fSJay        state := s_send_hint
198*7052722fSJay        req := io.req.bits
199*7052722fSJay      }
200*7052722fSJay    }
201*7052722fSJay
202*7052722fSJay    // memory request
203*7052722fSJay    is(s_send_hint) {
204*7052722fSJay      when(io.mem_hint.fire()) {
205*7052722fSJay        state := s_idle
206*7052722fSJay      }
207*7052722fSJay    }
208*7052722fSJay  }
209*7052722fSJay
210*7052722fSJay  /** refill write and meta write */
211*7052722fSJay  val hint = edge.Hint(
212*7052722fSJay    fromSource = io.id,
213*7052722fSJay    toAddress = addrAlign(req.paddr, blockBytes, PAddrBits) + blockBytes.U,
214*7052722fSJay    lgSize = (log2Up(cacheParams.blockBytes)).U,
215*7052722fSJay    param = TLHints.PREFETCH_READ
216*7052722fSJay  )._2
217*7052722fSJay  io.mem_hint.bits := hint
218*7052722fSJay
219*7052722fSJay
220*7052722fSJay  XSPerfAccumulate(
221*7052722fSJay    "PrefetchEntryPenalty" + Integer.toString(id, 10),
222*7052722fSJay    BoolStopWatch(
223*7052722fSJay      start = io.req.fire(),
224*7052722fSJay      stop = io.mem_hint_ack.fire(),
225*7052722fSJay      startHighPriority = true)
226*7052722fSJay  )
227*7052722fSJay  XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire())
228*7052722fSJay
229*7052722fSJay}