xref: /XiangShan/src/main/scala/xiangshan/mem/prefetch/FDP.scala (revision 0d32f7132f120ac0b32ab552fe0da4934208dd01)
1/***************************************************************************************
2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*
5* XiangShan is licensed under Mulan PSL v2.
6* You can use this software according to the terms and conditions of the Mulan PSL v2.
7* You may obtain a copy of Mulan PSL v2 at:
8*          http://license.coscl.org.cn/MulanPSL2
9*
10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*
14* See the Mulan PSL v2 for more details.
15***************************************************************************************/
16
17package xiangshan.mem.prefetch
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import freechips.rocketchip.tilelink.ClientStates._
23import freechips.rocketchip.tilelink.MemoryOpCategories._
24import freechips.rocketchip.tilelink.TLPermissions._
25import freechips.rocketchip.tilelink.{ClientMetadata, ClientStates, TLPermissions}
26import utils._
27import utility._
28import xiangshan.{L1CacheErrorInfo, XSCoreParamsKey}
29import xiangshan.mem.HasL1PrefetchSourceParameter
30import utility.{CircularQueuePtr}
31import xiangshan.cache._
32import xiangshan.{XSBundle, XSModule}
33
34//----------------------------------------
35// Feedback Direct Prefetching
36class CounterFilterDataBundle(implicit p: Parameters) extends DCacheBundle {
37  val idx = UInt(idxBits.W)
38  val way = UInt(wayBits.W)
39}
40
41class CounterFilterQueryBundle(implicit p: Parameters) extends DCacheBundle {
42  val req = ValidIO(new CounterFilterDataBundle())
43  val resp = Input(Bool())
44}
45
46// no Set Blocking in LoadPipe, so when counting useful prefetch counter, duplicate result occurs
47// s0    s1     s2     s3
48// r                   w
49// if 3 load insts is accessing the same cache line(set0, way0) in s0, s1, s2
50// they think they all prefetch hit, increment useful prefetch counter 3 times
51// so when load arrives at s3, save it's set&way to an FIFO, all loads will search this FIFO to avoid this case
52class CounterFilter()(implicit p: Parameters) extends DCacheModule {
53  val io = IO(new Bundle() {
54    // input, only from load for now
55    val ld_in = Flipped(Vec(exuParameters.LduCnt, ValidIO(new CounterFilterDataBundle())))
56    val query = Flipped(Vec(exuParameters.LduCnt, new CounterFilterQueryBundle()))
57  })
58
59  val LduStages = 4
60  val SIZE = (LduStages) * exuParameters.LduCnt
61  class Ptr(implicit p: Parameters) extends CircularQueuePtr[Ptr]( p => SIZE ){}
62  object Ptr {
63    def apply(f: Bool, v: UInt)(implicit p: Parameters): Ptr = {
64      val ptr = Wire(new Ptr)
65      ptr.flag := f
66      ptr.value := v
67      ptr
68    }
69  }
70
71  val entries = RegInit(VecInit(Seq.fill(SIZE){ (0.U.asTypeOf(new CounterFilterDataBundle())) }))
72  val valids = RegInit(VecInit(Seq.fill(SIZE){ (false.B) }))
73
74  // enq
75  val enqLen = exuParameters.LduCnt
76  val deqLen = exuParameters.LduCnt
77  val enqPtrExt = RegInit(VecInit((0 until enqLen).map(_.U.asTypeOf(new Ptr))))
78  val deqPtrExt = RegInit(VecInit((0 until deqLen).map(_.U.asTypeOf(new Ptr))))
79
80  val deqPtr = WireInit(deqPtrExt(0).value)
81
82  val reqs_l = io.ld_in.map(_.bits)
83  val reqs_vl = io.ld_in.map(_.valid)
84  val needAlloc = Wire(Vec(enqLen, Bool()))
85  val canAlloc = Wire(Vec(enqLen, Bool()))
86  val last3CycleAlloc = RegInit(0.U(log2Ceil(exuParameters.LduCnt + 1).W))
87
88  for(i <- (0 until enqLen)) {
89    val req = reqs_l(i)
90    val req_v = reqs_vl(i)
91    val index = PopCount(needAlloc.take(i))
92    val allocPtr = enqPtrExt(index)
93
94    needAlloc(i) := req_v
95    canAlloc(i) := needAlloc(i) && allocPtr >= deqPtrExt(0)
96
97    when(canAlloc(i)) {
98      valids(allocPtr.value) := true.B
99      entries(allocPtr.value) := req
100    }
101
102    assert(!needAlloc(i) || canAlloc(i), s"port${i} can not accept CounterFilter enq request, check if SIZE >= (Ldu stages - 2) * LduCnt")
103  }
104  val allocNum = PopCount(canAlloc)
105
106  enqPtrExt.foreach{case x => x := x + allocNum}
107  last3CycleAlloc := RegNext(RegNext(allocNum))
108
109  // deq
110  for(i <- (0 until deqLen)) {
111    when(i.U < last3CycleAlloc) {
112      valids(deqPtrExt(i).value) := false.B
113    }
114  }
115
116  deqPtrExt.foreach{case x => x := x + last3CycleAlloc}
117
118  // query
119  val querys_l = io.query.map(_.req.bits)
120  val querys_vl = io.query.map(_.req.valid)
121  for(i <- (0 until exuParameters.LduCnt)) {
122    val q = querys_l(i)
123    val q_v = querys_vl(i)
124
125    val entry_match = Cat(entries.zip(valids).map {
126      case(e, v) => v && (q.idx === e.idx) && (q.way === e.way)
127    }).orR
128
129    io.query(i).resp := q_v && entry_match
130  }
131
132  XSPerfAccumulate("req_nums", PopCount(io.query.map(_.req.valid)))
133  XSPerfAccumulate("req_set_way_match", PopCount(io.query.map(_.resp)))
134}
135
136class BloomQueryBundle(n: Int)(implicit p: Parameters) extends DCacheBundle {
137  val addr = UInt(BLOOMADDRWIDTH.W)
138
139  def BLOOMADDRWIDTH = log2Ceil(n)
140
141  def get_addr(paddr: UInt): UInt = {
142    assert(paddr.getWidth == PAddrBits)
143    assert(paddr.getWidth >= (blockOffBits + 2 * BLOOMADDRWIDTH))
144    val block_paddr = paddr(paddr.getWidth - 1, blockOffBits)
145    val low_part = block_paddr(BLOOMADDRWIDTH - 1, 0)
146    val high_part = block_paddr(2 * BLOOMADDRWIDTH - 1, BLOOMADDRWIDTH)
147    low_part ^ high_part
148  }
149}
150
151class BloomRespBundle(implicit p: Parameters) extends DCacheBundle {
152  val res = Bool()
153}
154class BloomFilter(n: Int, bypass: Boolean = true)(implicit p: Parameters) extends DCacheModule {
155  val io = IO(new DCacheBundle {
156    val set = Flipped(ValidIO(new BloomQueryBundle(n)))
157    val clr = Flipped(ValidIO(new BloomQueryBundle(n)))
158    val query = Vec(LoadPipelineWidth, Flipped(ValidIO(new BloomQueryBundle(n))))
159    val resp = Vec(LoadPipelineWidth, ValidIO(new BloomRespBundle))
160  })
161
162  val data = RegInit(0.U(n.W))
163  val data_next = Wire(Vec(n, Bool()))
164
165  for (i <- 0 until n) {
166    when(io.clr.valid && i.U === io.clr.bits.addr) {
167      data_next(i) := false.B
168    }.elsewhen(io.set.valid && i.U === io.set.bits.addr) {
169      data_next(i) := true.B
170    }.otherwise {
171      data_next(i) := data(i).asBool
172    }
173  }
174
175  // resp will valid in next cycle
176  for(i <- 0 until LoadPipelineWidth) {
177    io.resp(i).valid := RegNext(io.query(i).valid)
178    if(bypass) {
179      io.resp(i).bits.res := RegEnable(data_next(io.query(i).bits.addr), io.query(i).valid)
180    }else {
181      io.resp(i).bits.res := RegEnable(data(io.query(i).bits.addr), io.query(i).valid)
182    }
183  }
184
185  data := data_next.asUInt
186
187  assert(PopCount(data ^ data_next.asUInt) <= 2.U)
188
189  XSPerfHistogram("valid_nums", PopCount(data), true.B, 0, n + 1, 20)
190}
191
192class FDPrefetcherMonitorBundle()(implicit p: Parameters) extends XSBundle {
193  val refill = Input(Bool()) // from refill pipe, fire
194  val accuracy = new XSBundle {
195    val total_prefetch = Input(Bool()) // from mshr enq, fire, alloc, prefetch
196    val useful_prefetch = Vec(LoadPipelineWidth, Input(Bool())) // from load pipeline, prefetch hit
197  }
198
199  val timely = new XSBundle {
200    val late_prefetch = Input(Bool()) // from mshr enq, a load matches a mshr caused by prefetch
201  }
202
203  val pollution = new XSBundle {
204    val demand_miss = Vec(LoadPipelineWidth, Input(Bool())) // from load pipeline, fisrt miss
205    val cache_pollution = Vec(LoadPipelineWidth, Input(Bool())) // from load pipeline, fisrt miss and pollution caused
206  }
207
208  val pf_ctrl = Output(new PrefetchControlBundle)
209}
210
211class FDPrefetcherMonitor()(implicit p: Parameters) extends XSModule {
212  val io = IO(new FDPrefetcherMonitorBundle)
213
214  val INTERVAL = 8192
215  val CNTWIDTH = log2Up(INTERVAL) + 1
216
217  io.pf_ctrl := DontCare
218
219  val refill_cnt = RegInit(0.U(CNTWIDTH.W))
220
221  val total_prefetch_prev_cnt = RegInit(0.U(CNTWIDTH.W))
222  val useful_prefetch_prev_cnt = RegInit(0.U(CNTWIDTH.W))
223  val late_prefetch_prev_cnt = RegInit(0.U(CNTWIDTH.W))
224  val demand_miss_prev_cnt = RegInit(0.U(CNTWIDTH.W))
225  val pollution_prev_cnt = RegInit(0.U(CNTWIDTH.W))
226  val prev_cnts = Seq(total_prefetch_prev_cnt, useful_prefetch_prev_cnt, late_prefetch_prev_cnt, demand_miss_prev_cnt, pollution_prev_cnt)
227
228  val total_prefetch_interval_cnt = RegInit(0.U(CNTWIDTH.W))
229  val useful_prefetch_interval_cnt = RegInit(0.U(CNTWIDTH.W))
230  val late_prefetch_interval_cnt = RegInit(0.U(CNTWIDTH.W))
231  val demand_miss_interval_cnt = RegInit(0.U(CNTWIDTH.W))
232  val pollution_interval_cnt = RegInit(0.U(CNTWIDTH.W))
233  val interval_cnts = Seq(total_prefetch_interval_cnt, useful_prefetch_interval_cnt, late_prefetch_interval_cnt, demand_miss_interval_cnt, pollution_interval_cnt)
234
235  val interval_trigger = refill_cnt === INTERVAL.U
236
237  val io_ens = Seq(io.accuracy.total_prefetch, io.accuracy.useful_prefetch, io.timely.late_prefetch, io.pollution.demand_miss, io.pollution.cache_pollution)
238
239  for((interval, en) <- interval_cnts.zip(io_ens)) {
240    interval := interval + PopCount(en.asUInt)
241  }
242
243  when(io.refill) {
244    refill_cnt := refill_cnt + 1.U
245  }
246
247  when(interval_trigger) {
248    refill_cnt := 0.U
249    for((prev, interval) <- prev_cnts.zip(interval_cnts)) {
250      prev := Cat(0.U(1.W), prev(prev.getWidth - 1, 1)) + Cat(0.U(1.W), interval(interval.getWidth - 1, 1))
251      interval := 0.U
252    }
253  }
254
255  XSPerfAccumulate("io_refill", io.refill)
256  XSPerfAccumulate("total_prefetch_en", io.accuracy.total_prefetch)
257  XSPerfAccumulate("useful_prefetch_en", PopCount(io.accuracy.useful_prefetch) + io.timely.late_prefetch)
258  XSPerfAccumulate("late_prefetch_en", io.timely.late_prefetch)
259  XSPerfAccumulate("demand_miss_en", PopCount(io.pollution.demand_miss))
260  XSPerfAccumulate("cache_pollution_en", PopCount(io.pollution.cache_pollution))
261}