xref: /XiangShan/src/main/scala/xiangshan/frontend/FauFTB.scala (revision fd3aa0577117b390ca78476eb2755133f758af37)
111d0c81dSLingrui98/***************************************************************************************
211d0c81dSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
311d0c81dSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
411d0c81dSLingrui98*
511d0c81dSLingrui98* XiangShan is licensed under Mulan PSL v2.
611d0c81dSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
711d0c81dSLingrui98* You may obtain a copy of Mulan PSL v2 at:
811d0c81dSLingrui98*          http://license.coscl.org.cn/MulanPSL2
911d0c81dSLingrui98*
1011d0c81dSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
1111d0c81dSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
1211d0c81dSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
1311d0c81dSLingrui98*
1411d0c81dSLingrui98* See the Mulan PSL v2 for more details.
1511d0c81dSLingrui98***************************************************************************************/
1611d0c81dSLingrui98
1711d0c81dSLingrui98package xiangshan.frontend
1811d0c81dSLingrui98
198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
2011d0c81dSLingrui98import chisel3._
2111d0c81dSLingrui98import chisel3.util._
2211d0c81dSLingrui98import utils._
233c02ee8fSwakafaimport utility._
2411d0c81dSLingrui98import xiangshan._
2511d0c81dSLingrui98import scala.{Tuple2 => &}
2611d0c81dSLingrui98
2711d0c81dSLingrui98trait FauFTBParams extends HasXSParameter with HasBPUConst {
2811d0c81dSLingrui98  val numWays = 32
2911d0c81dSLingrui98  val tagSize = 16
3011d0c81dSLingrui98
3111d0c81dSLingrui98  val TAR_STAT_SZ = 2
3211d0c81dSLingrui98  def TAR_FIT = 0.U(TAR_STAT_SZ.W)
3311d0c81dSLingrui98  def TAR_OVF = 1.U(TAR_STAT_SZ.W)
3411d0c81dSLingrui98  def TAR_UDF = 2.U(TAR_STAT_SZ.W)
3511d0c81dSLingrui98
3611d0c81dSLingrui98  def BR_OFFSET_LEN = 12
3711d0c81dSLingrui98  def JMP_OFFSET_LEN = 20
3811d0c81dSLingrui98
3911d0c81dSLingrui98  def getTag(pc: UInt) = pc(tagSize+instOffsetBits-1, instOffsetBits)
4011d0c81dSLingrui98}
4111d0c81dSLingrui98
4211d0c81dSLingrui98class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {}
4311d0c81dSLingrui98
4411d0c81dSLingrui98class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams {
4511d0c81dSLingrui98  val io = IO(new Bundle{
4611d0c81dSLingrui98    val req_tag = Input(UInt(tagSize.W))
4711d0c81dSLingrui98    val resp = Output(new FauFTBEntry)
4811d0c81dSLingrui98    val resp_hit = Output(Bool())
4911d0c81dSLingrui98    val update_req_tag = Input(UInt(tagSize.W))
5011d0c81dSLingrui98    val update_hit = Output(Bool())
5111d0c81dSLingrui98    val write_valid = Input(Bool())
5211d0c81dSLingrui98    val write_entry = Input(new FauFTBEntry)
5311d0c81dSLingrui98    val write_tag = Input(UInt(tagSize.W))
5411d0c81dSLingrui98    val tag_read = Output(UInt(tagSize.W))
5511d0c81dSLingrui98  })
5611d0c81dSLingrui98
5711d0c81dSLingrui98  val data = Reg(new FauFTBEntry)
5811d0c81dSLingrui98  val tag = Reg(UInt(tagSize.W))
5911d0c81dSLingrui98  val valid = RegInit(false.B)
6011d0c81dSLingrui98
6111d0c81dSLingrui98  io.resp := data
6211d0c81dSLingrui98  io.resp_hit := tag === io.req_tag && valid
6311d0c81dSLingrui98  // write bypass to avoid multiple hit
6411d0c81dSLingrui98  io.update_hit := ((tag === io.update_req_tag) && valid) ||
6511d0c81dSLingrui98                   ((io.write_tag === io.update_req_tag) && io.write_valid)
6611d0c81dSLingrui98  io.tag_read := tag
6711d0c81dSLingrui98
6811d0c81dSLingrui98  when (io.write_valid) {
6911d0c81dSLingrui98    when (!valid) {
7011d0c81dSLingrui98      valid := true.B
7111d0c81dSLingrui98    }
7211d0c81dSLingrui98    tag   := io.write_tag
7311d0c81dSLingrui98    data  := io.write_entry
7411d0c81dSLingrui98  }
7511d0c81dSLingrui98}
7611d0c81dSLingrui98
7711d0c81dSLingrui98
7811d0c81dSLingrui98class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
7911d0c81dSLingrui98
8011d0c81dSLingrui98  class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams {
81deb3a97eSGao-Zeyu    val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None
8211d0c81dSLingrui98    val hit = Bool()
8311d0c81dSLingrui98  }
8411d0c81dSLingrui98  val resp_meta = Wire(new FauFTBMeta)
8511d0c81dSLingrui98  override val meta_size = resp_meta.getWidth
86b60e4b0bSLingrui98  override val is_fast_pred = true
8711d0c81dSLingrui98
8811d0c81dSLingrui98
8911d0c81dSLingrui98
9011d0c81dSLingrui98  val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay))
9111d0c81dSLingrui98  // numWays * numBr
9211d0c81dSLingrui98  val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
9311d0c81dSLingrui98  val replacer = ReplacementPolicy.fromString("plru", numWays)
9411d0c81dSLingrui98  val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W))))
9511d0c81dSLingrui98
9611d0c81dSLingrui98
9711d0c81dSLingrui98  // pred req
98adc0b8dfSGuokai Chen  ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0)))
9911d0c81dSLingrui98
10011d0c81dSLingrui98  // pred resp
10111d0c81dSLingrui98  val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
10211d0c81dSLingrui98  val s1_hit = s1_hit_oh.orR
10311d0c81dSLingrui98  val s1_hit_way = OHToUInt(s1_hit_oh)
10411d0c81dSLingrui98  val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction))
10511d0c81dSLingrui98
10611d0c81dSLingrui98  val s1_all_entries = VecInit(ways.map(_.io.resp))
10711d0c81dSLingrui98  for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) {
10811d0c81dSLingrui98    fp.hit := DontCare
109*fd3aa057SYuandongliang    fp.multiHit := false.B
110adc0b8dfSGuokai Chen    fp.fromFtbEntry(e, s1_pc_dup(0))
11111d0c81dSLingrui98    for (i <- 0 until numBr) {
11211d0c81dSLingrui98      fp.br_taken_mask(i) := c(i)(1) || e.always_taken(i)
11311d0c81dSLingrui98    }
11411d0c81dSLingrui98  }
11511d0c81dSLingrui98  val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
116*fd3aa057SYuandongliang  val s1_hit_fauftbentry  = Mux1H(s1_hit_oh, s1_all_entries)
11711d0c81dSLingrui98  XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n")
11811d0c81dSLingrui98  val fauftb_enable = RegNext(io.ctrl.ubtb_enable)
119adc0b8dfSGuokai Chen  io.out.s1.full_pred.map(_ := s1_hit_full_pred)
120adc0b8dfSGuokai Chen  io.out.s1.full_pred.map(_ .hit := s1_hit && fauftb_enable)
121*fd3aa057SYuandongliang  io.fauftb_entry_out := s1_hit_fauftbentry
122*fd3aa057SYuandongliang  io.fauftb_entry_hit_out := s1_hit && fauftb_enable
123*fd3aa057SYuandongliang
124*fd3aa057SYuandongliang  // Illegal check for FTB entry reading
125*fd3aa057SYuandongliang  val uftb_read_fallThrough = s1_hit_fauftbentry.getFallThrough(s1_pc_dup(0))
126*fd3aa057SYuandongliang  when(io.s1_fire(0) && s1_hit){
127*fd3aa057SYuandongliang    assert(s1_pc_dup(0) + (FetchWidth * 4).U >= uftb_read_fallThrough, s"FauFTB entry fallThrough address error!")
128*fd3aa057SYuandongliang  }
12911d0c81dSLingrui98
13011d0c81dSLingrui98  // assign metas
13111d0c81dSLingrui98  io.out.last_stage_meta := resp_meta.asUInt
132adc0b8dfSGuokai Chen  resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0))
133deb3a97eSGao-Zeyu  if(resp_meta.pred_way.isDefined) {resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0))}
13411d0c81dSLingrui98
13511d0c81dSLingrui98  // pred update replacer state
136adc0b8dfSGuokai Chen  val s1_fire = io.s1_fire(0)
137adc0b8dfSGuokai Chen  replacer_touch_ways(0).valid := RegNext(s1_fire(0) && s1_hit)
138adc0b8dfSGuokai Chen  replacer_touch_ways(0).bits  := RegEnable(s1_hit_way, s1_fire(0) && s1_hit)
13911d0c81dSLingrui98
14011d0c81dSLingrui98  /********************** update ***********************/
14111d0c81dSLingrui98  // s0: update_valid, read and tag comparison
14211d0c81dSLingrui98  // s1: alloc_way and write
14311d0c81dSLingrui98
14411d0c81dSLingrui98  // s0
14511d0c81dSLingrui98  val u = io.update
14611d0c81dSLingrui98  val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
14711d0c81dSLingrui98  val u_s0_tag = getTag(u.bits.pc)
14811d0c81dSLingrui98  ways.foreach(_.io.update_req_tag := u_s0_tag)
14911d0c81dSLingrui98  val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt
15011d0c81dSLingrui98  val u_s0_hit = u_s0_hit_oh.orR
15111d0c81dSLingrui98  val u_s0_br_update_valids =
15211d0c81dSLingrui98    VecInit((0 until numBr).map(w =>
15311d0c81dSLingrui98      u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) &&
15411d0c81dSLingrui98      !(PriorityEncoder(u.bits.br_taken_mask) < w.U)))
15511d0c81dSLingrui98
15611d0c81dSLingrui98  // s1
15711d0c81dSLingrui98  val u_s1_valid = RegNext(u.valid)
15811d0c81dSLingrui98  val u_s1_tag       = RegEnable(u_s0_tag, u.valid)
15911d0c81dSLingrui98  val u_s1_hit_oh    = RegEnable(u_s0_hit_oh, u.valid)
16011d0c81dSLingrui98  val u_s1_hit       = RegEnable(u_s0_hit, u.valid)
16111d0c81dSLingrui98  val u_s1_alloc_way = replacer.way
16211d0c81dSLingrui98  val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
16311d0c81dSLingrui98  val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
16411d0c81dSLingrui98  val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid))
16511d0c81dSLingrui98  for (w <- 0 until numWays) {
16611d0c81dSLingrui98    ways(w).io.write_valid := u_s1_ways_write_valid(w)
16711d0c81dSLingrui98    ways(w).io.write_tag   := u_s1_tag
16811d0c81dSLingrui98    ways(w).io.write_entry := u_s1_ftb_entry
16911d0c81dSLingrui98  }
17011d0c81dSLingrui98
171*fd3aa057SYuandongliang  // Illegal check for FTB entry writing
172*fd3aa057SYuandongliang  val uftb_write_pc = RegEnable(u.bits.pc, u.valid)
173*fd3aa057SYuandongliang  val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc)
174*fd3aa057SYuandongliang  when(u_s1_valid && u_s1_hit){
175*fd3aa057SYuandongliang    assert(uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough, s"FauFTB write entry fallThrough address error!")
176*fd3aa057SYuandongliang  }
177*fd3aa057SYuandongliang
17811d0c81dSLingrui98  // update saturating counters
17911d0c81dSLingrui98  val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid)
18011d0c81dSLingrui98  val u_s1_br_takens        = RegEnable(u.bits.br_taken_mask,  u.valid)
18111d0c81dSLingrui98  for (w <- 0 until numWays) {
18211d0c81dSLingrui98    when (u_s1_ways_write_valid(w)) {
18311d0c81dSLingrui98      for (br <- 0 until numBr) {
18411d0c81dSLingrui98        when (u_s1_br_update_valids(br)) {
18511d0c81dSLingrui98          ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br))
18611d0c81dSLingrui98        }
18711d0c81dSLingrui98      }
18811d0c81dSLingrui98    }
18911d0c81dSLingrui98  }
19011d0c81dSLingrui98
19111d0c81dSLingrui98  // commit update replacer state
19211d0c81dSLingrui98  replacer_touch_ways(1).valid := u_s1_valid
19311d0c81dSLingrui98  replacer_touch_ways(1).bits  := OHToUInt(u_s1_write_way_oh)
19411d0c81dSLingrui98
19511d0c81dSLingrui98  /******** update replacer *********/
19611d0c81dSLingrui98  replacer.access(replacer_touch_ways)
19711d0c81dSLingrui98
19811d0c81dSLingrui98
19911d0c81dSLingrui98  /********************** perf counters **********************/
200adc0b8dfSGuokai Chen  val s0_fire_next_cycle = RegNext(io.s0_fire(0))
20111d0c81dSLingrui98  val u_pred_hit_way_map   = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
20211d0c81dSLingrui98  XSPerfAccumulate("uftb_read_hits",   s0_fire_next_cycle &&  s1_hit)
20311d0c81dSLingrui98  XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit)
20411d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_hits",   u.valid &&  u_meta.hit)
20511d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit)
20611d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR)
20711d0c81dSLingrui98  for (w <- 0 until numWays) {
20811d0c81dSLingrui98    XSPerfAccumulate(f"uftb_pred_hit_way_${w}",   u_pred_hit_way_map(w))
20911d0c81dSLingrui98    XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U)
21011d0c81dSLingrui98  }
21111d0c81dSLingrui98
212deb3a97eSGao-Zeyu  if(u_meta.pred_way.isDefined) {
213deb3a97eSGao-Zeyu    val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way.get === w.U)
214deb3a97eSGao-Zeyu    for (w <- 0 until numWays) {
215deb3a97eSGao-Zeyu      XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w))
216deb3a97eSGao-Zeyu    }
217deb3a97eSGao-Zeyu  }
218deb3a97eSGao-Zeyu
21911d0c81dSLingrui98  override val perfEvents = Seq(
22011d0c81dSLingrui98    ("fauftb_commit_hit       ", u.valid &&  u_meta.hit),
22111d0c81dSLingrui98    ("fauftb_commit_miss      ", u.valid && !u_meta.hit),
22211d0c81dSLingrui98  )
22311d0c81dSLingrui98  generatePerfEvent()
22411d0c81dSLingrui98
22511d0c81dSLingrui98}