FTB.scala 13.5 KB
Newer Older
Z
zoujr 已提交
1 2
/***************************************************************************************
* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
L
Lingrui98 已提交
3
* Copyright (c) 2020-2021 Peng Cheng Laboratory
Z
zoujr 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
*
* XiangShan is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

package xiangshan.frontend

import chipsalliance.rocketchip.config.Parameters
import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util._
import xiangshan._
import utils._
import chisel3.experimental.chiselName

import scala.math.min


trait FTBParams extends HasXSParameter with HasBPUConst {
31
  val numEntries = 4096
Z
zoujr 已提交
32 33 34
  val numWays    = 4
  val numSets    = numEntries/numWays // 512
  val tagSize    = 20
35 36 37 38 39 40 41 42

  val TAR_STAT_SZ = 2
  def TAR_FIT = 0.U(TAR_STAT_SZ.W)
  def TAR_OVF = 1.U(TAR_STAT_SZ.W)
  def TAR_UDF = 2.U(TAR_STAT_SZ.W)

  def BR_OFFSET_LEN = 13
  def JMP_OFFSET_LEN = 21
Z
zoujr 已提交
43 44
}

L
Lingrui98 已提交
45
class FTBEntry(implicit p: Parameters) extends XSBundle with FTBParams with BPUUtils {
Z
zoujr 已提交
46 47
  val valid       = Bool()

Z
zoujr 已提交
48
  val brOffset    = Vec(numBr, UInt(log2Up(FetchWidth*2).W))
49 50
  val brLowers    = Vec(numBr, UInt(BR_OFFSET_LEN.W))
  val brTarStats  = Vec(numBr, UInt(TAR_STAT_SZ.W))
Z
zoujr 已提交
51
  val brValids    = Vec(numBr, Bool())
Z
zoujr 已提交
52

L
Lingrui98 已提交
53
  val jmpOffset = UInt(log2Ceil(PredictWidth).W)
54 55
  val jmpLower   = UInt(JMP_OFFSET_LEN.W)
  val jmpTarStat = UInt(TAR_STAT_SZ.W)
Z
zoujr 已提交
56
  val jmpValid    = Bool()
Z
zoujr 已提交
57 58

  // Partial Fall-Through Address
59
  val pftAddr     = UInt((log2Up(PredictWidth)+1).W)
Z
zoujr 已提交
60 61
  val carry       = Bool()

Z
zoujr 已提交
62 63 64
  val isCall      = Bool()
  val isRet       = Bool()
  val isJalr      = Bool()
Z
zoujr 已提交
65 66

  val oversize    = Bool()
Z
zoujr 已提交
67 68

  val last_is_rvc = Bool()
69 70
  
  val always_taken = Vec(numBr, Bool())
71

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  def getTarget(offsetLen: Int)(pc: UInt, lower: UInt, stat: UInt) = {
    val higher = pc(VAddrBits-1, offsetLen)
    Cat(
      Mux(stat === TAR_OVF, higher+1.U,
        Mux(stat === TAR_UDF, higher-1.U, higher)),
      lower
    )
  }
  val getBrTarget = getTarget(BR_OFFSET_LEN)(_, _, _)

  def getBrTargets(pc: UInt) = {
    VecInit((brLowers zip brTarStats).map{
      case (lower, stat) => getBrTarget(pc, lower, stat)
    })
  }

  def getJmpTarget(pc: UInt) = getTarget(JMP_OFFSET_LEN)(pc, jmpLower, jmpTarStat)

  def getLowerStatByTarget(offsetLen: Int)(pc: UInt, target: UInt) = {
    val pc_higher = pc(VAddrBits-1, offsetLen)
92
    val target_higher = target(VAddrBits-1, offsetLen)
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    val stat = WireInit(Mux(target_higher > pc_higher, TAR_OVF,
      Mux(target_higher < pc_higher, TAR_UDF, TAR_FIT)))
    val lower = WireInit(target(offsetLen-1, 0))
    (lower, stat)
  }
  def getBrLowerStatByTarget(pc: UInt, target: UInt) = getLowerStatByTarget(BR_OFFSET_LEN)(pc, target)
  def getJmpLowerStatByTarget(pc: UInt, target: UInt) = getLowerStatByTarget(JMP_OFFSET_LEN)(pc, target)
  def setByBrTarget(brIdx: Int, pc: UInt, target: UInt) = {
    val (lower, stat) = getBrLowerStatByTarget(pc, target)
    this.brLowers(brIdx) := lower
    this.brTarStats(brIdx) := stat
  }
  def setByJmpTarget(pc: UInt, target: UInt) = {
    val (lower, stat) = getJmpLowerStatByTarget(pc, target)
    this.jmpLower := lower
    this.jmpTarStat := stat
  }


112
  def getOffsetVec = VecInit(brOffset :+ jmpOffset)
L
Lingrui98 已提交
113
  def isJal = !isJalr
L
Lingrui98 已提交
114
  def getFallThrough(pc: UInt) = getFallThroughAddr(pc, carry, pftAddr)
115 116 117
  def hasBr(offset: UInt) = (brValids zip brOffset).map{
    case (v, off) => v && off <= offset
  }.reduce(_||_)
Z
zoujr 已提交
118

119 120 121 122 123 124 125
  def getBrMaskByOffset(offset: UInt) = (brValids zip brOffset).map{
    case (v, off) => v && off <= offset
  }
  
  def brIsSaved(offset: UInt) = (brValids zip brOffset).map{
    case (v, off) => v && off === offset
  }.reduce(_||_)
Z
zoujr 已提交
126 127
  def display(cond: Bool): Unit = {
    XSDebug(cond, p"-----------FTB entry----------- \n")
L
Lingrui98 已提交
128
    XSDebug(cond, p"v=${valid}\n")
Z
zoujr 已提交
129
    for(i <- 0 until numBr) {
130
      XSDebug(cond, p"[br$i]: v=${brValids(i)}, offset=${brOffset(i)}, lower=${Hexadecimal(brLowers(i))}\n")
Z
zoujr 已提交
131
    }
132
    XSDebug(cond, p"[jmp]: v=${jmpValid}, offset=${jmpOffset}, lower=${Hexadecimal(jmpLower)}\n")
Z
zoujr 已提交
133 134 135 136
    XSDebug(cond, p"pftAddr=${Hexadecimal(pftAddr)}, carry=$carry\n")
    XSDebug(cond, p"isCall=$isCall, isRet=$isRet, isjalr=$isJalr\n")
    XSDebug(cond, p"oversize=$oversize, last_is_rvc=$last_is_rvc\n")
    XSDebug(cond, p"------------------------------- \n")
Z
zoujr 已提交
137
  }
L
Lingrui98 已提交
138 139 140 141 142 143 144 145 146 147

}

class FTBEntryWithTag(implicit p: Parameters) extends XSBundle with FTBParams with BPUUtils {
  val entry = new FTBEntry
  val tag = UInt(tagSize.W)
  def display(cond: Bool): Unit = {
    XSDebug(cond, p"-----------FTB entry----------- \n")
    XSDebug(cond, p"v=${entry.valid}, tag=${Hexadecimal(tag)}\n")
    for(i <- 0 until numBr) {
148
      XSDebug(cond, p"[br$i]: v=${entry.brValids(i)}, offset=${entry.brOffset(i)}, lower=${Hexadecimal(entry.brLowers(i))}\n")
L
Lingrui98 已提交
149
    }
150
    XSDebug(cond, p"[jmp]: v=${entry.jmpValid}, offset=${entry.jmpOffset}, lower=${Hexadecimal(entry.jmpLower)}\n")
L
Lingrui98 已提交
151 152 153 154 155
    XSDebug(cond, p"pftAddr=${Hexadecimal(entry.pftAddr)}, carry=${entry.carry}\n")
    XSDebug(cond, p"isCall=${entry.isCall}, isRet=${entry.isRet}, isjalr=${entry.isJalr}\n")
    XSDebug(cond, p"oversize=${entry.oversize}, last_is_rvc=${entry.last_is_rvc}\n")
    XSDebug(cond, p"------------------------------- \n")
  }
Z
zoujr 已提交
156 157 158
}

class FTBMeta(implicit p: Parameters) extends XSBundle with FTBParams {
Z
zoujr 已提交
159
  val writeWay = UInt(numWays.W)
Z
zoujr 已提交
160
  val hit = Bool()
Z
zoujr 已提交
161
  val pred_cycle = UInt(64.W) // TODO: Use Option
Z
zoujr 已提交
162 163 164
}

object FTBMeta {
Z
zoujr 已提交
165
  def apply(writeWay: UInt, hit: Bool, pred_cycle: UInt)(implicit p: Parameters): FTBMeta = {
Z
zoujr 已提交
166 167 168
    val e = Wire(new FTBMeta)
    e.writeWay := writeWay
    e.hit := hit
Z
zoujr 已提交
169
    e.pred_cycle := pred_cycle
Z
zoujr 已提交
170 171 172 173
    e
  }
}

174
class FTB(implicit p: Parameters) extends BasePredictor with FTBParams with BPUUtils {
Z
zoujr 已提交
175 176
  override val meta_size = WireInit(0.U.asTypeOf(new FTBMeta)).getWidth

Z
zoujr 已提交
177
  val ftbAddr = new TableAddr(log2Up(numSets), 1)
Z
zoujr 已提交
178

Z
zoujr 已提交
179 180
  class FTBBank(val numSets: Int, val nWays: Int) extends XSModule with BPUUtils {
    val io = IO(new Bundle {
L
Lingrui98 已提交
181
      val req_pc = Flipped(DecoupledIO(UInt(VAddrBits.W)))
Z
zoujr 已提交
182 183 184 185 186 187 188
      val read_resp = Output(new FTBEntry)

      // when ftb hit, read_hits.valid is true, and read_hits.bits is OH of hit way
      // when ftb not hit, read_hits.valid is false, and read_hits is OH of allocWay
      val read_hits = Valid(Vec(numWays, Bool()))

      val update_pc = Input(UInt(VAddrBits.W))
L
Lingrui98 已提交
189
      val update_write_data = Flipped(Valid(new FTBEntryWithTag))
Z
zoujr 已提交
190 191 192
      val update_write_mask = Input(UInt(numWays.W))
    })

L
Lingrui98 已提交
193
    val ftb = Module(new SRAMTemplate(new FTBEntryWithTag, set = numSets, way = numWays, shouldReset = true, holdRead = true, singlePort = true))
Z
zoujr 已提交
194

L
Lingrui98 已提交
195 196
    ftb.io.r.req.valid := io.req_pc.valid // io.s0_fire
    ftb.io.r.req.bits.setIdx := ftbAddr.getIdx(io.req_pc.bits) // s0_idx
Z
zoujr 已提交
197

L
Lingrui98 已提交
198
    io.req_pc.ready := ftb.io.r.req.ready
Z
zoujr 已提交
199

L
Lingrui98 已提交
200
    val req_tag = RegEnable(ftbAddr.getTag(io.req_pc.bits)(tagSize-1, 0), io.req_pc.valid)
201
    val req_idx = RegEnable(ftbAddr.getIdx(io.req_pc.bits), io.req_pc.valid)
Z
zoujr 已提交
202

L
Lingrui98 已提交
203 204
    val read_entries = ftb.io.r.resp.data.map(_.entry)
    val read_tags    = ftb.io.r.resp.data.map(_.tag)
Z
zoujr 已提交
205

206
    val total_hits = VecInit((0 until numWays).map(b => read_tags(b) === req_tag && read_entries(b).valid && RegNext(io.req_pc.valid)))
Z
zoujr 已提交
207 208
    val hit = total_hits.reduce(_||_)
    val hit_way_1h = VecInit(PriorityEncoderOH(total_hits))
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
    
    val replacer = ReplacementPolicy.fromString(Some("setplru"), numWays, numSets)
    val allocWriteWay = replacer.way(req_idx)

    val touch_set = Seq.fill(1)(Wire(UInt(log2Ceil(numSets).W)))
    val touch_way = Seq.fill(1)(Wire(Valid(UInt(log2Ceil(numWays).W))))
    
    replacer.access(touch_set, touch_way)
    
    touch_set(0) := req_idx
    
    touch_way(0).valid := hit
    touch_way(0).bits := OHToUInt(hit_way_1h)

    // def allocWay(valids: UInt, meta_tags: UInt, req_tag: UInt) = {
    //   val randomAlloc = false
    //   if (numWays > 1) {
    //     val w = Wire(UInt(log2Up(numWays).W))
    //     val valid = WireInit(valids.andR)
    //     val tags = Cat(meta_tags, req_tag)
    //     val l = log2Up(numWays)
    //     val nChunks = (tags.getWidth + l - 1) / l
    //     val chunks = (0 until nChunks).map( i =>
    //       tags(min((i+1)*l, tags.getWidth)-1, i*l)
    //     )
    //     w := Mux(valid, if (randomAlloc) {LFSR64()(log2Up(numWays)-1,0)} else {chunks.reduce(_^_)}, PriorityEncoder(~valids))
    //     w
    //   } else {
    //     val w = WireInit(0.U)
    //     w
    //   }
    // }

    // val allocWriteWay = allocWay(
    //   VecInit(read_entries.map(_.valid)).asUInt,
    //   VecInit(read_tags).asUInt,
    //   req_tag
    // )
Z
zoujr 已提交
247

L
Lingrui98 已提交
248
    io.read_resp := PriorityMux(total_hits, read_entries) // Mux1H
Z
zoujr 已提交
249 250
    io.read_hits.valid := hit
    io.read_hits.bits := Mux(hit, hit_way_1h, VecInit(UIntToOH(allocWriteWay).asBools()))
251 252
    
    XSDebug(!hit, "FTB not hit, alloc a way: %d\n", allocWriteWay)
Z
zoujr 已提交
253

Z
zoujr 已提交
254 255 256 257 258
    // Update logic
    val u_valid = io.update_write_data.valid
    val u_data = io.update_write_data.bits
    val u_idx = ftbAddr.getIdx(io.update_pc)
    val u_mask = io.update_write_mask
Z
zoujr 已提交
259

Z
zoujr 已提交
260 261
    ftb.io.w.apply(u_valid, u_data, u_idx, u_mask)
  } // FTBBank
Z
zoujr 已提交
262

Z
zoujr 已提交
263
  val ftbBank = Module(new FTBBank(numSets, numWays))
Z
zoujr 已提交
264

L
Lingrui98 已提交
265 266
  ftbBank.io.req_pc.valid := io.s0_fire
  ftbBank.io.req_pc.bits := s0_pc
Z
zoujr 已提交
267

L
Lingrui98 已提交
268
  io.s1_ready := ftbBank.io.req_pc.ready //  && !io.redirect.valid
Z
zoujr 已提交
269

270
  val ftb_entry = RegEnable(ftbBank.io.read_resp, io.s1_fire)
Z
zoujr 已提交
271 272 273
  val s1_hit = ftbBank.io.read_hits.valid
  val s2_hit = RegEnable(s1_hit, io.s1_fire)
  val writeWay = ftbBank.io.read_hits.bits
Z
zoujr 已提交
274

275
  val fallThruAddr = getFallThroughAddr(s2_pc, ftb_entry.carry, ftb_entry.pftAddr)
276

277
  // io.out.bits.resp := RegEnable(io.in.bits.resp_in(0), 0.U.asTypeOf(new BranchPredictionResp), io.s1_fire)
Z
zoujr 已提交
278
  io.out.resp := io.in.bits.resp_in(0)
Z
zoujr 已提交
279

Z
zoujr 已提交
280 281
  val s1_latch_call_is_rvc   = DontCare // TODO: modify when add RAS

282
  io.out.resp.s2.preds.taken_mask    := io.in.bits.resp_in(0).s2.preds.taken_mask
283 284 285 286 287
  for (i <- 0 until numBr) {
    when (ftb_entry.always_taken(i)) {
      io.out.resp.s2.preds.taken_mask(i) := true.B
    }
  }
288 289 290 291

  io.out.resp.s2.preds.hit           := s2_hit
  io.out.resp.s2.pc                  := s2_pc
  io.out.resp.s2.ftb_entry           := ftb_entry
292
  io.out.resp.s2.preds.fromFtbEntry(ftb_entry, s2_pc)
293

Z
zoujr 已提交
294
  io.out.s3_meta                     := RegEnable(RegEnable(FTBMeta(writeWay.asUInt(), s1_hit, GTimer()).asUInt(), io.s1_fire), io.s2_fire)
Z
zoujr 已提交
295

Z
zoujr 已提交
296
  when(s2_hit) {
297 298
    io.out.resp.s2.ftb_entry.pftAddr := ftb_entry.pftAddr
    io.out.resp.s2.ftb_entry.carry := ftb_entry.carry
Z
zoujr 已提交
299
  }.otherwise {
300 301
    io.out.resp.s2.ftb_entry.pftAddr := s2_pc(instOffsetBits + log2Ceil(PredictWidth), instOffsetBits) ^ (1 << log2Ceil(PredictWidth)).U
    io.out.resp.s2.ftb_entry.carry := s2_pc(instOffsetBits + log2Ceil(PredictWidth)).asBool
302
    io.out.resp.s2.ftb_entry.oversize := false.B
303
  }
304

L
Lingrui98 已提交
305 306 307 308 309 310 311 312 313
  // always taken logic
  when (s2_hit) {
    for (i <- 0 until numBr) {
      when (ftb_entry.always_taken(i)) {
        io.out.resp.s2.preds.taken_mask(i) := true.B
      }
    }
  }

Z
zoujr 已提交
314
  // Update logic
Z
zoujr 已提交
315 316 317
  val has_update = RegInit(VecInit(Seq.fill(64)(0.U(VAddrBits.W))))
  val has_update_ptr = RegInit(0.U(log2Up(64)))

Z
zoujr 已提交
318
  val update = RegNext(io.update.bits)
Z
zoujr 已提交
319 320

  val u_meta = update.meta.asTypeOf(new FTBMeta)
321
  val u_valid = RegNext(io.update.valid && !io.update.bits.old_entry)
Z
zoujr 已提交
322
  val u_way_mask = u_meta.writeWay
Z
zoujr 已提交
323

L
Lingrui98 已提交
324 325
  val ftb_write = Wire(new FTBEntryWithTag)
  ftb_write.entry := update.ftb_entry
Z
zoujr 已提交
326 327 328 329 330 331
  ftb_write.tag   := ftbAddr.getTag(update.pc)(tagSize-1, 0)

  ftbBank.io.update_write_data.valid := u_valid
  ftbBank.io.update_write_data.bits := ftb_write
  ftbBank.io.update_pc := update.pc
  ftbBank.io.update_write_mask := u_way_mask
Z
zoujr 已提交
332 333 334 335 336 337 338 339 340 341

  val r_updated = (0 until 64).map(i => has_update(i) === s1_pc).reduce(_||_)
  val u_updated = (0 until 64).map(i => has_update(i) === update.pc).reduce(_||_)

  when(u_valid) {
    when(!u_updated) { has_update(has_update_ptr) := update.pc }

    has_update_ptr := has_update_ptr + !u_updated
  }

L
Lingrui98 已提交
342 343 344 345 346
  XSDebug("req_v=%b, req_pc=%x, ready=%b (resp at next cycle)\n", io.s0_fire, s0_pc, ftbBank.io.req_pc.ready)
  XSDebug("s2_hit=%b, hit_way=%b\n", s2_hit, writeWay.asUInt)
  XSDebug("s2_taken_mask=%b, s2_real_taken_mask=%b\n",
    io.in.bits.resp_in(0).s2.preds.taken_mask.asUInt, io.out.resp.s2.real_taken_mask().asUInt)
  XSDebug("s2_target=%x\n", io.out.resp.s2.target)
Z
zoujr 已提交
347

L
Lingrui98 已提交
348
  ftb_entry.display(true.B)
Z
zoujr 已提交
349

L
Lingrui98 已提交
350 351 352
  XSDebug(u_valid, "Update from ftq\n")
  XSDebug(u_valid, "update_pc=%x, tag=%x, update_write_way=%b, pred_cycle=%d\n",
    update.pc, ftbAddr.getTag(update.pc), u_way_mask, u_meta.pred_cycle)
Z
zoujr 已提交
353 354


Z
zoujr 已提交
355 356 357



L
Lingrui98 已提交
358 359
  XSPerfAccumulate("ftb_first_miss", u_valid && !u_updated && !update.preds.hit)
  XSPerfAccumulate("ftb_updated_miss", u_valid && u_updated && !update.preds.hit)
Z
zoujr 已提交
360

L
Lingrui98 已提交
361 362
  XSPerfAccumulate("ftb_read_first_miss", RegNext(io.s0_fire) && !s1_hit && !r_updated)
  XSPerfAccumulate("ftb_read_updated_miss", RegNext(io.s0_fire) && !s1_hit && r_updated)
Z
zoujr 已提交
363

L
Lingrui98 已提交
364 365
  XSPerfAccumulate("ftb_read_hits", RegNext(io.s0_fire) && s1_hit)
  XSPerfAccumulate("ftb_read_misses", RegNext(io.s0_fire) && !s1_hit)
Z
zoujr 已提交
366

L
Lingrui98 已提交
367 368
  XSPerfAccumulate("ftb_commit_hits", u_valid && update.preds.hit)
  XSPerfAccumulate("ftb_commit_misses", u_valid && !update.preds.hit)
369

L
Lingrui98 已提交
370 371 372
  XSPerfAccumulate("ftb_update_req", io.update.valid)
  XSPerfAccumulate("ftb_update_ignored", io.update.valid && io.update.bits.old_entry)
  XSPerfAccumulate("ftb_updated", u_valid)
Z
zoujr 已提交
373
}