xref: /XiangShan/src/main/scala/xiangshan/cache/wpu/WPUWrapper.scala (revision 78a8cd257caa1ff2b977d80082b1b3a2fa98a1d3)
1package xiangshan.cache.wpu
2
3import org.chipsalliance.cde.config.Parameters
4import chisel3._
5import chisel3.util._
6import utils.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 wayConflictPredictor = Module(new WayConflictPredictor(nPorts))
85  val io = IO(new DwpuIO(nWays, nPorts))
86
87  /** pred */
88  val s0_dmSel = Wire(Vec(nPorts, Bool()))
89  val s0_pred_way_conflict = Wire(Vec(nPorts, Bool()))
90  val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
91  val s1_lookup_valid = Wire(Vec(nPorts, Bool()))
92  val s1_dmSel = Wire(Vec(nPorts, Bool()))
93  val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
94  val s1_pred_fail = Wire(Vec(nPorts, Bool()))
95  val s1_hit = Wire(Vec(nPorts, Bool()))
96
97  for(i <- 0 until nPorts){
98    wayConflictPredictor.io.pred(i).en := io.req(i).valid
99    wayConflictPredictor.io.pred(i).vaddr := io.cfpred(i).s0_vaddr
100    s0_pred_way_conflict(i) := wayConflictPredictor.io.pred(i).way_conflict
101
102    s0_dmSel(i) := false.B
103    wpu.io.predVec(i).en := io.req(i).valid
104    wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr
105    when(io.req(i).bits.replayCarry.valid) {
106      // replay carry
107      s0_pred_way_en(i) := io.req(i).bits.replayCarry.real_way_en
108    }.otherwise {
109      // way prediction
110      s0_pred_way_en(i) := wpu.io.predVec(i).way_en
111
112      if (dwpuParam.enCfPred) {
113        // selective direct mapping
114        when(!s0_pred_way_conflict(i)) {
115          s0_pred_way_en(i) := UIntToOH(get_direct_map_way(io.req(i).bits.vaddr))
116          s0_dmSel(i) := true.B
117        }
118      }
119    }
120
121    /** check and update in s1 */
122    s1_lookup_valid(i) := io.lookup_upd(i).valid
123    s1_dmSel(i) := RegNext(s0_dmSel(i))
124    s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en
125    s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= io.lookup_upd(i).bits.s1_real_way_en
126    s1_hit(i) := !s1_pred_fail(i) && s1_pred_way_en(i).orR
127
128    val s0_replay_upd = Wire(new BaseWpuUpdateBundle(nWays))
129    s0_replay_upd.en := io.req(i).valid && io.req(i).bits.replayCarry.valid
130    s0_replay_upd.vaddr := io.req(i).bits.vaddr
131    s0_replay_upd.way_en := io.req(i).bits.replayCarry.real_way_en
132    val s1_replay_upd = RegNext(s0_replay_upd)
133
134    wayConflictPredictor.io.update(i).en := io.lookup_upd(i).valid
135    wayConflictPredictor.io.update(i).vaddr := io.cfpred(i).s1_vaddr
136    wayConflictPredictor.io.update(i).dm_hit := s1_dmSel(i) && io.cfpred(i).s1_dm_hit
137    wayConflictPredictor.io.update(i).sa_hit := !s1_dmSel(i) && s1_hit(i)
138
139    // look up res
140    wpu.io.updLookup(i).en := io.lookup_upd(i).valid
141    wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr
142    wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en
143    wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en
144
145    // which will update in look up pred fail
146    wpu.io.updReplaycarry(i) := s1_replay_upd
147
148    // replace / tag write
149    wpu.io.updTagwrite(i) := DontCare
150
151    /** predict and response in s0 */
152    io.req(i).ready := true.B
153    if (dwpuParam.enWPU) {
154      io.resp(i).valid := io.req(i).valid
155    } else {
156      io.resp(i).valid := false.B
157    }
158    io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i)
159    assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way")
160  }
161  wpu.io.updTagwrite(0).en := io.tagwrite_upd.valid
162  wpu.io.updTagwrite(0).vaddr := io.tagwrite_upd.bits.vaddr
163  wpu.io.updTagwrite(0).way_en := io.tagwrite_upd.bits.s1_real_way_en
164
165  // PerfLog
166  // pred situation
167  XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i))))
168  XSPerfAccumulate("wpu_pred_succ", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && !s1_pred_fail(i))))
169  XSPerfAccumulate("wpu_pred_fail", PopCount((0 until nPorts).map(i => RegNext(io.req(i).valid) && s1_lookup_valid(i) && s1_pred_fail(i))))
170  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)))
171  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)))
172  // pred component
173  XSPerfAccumulate("wpu_pred_replayCarry", PopCount((0 until nPorts).map(i => io.req(i).valid && io.req(i).bits.replayCarry.valid)))
174  if(!dwpuParam.enCfPred){
175    XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid)))
176  }else{
177    XSPerfAccumulate("wpu_pred_wayPrediction", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && s0_pred_way_conflict(i))))
178    XSPerfAccumulate("wpu_pred_directMap", PopCount((0 until nPorts).map(i => io.req(i).valid && !io.req(i).bits.replayCarry.valid && !s0_pred_way_conflict(i))))
179    // dm situation
180    XSPerfAccumulate("direct_map_all", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid)))
181    XSPerfAccumulate("direct_map_ok", PopCount((0 until nPorts).map(i => io.lookup_upd(i).valid && io.cfpred(i).s1_dm_hit)))
182  }
183}
184
185
186class ICacheWpuWrapper (nPorts: Int) (implicit p:Parameters) extends WPUModule with HasICacheParameters {
187  val wpu = AlgoWPUMap(iwpuParam, nPorts)
188  val io = IO(new IwpuIO(nWays, nPorts))
189
190  val s1_pred_fail = Wire(Vec(nPorts, Bool()))
191  val s0_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
192  val s1_pred_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
193  val s1_real_way_en = Wire(Vec(nPorts, UInt(nWays.W)))
194  /** pred in s0*/
195  for (i <- 0 until nPorts){
196    wpu.io.predVec(i).en := io.req(i).valid
197    wpu.io.predVec(i).vaddr := io.req(i).bits.vaddr
198    s0_pred_way_en(i) := wpu.io.predVec(i).way_en
199    // io
200    io.req(i).ready := true.B
201    if (iwpuParam.enWPU) {
202      io.resp(i).valid := io.req(i).valid
203    } else {
204      io.resp(i).valid := false.B
205    }
206    io.resp(i).bits.s0_pred_way_en := s0_pred_way_en(i)
207    assert(PopCount(io.resp(i).bits.s0_pred_way_en) <= 1.U, "tag should not match with more than 1 way")
208
209    /** update in s1 */
210    s1_pred_way_en(i) := io.lookup_upd(i).bits.s1_pred_way_en
211    s1_real_way_en(i) := io.lookup_upd(i).bits.s1_real_way_en
212    s1_pred_fail(i) := io.lookup_upd(i).valid && s1_pred_way_en(i) =/= s1_real_way_en(i)
213    // look up res
214    wpu.io.updLookup(i).en := io.lookup_upd(i).valid
215    wpu.io.updLookup(i).vaddr := io.lookup_upd(i).bits.vaddr
216    wpu.io.updLookup(i).way_en := io.lookup_upd(i).bits.s1_real_way_en
217    wpu.io.updLookup(i).pred_way_en := io.lookup_upd(i).bits.s1_pred_way_en
218    // which will update in look up pred fail
219    wpu.io.updReplaycarry := DontCare
220    // replace / tag write
221    wpu.io.updTagwrite := DontCare
222  }
223  wpu.io.updTagwrite.head.en := io.tagwrite_upd.valid
224  wpu.io.updTagwrite.head.vaddr := io.tagwrite_upd.bits.vaddr
225  wpu.io.updTagwrite.head.way_en := io.tagwrite_upd.bits.s1_real_way_en
226
227  XSPerfAccumulate("wpu_pred_total", PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid}))
228  XSPerfAccumulate("wpu_pred_succ",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && !s1_pred_fail(i)}))
229  XSPerfAccumulate("wpu_pred_fail",  PopCount((0 until nPorts).map{i => RegNext(io.req(i).valid) && io.lookup_upd(i).valid && s1_pred_fail(i)}))
230  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}))
231  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}))
232}
233
234/** IdealWPU:
235  * req in s1 and resp in s1
236  */
237class IdealWPU(implicit p:Parameters) extends WPUModule with HasDCacheParameters {
238  val io = IO(new Bundle{
239    val req = Output(new Bundle {
240      val valid = Bool()
241      val s1_real_way_en = UInt(nWays.W)
242    })
243    val resp = Output(new Bundle{
244      val valid = Bool()
245      val s1_pred_way_en = UInt(nWays.W)
246    })
247  })
248
249  val s1_pred_way_en = io.req.s1_real_way_en
250
251  if(dwpuParam.enWPU){
252    io.resp.valid := io.req.valid
253  }else{
254    io.resp.valid := false.B
255  }
256  io.resp.s1_pred_way_en := s1_pred_way_en
257}