xref: /XiangShan/src/main/scala/xiangshan/frontend/SC.scala (revision ae20d4f813bcc42178dcf493be4be500e5c7c0b9)
1package xiangshan.frontend
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import utils._
7import chisel3.experimental.chiselName
8
9import scala.math.min
10
11trait HasSCParameter extends HasTageParameter {
12  val SCHistLens = 0 :: TableInfo.map{ case (_,h,_) => h}.toList
13  val SCNTables = 6
14  val SCCtrBits = 6
15  val SCNRows = 1024
16  val SCTableInfo = Seq.fill(SCNTables)((SCNRows, SCCtrBits)) zip SCHistLens map {case ((n, cb), h) => (n, cb, h)}
17}
18
19class SCReq extends TageReq
20
21abstract class SCBundle extends TageBundle with HasSCParameter {}
22abstract class SCModule extends TageModule with HasSCParameter {}
23
24class SCResp(val ctrBits: Int = 6) extends SCBundle {
25  val ctr = Vec(2, SInt(ctrBits.W))
26}
27
28class SCUpdate(val ctrBits: Int = 6) extends SCBundle {
29  val pc = UInt(VAddrBits.W)
30  val hist = UInt(HistoryLength.W)
31  val mask = Vec(TageBanks, Bool())
32  val oldCtrs = Vec(TageBanks, SInt(ctrBits.W))
33  val tagePreds = Vec(TageBanks, Bool())
34  val takens = Vec(TageBanks, Bool())
35}
36
37class SCTableIO extends SCBundle {
38  val req = Input(Valid(new SCReq))
39  val resp = Output(Vec(TageBanks, new SCResp))
40  val update = Input(new SCUpdate)
41}
42
43abstract class BaseSCTable(val r: Int = 1024, val cb: Int = 6, val h: Int = 0) extends SCModule {
44  val io = IO(new SCTableIO)
45  def getCenteredValue(ctr: SInt): SInt = (ctr << 1).asSInt + 1.S
46}
47
48class FakeSCTable extends BaseSCTable {
49  io.resp := 0.U.asTypeOf(Vec(TageBanks, new SCResp))
50}
51
52@chiselName
53class SCTable(val nRows: Int, val ctrBits: Int, val histLen: Int)
54  extends BaseSCTable(nRows, ctrBits, histLen) with HasFoldedHistory {
55
56  val table = Module(new SRAMTemplate(SInt(ctrBits.W), set=nRows, way=2*TageBanks, shouldReset=true, holdRead=true, singlePort=false))
57
58  def getIdx(hist: UInt, pc: UInt) = {
59    (compute_folded_hist(hist, log2Ceil(nRows)) ^ (pc >> instOffsetBits.U))(log2Ceil(nRows)-1,0)
60  }
61
62  def ctrUpdate(ctr: SInt, cond: Bool): SInt = signedSatUpdate(ctr, ctrBits, cond)
63
64  val if2_idx = getIdx(io.req.bits.hist, io.req.bits.pc)
65  val if3_idx = RegEnable(if2_idx, enable=io.req.valid)
66
67  val table_r =
68    VecInit((0 until TageBanks).map(b => VecInit((0 to 1).map(i => table.io.r.resp.data(b*2+i)))))
69
70
71  val if2_mask = io.req.bits.mask
72  val if3_mask = RegEnable(if2_mask, enable=io.req.valid)
73
74  val update_idx = getIdx(io.update.hist, io.update.pc)
75  val update_wdatas =
76    VecInit((0 until TageBanks).map(w =>
77      ctrUpdate(io.update.oldCtrs(w), io.update.takens(w))))
78
79  table.io.r.req.valid := io.req.valid
80  table.io.r.req.bits.setIdx := if2_idx
81
82  val updateWayMask =
83    VecInit((0 until TageBanks).map(b =>
84      VecInit((0 to 1).map(i =>
85        (io.update.mask(b) && i.U === io.update.tagePreds(b).asUInt))))).asUInt
86
87  table.io.w.apply(
88    valid = io.update.mask.asUInt.orR,
89    data = VecInit((0 until TageBanks*2).map(i => update_wdatas(i/2))),
90    setIdx = update_idx,
91    waymask = updateWayMask
92  )
93
94  (0 until TageBanks).map(b => {
95    io.resp(b).ctr := table_r(b)
96  })
97
98  if (BPUDebug && debug) {
99    val u = io.update
100    val b = PriorityEncoder(u.mask)
101    XSDebug(io.req.valid, p"scTableReq: pc=0x${Hexadecimal(io.req.bits.pc)}" +
102                          p"if2_idx=${if2_idx}, hist=${Hexadecimal(io.req.bits.hist)}," +
103                          p"if2_mask=${Binary(if2_mask)}\n")
104    for (i <- 0 until TageBanks) {
105      XSDebug(RegNext(io.req.valid),
106              p"scTableResp[${i.U}]: if3_idx=${if3_idx}," +
107              p"ctr:${io.resp(i).ctr}, if3_mask=${Binary(if3_mask)}\n")
108      XSDebug(io.update.mask(i),
109              p"update Table: pc:${Hexadecimal(u.pc)}, hist:${Hexadecimal(u.hist)}," +
110              p"bank:${b}%d, tageTaken:${u.tagePreds(i)}%d, taken:${u.takens(i)}%d, oldCtr:${u.oldCtrs(i)}%d\n")
111    }
112  }
113
114}
115
116class SCThreshold(val ctrBits: Int = 5) extends SCBundle {
117  val ctr = UInt(ctrBits.W)
118  def satPos(ctr: UInt = this.ctr) = ctr === ((1.U << ctrBits) - 1.U)
119  def satNeg(ctr: UInt = this.ctr) = ctr === 0.U
120  def neutralVal = (1.U << (ctrBits - 1))
121  val thres = UInt(5.W)
122  def minThres = 5.U
123  def maxThres = 31.U
124  def update(cause: Bool): SCThreshold = {
125    val res = Wire(new SCThreshold(this.ctrBits))
126    val newCtr = satUpdate(this.ctr, this.ctrBits, cause)
127    val newThres = Mux(res.satPos(newCtr), this.thres + 1.U,
128                      Mux(res.satNeg(newCtr), this.thres - 1.U,
129                      this.thres))
130    res.thres := newThres
131    res.ctr := Mux(res.satPos(newCtr) || res.satNeg(newCtr), res.neutralVal, newCtr)
132    // XSDebug(true.B, p"scThres Update: cause${cause} newCtr ${newCtr} newThres ${newThres}\n")
133    res
134  }
135}
136
137object SCThreshold {
138  def apply(bits: Int) = {
139    val t = Wire(new SCThreshold(ctrBits=bits))
140    t.ctr := t.neutralVal
141    t.thres := t.minThres
142    t
143  }
144}
145
146
147trait HasSC extends HasSCParameter { this: Tage =>
148  val scTables = SCTableInfo.map {
149    case (nRows, ctrBits, histLen) => {
150      val t = if (EnableSC) Module(new SCTable(nRows/TageBanks, ctrBits, histLen)) else Module(new FakeSCTable)
151      val req = t.io.req
152      req.valid := io.pc.valid
153      req.bits.pc := io.pc.bits
154      req.bits.hist := io.hist
155      req.bits.mask := io.inMask
156      if (!EnableSC) {t.io.update := DontCare}
157      t
158    }
159  }
160
161  val scThreshold = RegInit(SCThreshold(5))
162  val useThreshold = WireInit(scThreshold.thres)
163  val updateThreshold = WireInit((useThreshold << 3) + 21.U)
164
165  val if3_scResps = VecInit(scTables.map(t => t.io.resp))
166
167  val scUpdateMask = WireInit(0.U.asTypeOf(Vec(SCNTables, Vec(TageBanks, Bool()))))
168  val scUpdateTagePreds = Wire(Vec(TageBanks, Bool()))
169  val scUpdateTakens = Wire(Vec(TageBanks, Bool()))
170  val scUpdateOldCtrs = Wire(Vec(TageBanks, Vec(SCNTables, SInt(SCCtrBits.W))))
171  scUpdateTagePreds := DontCare
172  scUpdateTakens := DontCare
173  scUpdateOldCtrs := DontCare
174
175  val updateSCMetas = VecInit(u.metas.map(_.tageMeta.scMeta))
176
177  for (w <- 0 until TageBanks) {
178    val scMeta = io.meta(w).scMeta
179    scMeta := DontCare
180    // do summation in if3
181    val if3_scTableSums = VecInit(
182      (0 to 1) map { i => {
183          if (EnableSC) {
184            (0 until SCNTables) map { j =>
185              scTables(j).getCenteredValue(if3_scResps(j)(w).ctr(i))
186            } reduce (_+_) // TODO: rewrite with adder tree
187          }
188          else 0.S
189        }
190      }
191    )
192    val providerCtr = if3_providerCtrs(w).zext()
193    val if3_pvdrCtrCentered = ((((providerCtr - 4.S) << 1).asSInt + 1.S) << 3).asSInt
194    val if3_totalSums = VecInit(if3_scTableSums.map(_  + if3_pvdrCtrCentered))
195    val if3_sumAbs = VecInit(if3_totalSums.map(_.abs.asUInt))
196    val if3_sumBelowThresholds = VecInit(if3_sumAbs.map(_ < useThreshold))
197    val if3_scPreds = VecInit(if3_totalSums.map (_ >= 0.S))
198
199    val if4_sumBelowThresholds = RegEnable(if3_sumBelowThresholds, s3_fire)
200    val if4_scPreds = RegEnable(if3_scPreds, s3_fire)
201    val if4_sumAbs = RegEnable(if3_sumAbs, s3_fire)
202
203    val if4_scCtrs = RegEnable(VecInit(if3_scResps.map(r => r(w).ctr(if3_tageTakens(w).asUInt))), s3_fire)
204    val if4_chooseBit = if4_tageTakens(w)
205    scMeta.tageTaken := if4_tageTakens(w)
206    scMeta.scUsed := if4_provideds(w)
207    scMeta.scPred := if4_scPreds(if4_chooseBit)
208    scMeta.sumAbs := if4_sumAbs(if4_chooseBit)
209    scMeta.ctrs   := if4_scCtrs
210
211
212    if (EnableSC) {
213      when (if4_provideds(w)) {
214        // Use prediction from Statistical Corrector
215        when (!if4_sumBelowThresholds(if4_chooseBit)) {
216          val pred = if4_scPreds(if4_chooseBit)
217          XSDebug(RegNext(s3_fire), p"SC(${w.U}) overriden pred to ${pred}\n")
218          io.resp.takens(w) := pred
219        }
220      }
221    }
222    if (EnableSC) {
223      val updateSCMeta = updateSCMetas(w)
224      when (updateValids(w) && updateSCMeta.scUsed.asBool && updateBrMask(w)) {
225        val scPred = updateSCMeta.scPred
226        val tagePred = updateSCMeta.tageTaken
227        val taken = u.takens(w)
228        val sumAbs = updateSCMeta.sumAbs.asUInt
229        val scOldCtrs = updateSCMeta.ctrs
230        scUpdateTagePreds(w) := tagePred
231        scUpdateTakens(w) := taken
232        (scUpdateOldCtrs(w) zip scOldCtrs).foreach{case (t, c) => t := c}
233
234        when (scPred =/= tagePred && sumAbs < useThreshold - 2.U) {
235          val newThres = scThreshold.update(scPred =/= taken)
236          scThreshold := newThres
237          XSDebug(p"scThres update: old d${useThreshold} --> new ${newThres.thres}\n")
238        }
239        when (scPred =/= taken || sumAbs < updateThreshold) {
240          scUpdateMask.foreach(t => t(w) := true.B)
241          XSDebug(p"scUpdate: bank(${w}), scPred(${scPred}), tagePred(${tagePred}), scSumAbs(${sumAbs}), mispred: sc(${updateMisPred}), tage(${updateTageMisPreds(w)})\n")
242          XSDebug(p"update: sc: ${updateSCMeta}\n")
243        }
244      }
245    }
246    for (i <- 0 until SCNTables) {
247      scTables(i).io.update.mask := RegNext(scUpdateMask(i))
248      scTables(i).io.update.tagePreds := RegNext(scUpdateTagePreds)
249      scTables(i).io.update.takens    := RegNext(scUpdateTakens)
250      scTables(i).io.update.oldCtrs   := RegNext(VecInit(scUpdateOldCtrs.map(_(i))))
251      scTables(i).io.update.pc := RegNext(u.ftqPC)
252      scTables(i).io.update.hist := RegNext(updateHist)
253    }
254  }
255}