xref: /XiangShan/src/main/scala/xiangshan/cache/wpu/WPUWrapper.scala (revision 4a0e27ecb184507a75a30529c824cb060e35b912)
1package xiangshan.cache.wpu
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import utility.XSPerfAccumulate
7import xiangshan._
8import xiangshan.cache.{DCacheModule, HasDCacheParameters}
9import xiangshan.frontend.icache.HasICacheParameters
10
11class ReplayCarry(nWays: Int)(implicit p: Parameters) extends XSBundle {
12  val real_way_en = UInt(nWays.W)
13  val valid = Bool()
14}
15
16object ReplayCarry{
17  def apply(nWays: Int, rwe: UInt = 0.U, v: Bool = false.B)(implicit p: Parameters): ReplayCarry = {
18    val rcry = Wire(new ReplayCarry(nWays))
19    rcry.real_way_en := rwe
20    rcry.valid := v
21    rcry
22  }
23
24  def init(nWays: Int)(implicit p: Parameters): ReplayCarry = {
25    val rcry = Wire(new ReplayCarry(nWays))
26    rcry.real_way_en := 0.U
27    rcry.valid := false.B
28    rcry
29  }
30}
31
32class WPUBaseReq(implicit p: Parameters) extends BaseWPUBundle{
33  val vaddr = UInt(VAddrBits.W)
34}
35
36class WPUReplayedReq(nWays: Int)(implicit p: Parameters) extends WPUBaseReq {
37  val replayCarry = new ReplayCarry(nWays)
38}
39
40class WPUResp(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{
41  val s0_pred_way_en = UInt(nWays.W)
42}
43
44class WPUUpdate(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{
45  val vaddr = UInt(VAddrBits.W)
46  val s1_real_way_en = UInt(nWays.W)
47}
48
49class WPUUpdateLookup(nWays:Int)(implicit p:Parameters) extends WPUUpdate(nWays){
50  val s1_pred_way_en = UInt(nWays.W)
51}
52
53class ConflictPredictIO(nWays:Int)(implicit p:Parameters) extends BaseWPUBundle{
54  // pred
55  val s0_vaddr = Input(UInt(VAddrBits.W))
56  // update
57  val s1_vaddr = Input(UInt(VAddrBits.W))
58  val s1_dm_hit = Input(Bool())
59}
60
61class IwpuBaseIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends BaseWPUBundle{
62  val req = Vec(nPorts, Flipped(Decoupled(new WPUBaseReq)))
63  val resp = Vec(nPorts, ValidIO(new WPUResp(nWays)))
64  val lookup_upd = Vec(nPorts, Flipped(ValidIO(new WPUUpdateLookup(nWays))))
65}
66
67class IwpuIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends IwpuBaseIO(nWays, nPorts){
68  val tagwrite_upd = Flipped(ValidIO(new WPUUpdate(nWays)))
69}
70
71class DwpuBaseIO(nWays:Int, nPorts: Int)(implicit p:Parameters) extends BaseWPUBundle{
72  val req = Vec(nPorts, Flipped(Decoupled(new WPUReplayedReq(nWays))))
73  val resp = Vec(nPorts, ValidIO(new WPUResp(nWays)))
74  val lookup_upd = Vec(nPorts, Flipped(ValidIO(new WPUUpdateLookup(nWays))))
75  val cfpred = Vec(nPorts, new ConflictPredictIO(nWays))
76}
77
78class DwpuIO(nWays:Int, nPorts:Int)(implicit p:Parameters) extends DwpuBaseIO(nWays, nPorts){
79  val tagwrite_upd = Flipped(ValidIO(new WPUUpdate(nWays)))
80}
81
82class DCacheWpuWrapper (nPorts: Int = 1) (implicit p:Parameters) extends DCacheModule with HasWPUParameters  {
83  val wpu = AlgoWPUMap(dwpuParam, nPorts)
84  val io = IO(new DwpuIO(nWays, nPorts))
85
86  /** pred */
87  val s0_dmSel = Wire(Vec(nPorts, Bool()))
88  val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
89  val s1_lookup_valid = Wire(Vec(nPorts, Bool()))
90  val s1_dmSel = Wire(Vec(nPorts, Bool()))
91  val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
92  val s1_pred_fail = Wire(Vec(nPorts, Bool()))
93  val s1_hit = Wire(Vec(nPorts, Bool()))
94
95  for(i <- 0 until nPorts){
96    s0_dmSel(i) := false.B
97    wpu.io.predVec(i).en := io.req(i).valid
98    wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr
99    when(io.req(i).bits.replayCarry.valid) {
100      // replay carry
101      s0_pred_way_en(i) := io.req(i).bits.replayCarry.real_way_en
102    }.otherwise {
103      // way prediction
104      s0_pred_way_en(i) := wpu.io.predVec(i).way_en
105    }
106
107    /** check and update in s1 */
108    s1_lookup_valid(i) := io.lookup_upd(i).valid
109    s1_dmSel(i) := RegNext(s0_dmSel(i))
110    s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en
111    s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= io.lookup_upd(i).bits.s1_real_way_en
112    s1_hit(i) := !s1_pred_fail(i) && s1_pred_way_en(i).orR
113
114    val s0_replay_upd = Wire(new BaseWpuUpdateBundle(nWays))
115    s0_replay_upd.en := io.req(i).valid && io.req(i).bits.replayCarry.valid
116    s0_replay_upd.vaddr := io.req(i).bits.vaddr
117    s0_replay_upd.way_en := io.req(i).bits.replayCarry.real_way_en
118    val s1_replay_upd = RegEnable(s0_replay_upd, io.req(i).valid)
119
120
121    // look up res
122    wpu.io.updLookup(i).en := io.lookup_upd(i).valid
123    wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr
124    wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en
125    wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en
126
127    // which will update in look up pred fail
128    wpu.io.updReplaycarry(i) := s1_replay_upd
129
130    // replace / tag write
131    wpu.io.updTagwrite(i) := DontCare
132
133    /** predict and response in s0 */
134    io.req(i).ready := true.B
135    if (dwpuParam.enWPU) {
136      io.resp(i).valid := io.req(i).valid
137    } else {
138      io.resp(i).valid := false.B
139    }
140    io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i)
141    assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way")
142  }
143  wpu.io.updTagwrite(0).en := io.tagwrite_upd.valid
144  wpu.io.updTagwrite(0).vaddr := io.tagwrite_upd.bits.vaddr
145  wpu.io.updTagwrite(0).way_en := io.tagwrite_upd.bits.s1_real_way_en
146  // PerfLog
147  // pred situation
148  XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i))))
149  XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_fail(i))))
150  XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && s1_pred_fail(i))))
151  XSPerfAccumulate("wpu_pred_miss", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_way_en(i).orR)))
152  XSPerfAccumulate("wpu_real_miss", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !io.lookup_upd(i).bits.s1_real_way_en.orR)))
153  // pred component
154  XSPerfAccumulate("wpu_pred_replayCarry", PopCount((0 until nPorts).map(i => io.req(i).valid && io.req(i).bits.replayCarry.valid)))
155  XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid)))
156
157  /* selective direct mapping */
158  if(dwpuParam.enCfPred){
159    val wayConflictPredictor = Module(new WayConflictPredictor(nPorts))
160    val s0_pred_way_conflict = Wire(Vec(nPorts, Bool()))
161    for(i <- 0 until nPorts){
162      wayConflictPredictor.io.pred(i).en := io.req(i).valid
163      wayConflictPredictor.io.pred(i).vaddr := io.cfpred(i).s0_vaddr
164      s0_pred_way_conflict(i) := wayConflictPredictor.io.pred(i).way_conflict
165      when(!s0_pred_way_conflict(i)) {
166        s0_pred_way_en(i) := UIntToOH(get_direct_map_way(io.req(i).bits.vaddr))
167        s0_dmSel(i) := true.B
168      }
169      wayConflictPredictor.io.update(i).en := io.lookup_upd(i).valid
170      wayConflictPredictor.io.update(i).vaddr := io.cfpred(i).s1_vaddr
171      wayConflictPredictor.io.update(i).dm_hit := s1_dmSel(i) && io.cfpred(i).s1_dm_hit
172      wayConflictPredictor.io.update(i).sa_hit := !s1_dmSel(i) && s1_hit(i)
173    }
174    XSPerfAccumulate("wpu_pred_from_prediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && s0_pred_way_conflict(i))))
175    XSPerfAccumulate("wpu_pred_from_directMap", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && !s0_pred_way_conflict(i))))
176    // dm situation
177    XSPerfAccumulate("direct_map_all", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid)))
178    XSPerfAccumulate("direct_map_ok", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid && io.cfpred(i).s1_dm_hit)))
179  }
180}
181
182
183class ICacheWpuWrapper (nPorts: Int) (implicit p:Parameters) extends WPUModule with HasICacheParameters {
184  val wpu = AlgoWPUMap(iwpuParam, nPorts)
185  val io = IO(new IwpuIO(nWays, nPorts))
186
187  val s1_pred_fail = Wire(Vec(nPorts, Bool()))
188  val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
189  val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
190  val s1_real_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
191  /** pred in s0*/
192  for (i <- 0 until nPorts){
193    wpu.io.predVec(i).en := io.req(i).valid
194    wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr
195    s0_pred_way_en(i) := wpu.io.predVec(i).way_en
196    // io
197    io.req(i).ready := true.B
198    if (iwpuParam.enWPU) {
199      io.resp(i).valid := io.req(i).valid
200    } else {
201      io.resp(i).valid := false.B
202    }
203    io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i)
204    assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way")
205
206    /** update in s1 */
207    s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en
208    s1_real_way_en(i) := io.lookup_upd(i).bits.s1_real_way_en
209    s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= s1_real_way_en(i)
210    // look up res
211    wpu.io.updLookup(i).en := io.lookup_upd(i).valid
212    wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr
213    wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en
214    wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en
215    // which will update in look up pred fail
216    wpu.io.updReplaycarry := DontCare
217    // replace / tag write
218    wpu.io.updTagwrite := DontCare
219  }
220  wpu.io.updTagwrite.head.en := io.tagwrite_upd.valid
221  wpu.io.updTagwrite.head.vaddr := io.tagwrite_upd.bits.vaddr
222  wpu.io.updTagwrite.head.way_en := io.tagwrite_upd.bits.s1_real_way_en
223
224  XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid}))
225  XSPerfAccumulate("wpu_pred_succ",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !s1_pred_fail(i)}))
226  XSPerfAccumulate("wpu_pred_fail",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && s1_pred_fail(i)}))
227  XSPerfAccumulate("wpu_pred_miss",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !RegNext(s0_pred_way_en(i)).orR}))
228  XSPerfAccumulate("wpu_real_miss",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !RegNext(s1_real_way_en(i)).orR}))
229}
230
231/** IdealWPU:
232  * req in s1 and resp in s1
233  */
234class IdealWPU(implicit p:Parameters) extends WPUModule with HasDCacheParameters {
235  val io = IO(new Bundle{
236    val req = Output(new Bundle {
237      val valid = Bool()
238      val s1_real_way_en = UInt(nWays.W)
239    })
240    val resp = Output(new Bundle{
241      val valid = Bool()
242      val s1_pred_way_en = UInt(nWays.W)
243    })
244  })
245
246  val s1_pred_way_en = io.req.s1_real_way_en
247
248  if(dwpuParam.enWPU){
249    io.resp.valid := io.req.valid
250  }else{
251    io.resp.valid := false.B
252  }
253  io.resp.s1_pred_way_en := s1_pred_way_en
254}