Tage.scala 14.5 KB
Newer Older
1 2 3 4 5 6 7
package xiangshan.frontend

import chisel3._
import chisel3.util._
import xiangshan._
import utils._

G
GouLingrui 已提交
8 9
import scala.math.min

10 11 12 13 14 15 16 17 18 19
trait HasTageParameter {
  //                   Sets  Hist   Tag
  val TableInfo = Seq(( 128,    2,    7),
                      ( 128,    4,    7),
                      ( 256,    8,    8),
                      ( 256,   16,    8),
                      ( 128,   32,    9),
                      ( 128,   64,    9))
  val TageNTables = TableInfo.size
  val UBitPeriod = 2048
G
GouLingrui 已提交
20
  val BankWidth = 16 // FetchWidth
G
GouLingrui 已提交
21 22 23 24 25 26

  val TotalBits = TableInfo.map {
    case (s, h, t) => {
      s * (1+t+3) * BankWidth
    }
  }.reduce(_+_)
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
}

abstract class TageBundle extends XSBundle with HasTageParameter
abstract class TageModule extends XSModule with HasTageParameter

class TageReq extends TageBundle {
  val pc = UInt(VAddrBits.W)
  val hist = UInt(HistoryLength.W)
}

class TageResp extends TageBundle {
  val ctr = UInt(3.W)
  val u = UInt(2.W)
}

class TageUpdate extends TageBundle {
  val pc = UInt(VAddrBits.W)
  val hist = UInt(HistoryLength.W)
  // update tag and ctr
  val mask = Vec(BankWidth, Bool())
  val taken = Vec(BankWidth, Bool())
  val alloc = Vec(BankWidth, Bool())
  val oldCtr = Vec(BankWidth, UInt(3.W))
  // update u
  val uMask = Vec(BankWidth, Bool())
  val u = Vec(BankWidth, UInt(2.W))
}

G
GouLingrui 已提交
55
class FakeTageTable() extends TageModule {
G
GouLingrui 已提交
56 57 58 59 60 61 62 63 64
  val io = IO(new Bundle() {
    val req = Input(Valid(new TageReq))
    val resp = Output(Vec(BankWidth, Valid(new TageResp)))
    val update = Input(new TageUpdate)
  })
  io.resp := DontCare

}

65
class TageTable(val nRows: Int, val histLen: Int, val tagLen: Int, val uBitPeriod: Int) extends TageModule {
66 67 68 69 70 71
  val io = IO(new Bundle() {
    val req = Input(Valid(new TageReq))
    val resp = Output(Vec(BankWidth, Valid(new TageResp)))
    val update = Input(new TageUpdate)
  })

G
GouLingrui 已提交
72 73
  // bypass entries for tage update
  val wrBypassEntries = 8
G
GouLingrui 已提交
74

G
GouLingrui 已提交
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  def compute_folded_hist(hist: UInt, l: Int) = {
    val nChunks = (histLen + l - 1) / l
    val hist_chunks = (0 until nChunks) map {i =>
      hist(min((i+1)*l, histLen)-1, i*l)
    }
    hist_chunks.reduce(_^_)
  }

  def compute_tag_and_hash(unhashed_idx: UInt, hist: UInt) = {
    val idx_history = compute_folded_hist(hist, log2Ceil(nRows))
    val idx = (unhashed_idx ^ idx_history)(log2Ceil(nRows)-1,0)
    val tag_history = compute_folded_hist(hist, tagLen)
    // Use another part of pc to make tags
    val tag = ((unhashed_idx >> log2Ceil(nRows)) ^ tag_history)(tagLen-1,0)
    (idx, tag)
  }

  def inc_ctr(ctr: UInt, taken: Bool): UInt = {
    Mux(!taken, Mux(ctr === 0.U, 0.U, ctr - 1.U),
                Mux(ctr === 7.U, 7.U, ctr + 1.U))
  }

  val doing_reset = RegInit(true.B)
  val reset_idx = RegInit(0.U(log2Ceil(nRows).W))
  reset_idx := reset_idx + doing_reset
  when (reset_idx === (nRows-1).U) { doing_reset := false.B }

G
GouLingrui 已提交
102
  class TageEntry() extends TageBundle {
G
GouLingrui 已提交
103 104 105 106 107 108 109
    val valid = Bool()
    val tag = UInt(tagLen.W)
    val ctr = UInt(3.W)
  }

  val tageEntrySz = 1 + tagLen + 3

G
GouLingrui 已提交
110
  val (hashed_idx, tag) = compute_tag_and_hash(io.req.bits.pc, io.req.bits.hist)
G
GouLingrui 已提交
111

112 113 114
  val hi_us = List.fill(BankWidth)(Module(new SRAMTemplate(Bool(), set=nRows, shouldReset=false, holdRead=true, singlePort=false)))
  val lo_us = List.fill(BankWidth)(Module(new SRAMTemplate(Bool(), set=nRows, shouldReset=false, holdRead=true, singlePort=false)))
  val table = List.fill(BankWidth)(Module(new SRAMTemplate(new TageEntry, set=nRows, shouldReset=false, holdRead=true, singlePort=false)))
G
GouLingrui 已提交
115

G
GouLingrui 已提交
116 117 118 119
  val hi_us_r = Wire(Vec(BankWidth, Bool()))
  val lo_us_r = Wire(Vec(BankWidth, Bool()))
  val table_r = Wire(Vec(BankWidth, new TageEntry))

G
GouLingrui 已提交
120 121
  (0 until BankWidth).map(
    b => {
G
GouLingrui 已提交
122 123 124 125 126 127 128 129 130
      hi_us(b).reset := reset.asBool
      lo_us(b).reset := reset.asBool
      table(b).reset := reset.asBool
      hi_us(b).io.r.req.valid := io.req.valid
      lo_us(b).io.r.req.valid := io.req.valid
      table(b).io.r.req.valid := io.req.valid
      hi_us(b).io.r.req.bits.setIdx := hashed_idx
      lo_us(b).io.r.req.bits.setIdx := hashed_idx
      table(b).io.r.req.bits.setIdx := hashed_idx
G
GouLingrui 已提交
131
      
G
GouLingrui 已提交
132 133 134
      hi_us_r(b) := hi_us(b).io.r.resp.data(0)
      lo_us_r(b) := lo_us(b).io.r.resp.data(0)
      table_r(b) := table(b).io.r.resp.data(0)
G
GouLingrui 已提交
135

136 137 138
      // io.resp(b).valid := table_r(b).valid && table_r(b).tag === tag // Missing reset logic
      // io.resp(b).bits.ctr := table_r(b).ctr
      // io.resp(b).bits.u := Cat(hi_us_r(b),lo_us_r(b))
G
GouLingrui 已提交
139 140 141
    }
  )

G
GouLingrui 已提交
142 143 144 145 146 147 148 149 150
  val req_rhits = VecInit(table_r.map(e => e.valid && e.tag === tag && !doing_reset))

  (0 until BankWidth).map(b => {
    io.resp(b).valid := req_rhits(b)
    io.resp(b).bits.ctr := table_r(b).ctr
    io.resp(b).bits.u := Cat(hi_us_r(b),lo_us_r(b))
  })


G
GouLingrui 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163
  val clear_u_ctr = RegInit(0.U((log2Ceil(uBitPeriod) + log2Ceil(nRows) + 1).W))
  when (doing_reset) { clear_u_ctr := 1.U } .otherwise { clear_u_ctr := clear_u_ctr + 1.U }

  val doing_clear_u = clear_u_ctr(log2Ceil(uBitPeriod)-1,0) === 0.U
  val doing_clear_u_hi = doing_clear_u && clear_u_ctr(log2Ceil(uBitPeriod) + log2Ceil(nRows)) === 1.U
  val doing_clear_u_lo = doing_clear_u && clear_u_ctr(log2Ceil(uBitPeriod) + log2Ceil(nRows)) === 0.U
  val clear_u_idx = clear_u_ctr >> log2Ceil(uBitPeriod)

  val (update_idx, update_tag) = compute_tag_and_hash(io.update.pc, io.update.hist)

  val update_wdata = Wire(Vec(BankWidth, new TageEntry))

  
G
GouLingrui 已提交
164 165 166 167 168
  (0 until BankWidth).map(b => {
    table(b).io.w.req.valid := io.update.mask(b) || doing_reset
    table(b).io.w.req.bits.setIdx := Mux(doing_reset, reset_idx, update_idx)
    table(b).io.w.req.bits.data := Mux(doing_reset, 0.U.asTypeOf(new TageEntry), update_wdata(b))
  })
G
GouLingrui 已提交
169 170

  val update_hi_wdata = Wire(Vec(BankWidth, Bool()))
G
GouLingrui 已提交
171 172 173 174 175
  (0 until BankWidth).map(b => {
    hi_us(b).io.w.req.valid := io.update.uMask(b) || doing_reset || doing_clear_u_hi
    hi_us(b).io.w.req.bits.setIdx := Mux(doing_reset, reset_idx, Mux(doing_clear_u_hi, clear_u_idx, update_idx))
    hi_us(b).io.w.req.bits.data := Mux(doing_reset || doing_clear_u_hi, 0.U, update_hi_wdata(b))
  })
G
GouLingrui 已提交
176 177

  val update_lo_wdata = Wire(Vec(BankWidth, Bool()))
G
GouLingrui 已提交
178 179 180 181 182
  (0 until BankWidth).map(b => {
    lo_us(b).io.w.req.valid := io.update.uMask(b) || doing_reset || doing_clear_u_lo
    lo_us(b).io.w.req.bits.setIdx := Mux(doing_reset, reset_idx, Mux(doing_clear_u_lo, clear_u_idx, update_idx))
    lo_us(b).io.w.req.bits.data := Mux(doing_reset || doing_clear_u_lo, 0.U, update_lo_wdata(b))
  })
G
GouLingrui 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

  val wrbypass_tags    = Reg(Vec(wrBypassEntries, UInt(tagLen.W)))
  val wrbypass_idxs    = Reg(Vec(wrBypassEntries, UInt(log2Ceil(nRows).W)))
  val wrbypass         = Reg(Vec(wrBypassEntries, Vec(BankWidth, UInt(3.W))))
  val wrbypass_enq_idx = RegInit(0.U(log2Ceil(wrBypassEntries).W))

  val wrbypass_hits    = VecInit((0 until wrBypassEntries) map { i =>
    !doing_reset &&
    wrbypass_tags(i) === update_tag &&
    wrbypass_idxs(i) === update_idx
  })
  val wrbypass_hit     = wrbypass_hits.reduce(_||_)
  val wrbypass_hit_idx = PriorityEncoder(wrbypass_hits)

  for (w <- 0 until BankWidth) {
    update_wdata(w).ctr   := Mux(io.update.alloc(w),
      Mux(io.update.taken(w), 4.U,
                              3.U
      ),
      Mux(wrbypass_hit,       inc_ctr(wrbypass(wrbypass_hit_idx)(w), io.update.taken(w)),
                              inc_ctr(io.update.oldCtr(w), io.update.taken(w))
      )
    )
    update_wdata(w).valid := true.B
    update_wdata(w).tag   := update_tag

    update_hi_wdata(w)    := io.update.u(w)(1)
    update_lo_wdata(w)    := io.update.u(w)(0)
  }

  when (io.update.mask.reduce(_||_)) {
    when (wrbypass_hits.reduce(_||_)) {
      wrbypass(wrbypass_hit_idx) := VecInit(update_wdata.map(_.ctr))
    } .otherwise {
      wrbypass     (wrbypass_enq_idx) := VecInit(update_wdata.map(_.ctr))
      wrbypass_tags(wrbypass_enq_idx) := update_tag
      wrbypass_idxs(wrbypass_enq_idx) := update_idx
      wrbypass_enq_idx := (wrbypass_enq_idx + 1.U)(log2Ceil(wrBypassEntries)-1,0)
    }
  }
G
GouLingrui 已提交
223 224 225 226
  XSDebug(io.req.valid, "tableReq: pc=0x%x, hist=%b, idx=%d, tag=%x\n", io.req.bits.pc, io.req.bits.hist, hashed_idx, tag)
  for (i <- 0 until BankWidth) {
    XSDebug(RegNext(io.req.valid), "TageTableResp[%d]: idx=%d, hit:%d, ctr:%d, u:%d\n", i.U, RegNext(hashed_idx), req_rhits(i), table_r(i).ctr, Cat(hi_us_r(i),lo_us_r(i)).asUInt)
  }
G
GouLingrui 已提交
227 228 229 230 231 232 233

}

class FakeTAGE extends TageModule {
  val io = IO(new Bundle() {
    val req = Input(Valid(new TageReq))
    val out = new Bundle {
G
GouLingrui 已提交
234 235
      val hits = Output(UInt(BankWidth.W))
      val takens = Output(Vec(BankWidth, Bool()))
G
GouLingrui 已提交
236
    }
G
GouLingrui 已提交
237
    val meta = Output(Vec(BankWidth, (new TageMeta)))
G
GouLingrui 已提交
238
    val redirectInfo = Input(new RedirectInfo)
Z
zhanglinjuan 已提交
239
  })
G
GouLingrui 已提交
240
  
G
GouLingrui 已提交
241
  io.out.hits := 0.U(BankWidth.W)
G
GouLingrui 已提交
242 243
  io.out.takens := DontCare
  io.meta := DontCare
244 245
}

G
GouLingrui 已提交
246

247 248 249 250
class Tage extends TageModule {
  val io = IO(new Bundle() {
    val req = Input(Valid(new TageReq))
    val out = new Bundle {
G
GouLingrui 已提交
251 252
      val hits = Output(UInt(BankWidth.W))
      val takens = Output(Vec(BankWidth, Bool()))
253
    }
G
GouLingrui 已提交
254
    val meta = Output(Vec(BankWidth, (new TageMeta)))
G
GouLingrui 已提交
255
    val redirectInfo = Input(new RedirectInfo)
256 257
  })

Z
zhanglinjuan 已提交
258 259
  val tables = TableInfo.map {
    case (nRows, histLen, tagLen) => {
260
      val t = if(EnableBPD) Module(new TageTable(nRows, histLen, tagLen, UBitPeriod)) else Module(new FakeTageTable)
Z
zhanglinjuan 已提交
261 262 263 264 265 266 267 268
      t.io.req <> io.req
      t
    }
  }
  val resps = VecInit(tables.map(_.io.resp))

  val updateMeta = io.redirectInfo.redirect.tageMeta
  //val updateMisPred = UIntToOH(io.redirectInfo.redirect.fetchIdx) &
G
GouLingrui 已提交
269
  //  Fill(BankWidth, (io.redirectInfo.misPred && io.redirectInfo.redirect.btbType === BTBtype.B).asUInt)
Z
zhanglinjuan 已提交
270
  val updateMisPred = io.redirectInfo.misPred && io.redirectInfo.redirect.btbType === BTBtype.B
Z
zhanglinjuan 已提交
271 272 273 274 275 276 277 278 279 280 281 282 283

  val updateMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(BankWidth, Bool()))))
  val updateUMask = WireInit(0.U.asTypeOf(Vec(TageNTables, Vec(BankWidth, Bool()))))
  val updateTaken = Wire(Vec(TageNTables, Vec(BankWidth, Bool())))
  val updateAlloc = Wire(Vec(TageNTables, Vec(BankWidth, Bool())))
  val updateOldCtr = Wire(Vec(TageNTables, Vec(BankWidth, UInt(3.W))))
  val updateU = Wire(Vec(TageNTables, Vec(BankWidth, UInt(2.W))))
  updateTaken := DontCare
  updateAlloc := DontCare
  updateOldCtr := DontCare
  updateU := DontCare

  // access tag tables and output meta info
G
GouLingrui 已提交
284
  val outHits = Wire(Vec(BankWidth, Bool()))
Z
zhanglinjuan 已提交
285 286 287 288 289 290 291 292 293 294 295 296
  for (w <- 0 until BankWidth) {
    var altPred = false.B
    val finalAltPred = WireInit(false.B)
    var provided = false.B
    var provider = 0.U
    outHits(w) := false.B
    io.out.takens(w) := false.B

    for (i <- 0 until TageNTables) {
      val hit = resps(i)(w).valid
      val ctr = resps(i)(w).bits.ctr
      when (hit) {
G
GouLingrui 已提交
297
        io.out.takens(w) := Mux(ctr === 3.U || ctr === 4.U, altPred, ctr(2)) // Use altpred on weak taken
Z
zhanglinjuan 已提交
298 299
        finalAltPred := altPred
      }
G
GouLingrui 已提交
300 301 302
      provided = provided || hit          // Once hit then provide
      provider = Mux(hit, i.U, provider)  // Use the last hit as provider
      altPred = Mux(hit, ctr(2), altPred) // Save current pred as potential altpred
Z
zhanglinjuan 已提交
303 304 305 306 307 308 309 310 311 312 313
    }
    outHits(w) := provided
    io.meta(w).provider.valid := provided
    io.meta(w).provider.bits := provider
    io.meta(w).altDiffers := finalAltPred =/= io.out.takens(w)
    io.meta(w).providerU := resps(provider)(w).bits.u
    io.meta(w).providerCtr := resps(provider)(w).bits.ctr

    // Create a mask fo tables which did not hit our query, and also contain useless entries
    // and also uses a longer history than the provider
    val allocatableSlots = (VecInit(resps.map(r => !r(w).valid && r(w).bits.u === 0.U)).asUInt &
314
      ~(LowerMask(UIntToOH(provider), TageNTables) & Fill(TageNTables, provided.asUInt))
Z
zhanglinjuan 已提交
315 316 317 318 319 320 321 322 323
    )
    val allocLFSR = LFSR64()(TageNTables - 1, 0)
    val firstEntry = PriorityEncoder(allocatableSlots)
    val maskedEntry = PriorityEncoder(allocatableSlots & allocLFSR)
    val allocEntry = Mux(allocatableSlots(maskedEntry), maskedEntry, firstEntry)
    io.meta(w).allocate.valid := allocatableSlots =/= 0.U
    io.meta(w).allocate.bits := allocEntry

    val isUpdateTaken = io.redirectInfo.valid && io.redirectInfo.redirect.fetchIdx === w.U &&
Z
zhanglinjuan 已提交
324 325
      io.redirectInfo.redirect.taken && io.redirectInfo.redirect.btbType === BTBtype.B
    when (io.redirectInfo.redirect.btbType === BTBtype.B && io.redirectInfo.valid &&  io.redirectInfo.redirect.fetchIdx === w.U) {
Z
zhanglinjuan 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
      when (updateMeta.provider.valid) {
        val provider = updateMeta.provider.bits

        updateMask(provider)(w) := true.B
        updateUMask(provider)(w) := true.B

        updateU(provider)(w) := Mux(!updateMeta.altDiffers, updateMeta.providerU,
          Mux(updateMisPred, Mux(updateMeta.providerU === 0.U, 0.U, updateMeta.providerU - 1.U),
                             Mux(updateMeta.providerU === 3.U, 3.U, updateMeta.providerU + 1.U))
        )
        updateTaken(provider)(w) := isUpdateTaken
        updateOldCtr(provider)(w) := updateMeta.providerCtr
        updateAlloc(provider)(w) := false.B
      }
    }
  }

  when (io.redirectInfo.valid && updateMisPred) {
    val idx = io.redirectInfo.redirect.fetchIdx
    val allocate = updateMeta.allocate
    when (allocate.valid) {
      updateMask(allocate.bits)(idx) := true.B
      updateTaken(allocate.bits)(idx) := io.redirectInfo.redirect.taken
      updateAlloc(allocate.bits)(idx) := true.B
      updateUMask(allocate.bits)(idx) := true.B
      updateU(allocate.bits)(idx) := 0.U
    }.otherwise {
      val provider = updateMeta.provider
354
      val decrMask = Mux(provider.valid, ~LowerMask(UIntToOH(provider.bits), TageNTables), 0.U)
Z
zhanglinjuan 已提交
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
      for (i <- 0 until TageNTables) {
        when (decrMask(i)) {
          updateUMask(i)(idx) := true.B
          updateU(i)(idx) := 0.U
        }
      }
    }
  }

  for (i <- 0 until TageNTables) {
    for (w <- 0 until BankWidth) {
      tables(i).io.update.mask(w) := updateMask(i)(w)
      tables(i).io.update.taken(w) := updateTaken(i)(w)
      tables(i).io.update.alloc(w) := updateAlloc(i)(w)
      tables(i).io.update.oldCtr(w) := updateOldCtr(i)(w)
      
      tables(i).io.update.uMask(w) := updateUMask(i)(w)
      tables(i).io.update.u(w) := updateU(i)(w)
    }
    // use fetch pc instead of instruction pc
G
GouLingrui 已提交
375
    tables(i).io.update.pc := io.redirectInfo.redirect.pc - (io.redirectInfo.redirect.fetchIdx << 1.U)
376
    tables(i).io.update.hist := io.redirectInfo.redirect.hist
Z
zhanglinjuan 已提交
377 378 379 380
  }

  io.out.hits := outHits.asUInt

G
GouLingrui 已提交
381

382
  val m = updateMeta
G
GouLingrui 已提交
383
  XSDebug(io.req.valid, "req: pc=0x%x, hist=%b\n", io.req.bits.pc, io.req.bits.hist)
384
  XSDebug(io.redirectInfo.valid, "redirect: provider(%d):%d, altDiffers:%d, providerU:%d, providerCtr:%d, allocate(%d):%d\n", m.provider.valid, m.provider.bits, m.altDiffers, m.providerU, m.providerCtr, m.allocate.valid, m.allocate.bits)
G
GouLingrui 已提交
385
  XSDebug(RegNext(io.req.valid), "resp: pc=%x, outHits=%b, takens=%b\n", RegNext(io.req.bits.pc), io.out.hits, io.out.takens.asUInt)
386
}