xref: /XiangShan/src/main/scala/xiangshan/frontend/FauFTB.scala (revision 11d0c81de7c8aef111817d974babc0d80085d414)
1*11d0c81dSLingrui98/***************************************************************************************
2*11d0c81dSLingrui98* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3*11d0c81dSLingrui98* Copyright (c) 2020-2021 Peng Cheng Laboratory
4*11d0c81dSLingrui98*
5*11d0c81dSLingrui98* XiangShan is licensed under Mulan PSL v2.
6*11d0c81dSLingrui98* You can use this software according to the terms and conditions of the Mulan PSL v2.
7*11d0c81dSLingrui98* You may obtain a copy of Mulan PSL v2 at:
8*11d0c81dSLingrui98*          http://license.coscl.org.cn/MulanPSL2
9*11d0c81dSLingrui98*
10*11d0c81dSLingrui98* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11*11d0c81dSLingrui98* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12*11d0c81dSLingrui98* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13*11d0c81dSLingrui98*
14*11d0c81dSLingrui98* See the Mulan PSL v2 for more details.
15*11d0c81dSLingrui98***************************************************************************************/
16*11d0c81dSLingrui98
17*11d0c81dSLingrui98package xiangshan.frontend
18*11d0c81dSLingrui98
19*11d0c81dSLingrui98import chipsalliance.rocketchip.config.Parameters
20*11d0c81dSLingrui98import chisel3._
21*11d0c81dSLingrui98import chisel3.util._
22*11d0c81dSLingrui98import utils._
23*11d0c81dSLingrui98import xiangshan._
24*11d0c81dSLingrui98import chisel3.experimental.chiselName
25*11d0c81dSLingrui98import scala.{Tuple2 => &}
26*11d0c81dSLingrui98
27*11d0c81dSLingrui98trait FauFTBParams extends HasXSParameter with HasBPUConst {
28*11d0c81dSLingrui98  val numWays = 32
29*11d0c81dSLingrui98  val tagSize = 16
30*11d0c81dSLingrui98
31*11d0c81dSLingrui98  val TAR_STAT_SZ = 2
32*11d0c81dSLingrui98  def TAR_FIT = 0.U(TAR_STAT_SZ.W)
33*11d0c81dSLingrui98  def TAR_OVF = 1.U(TAR_STAT_SZ.W)
34*11d0c81dSLingrui98  def TAR_UDF = 2.U(TAR_STAT_SZ.W)
35*11d0c81dSLingrui98
36*11d0c81dSLingrui98  def BR_OFFSET_LEN = 12
37*11d0c81dSLingrui98  def JMP_OFFSET_LEN = 20
38*11d0c81dSLingrui98
39*11d0c81dSLingrui98  def getTag(pc: UInt) = pc(tagSize+instOffsetBits-1, instOffsetBits)
40*11d0c81dSLingrui98}
41*11d0c81dSLingrui98
42*11d0c81dSLingrui98class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {}
43*11d0c81dSLingrui98
44*11d0c81dSLingrui98class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams {
45*11d0c81dSLingrui98  val io = IO(new Bundle{
46*11d0c81dSLingrui98    val req_tag = Input(UInt(tagSize.W))
47*11d0c81dSLingrui98    val resp = Output(new FauFTBEntry)
48*11d0c81dSLingrui98    val resp_hit = Output(Bool())
49*11d0c81dSLingrui98    val update_req_tag = Input(UInt(tagSize.W))
50*11d0c81dSLingrui98    val update_hit = Output(Bool())
51*11d0c81dSLingrui98    val write_valid = Input(Bool())
52*11d0c81dSLingrui98    val write_entry = Input(new FauFTBEntry)
53*11d0c81dSLingrui98    val write_tag = Input(UInt(tagSize.W))
54*11d0c81dSLingrui98    val tag_read = Output(UInt(tagSize.W))
55*11d0c81dSLingrui98  })
56*11d0c81dSLingrui98
57*11d0c81dSLingrui98  val data = Reg(new FauFTBEntry)
58*11d0c81dSLingrui98  val tag = Reg(UInt(tagSize.W))
59*11d0c81dSLingrui98  val valid = RegInit(false.B)
60*11d0c81dSLingrui98
61*11d0c81dSLingrui98  io.resp := data
62*11d0c81dSLingrui98  io.resp_hit := tag === io.req_tag && valid
63*11d0c81dSLingrui98  // write bypass to avoid multiple hit
64*11d0c81dSLingrui98  io.update_hit := ((tag === io.update_req_tag) && valid) ||
65*11d0c81dSLingrui98                   ((io.write_tag === io.update_req_tag) && io.write_valid)
66*11d0c81dSLingrui98  io.tag_read := tag
67*11d0c81dSLingrui98
68*11d0c81dSLingrui98  when (io.write_valid) {
69*11d0c81dSLingrui98    when (!valid) {
70*11d0c81dSLingrui98      valid := true.B
71*11d0c81dSLingrui98    }
72*11d0c81dSLingrui98    tag   := io.write_tag
73*11d0c81dSLingrui98    data  := io.write_entry
74*11d0c81dSLingrui98  }
75*11d0c81dSLingrui98}
76*11d0c81dSLingrui98
77*11d0c81dSLingrui98
78*11d0c81dSLingrui98class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
79*11d0c81dSLingrui98
80*11d0c81dSLingrui98  class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams {
81*11d0c81dSLingrui98    val pred_way = UInt(log2Ceil(numWays).W)
82*11d0c81dSLingrui98    val hit = Bool()
83*11d0c81dSLingrui98  }
84*11d0c81dSLingrui98  val resp_meta = Wire(new FauFTBMeta)
85*11d0c81dSLingrui98  override val meta_size = resp_meta.getWidth
86*11d0c81dSLingrui98
87*11d0c81dSLingrui98
88*11d0c81dSLingrui98
89*11d0c81dSLingrui98  val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay))
90*11d0c81dSLingrui98  // numWays * numBr
91*11d0c81dSLingrui98  val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
92*11d0c81dSLingrui98  val replacer = ReplacementPolicy.fromString("plru", numWays)
93*11d0c81dSLingrui98  val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W))))
94*11d0c81dSLingrui98
95*11d0c81dSLingrui98
96*11d0c81dSLingrui98  // pred req
97*11d0c81dSLingrui98  ways.foreach(_.io.req_tag := getTag(s1_pc))
98*11d0c81dSLingrui98
99*11d0c81dSLingrui98  // pred resp
100*11d0c81dSLingrui98  val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
101*11d0c81dSLingrui98  val s1_hit = s1_hit_oh.orR
102*11d0c81dSLingrui98  val s1_hit_way = OHToUInt(s1_hit_oh)
103*11d0c81dSLingrui98  val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction))
104*11d0c81dSLingrui98
105*11d0c81dSLingrui98  val s1_all_entries = VecInit(ways.map(_.io.resp))
106*11d0c81dSLingrui98  for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) {
107*11d0c81dSLingrui98    fp.hit := DontCare
108*11d0c81dSLingrui98    fp.fromFtbEntry(e, s1_pc)
109*11d0c81dSLingrui98    for (i <- 0 until numBr) {
110*11d0c81dSLingrui98      fp.br_taken_mask(i) := c(i)(1) || e.always_taken(i)
111*11d0c81dSLingrui98    }
112*11d0c81dSLingrui98  }
113*11d0c81dSLingrui98  val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
114*11d0c81dSLingrui98  XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n")
115*11d0c81dSLingrui98  val fauftb_enable = RegNext(io.ctrl.ubtb_enable)
116*11d0c81dSLingrui98  io.out.s1.full_pred := s1_hit_full_pred
117*11d0c81dSLingrui98  io.out.s1.full_pred.hit := s1_hit && fauftb_enable
118*11d0c81dSLingrui98  io.out.s1.is_minimal := false.B
119*11d0c81dSLingrui98
120*11d0c81dSLingrui98  // assign metas
121*11d0c81dSLingrui98  io.out.last_stage_meta := resp_meta.asUInt
122*11d0c81dSLingrui98  resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire), io.s2_fire)
123*11d0c81dSLingrui98  resp_meta.pred_way := RegEnable(RegEnable(s1_hit_way, io.s1_fire), io.s2_fire)
124*11d0c81dSLingrui98
125*11d0c81dSLingrui98  // pred update replacer state
126*11d0c81dSLingrui98  val s1_fire = io.s1_fire
127*11d0c81dSLingrui98  replacer_touch_ways(0).valid := RegNext(s1_fire && s1_hit)
128*11d0c81dSLingrui98  replacer_touch_ways(0).bits  := RegEnable(s1_hit_way, s1_fire && s1_hit)
129*11d0c81dSLingrui98
130*11d0c81dSLingrui98  /********************** update ***********************/
131*11d0c81dSLingrui98  // s0: update_valid, read and tag comparison
132*11d0c81dSLingrui98  // s1: alloc_way and write
133*11d0c81dSLingrui98
134*11d0c81dSLingrui98  // s0
135*11d0c81dSLingrui98  val u = io.update
136*11d0c81dSLingrui98  val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
137*11d0c81dSLingrui98  val u_s0_tag = getTag(u.bits.pc)
138*11d0c81dSLingrui98  ways.foreach(_.io.update_req_tag := u_s0_tag)
139*11d0c81dSLingrui98  val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt
140*11d0c81dSLingrui98  val u_s0_hit = u_s0_hit_oh.orR
141*11d0c81dSLingrui98  val u_s0_br_update_valids =
142*11d0c81dSLingrui98    VecInit((0 until numBr).map(w =>
143*11d0c81dSLingrui98      u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) &&
144*11d0c81dSLingrui98      !(PriorityEncoder(u.bits.br_taken_mask) < w.U)))
145*11d0c81dSLingrui98
146*11d0c81dSLingrui98  // s1
147*11d0c81dSLingrui98  val u_s1_valid = RegNext(u.valid)
148*11d0c81dSLingrui98  val u_s1_tag       = RegEnable(u_s0_tag, u.valid)
149*11d0c81dSLingrui98  val u_s1_hit_oh    = RegEnable(u_s0_hit_oh, u.valid)
150*11d0c81dSLingrui98  val u_s1_hit       = RegEnable(u_s0_hit, u.valid)
151*11d0c81dSLingrui98  val u_s1_alloc_way = replacer.way
152*11d0c81dSLingrui98  val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
153*11d0c81dSLingrui98  val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
154*11d0c81dSLingrui98  val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid))
155*11d0c81dSLingrui98  for (w <- 0 until numWays) {
156*11d0c81dSLingrui98    ways(w).io.write_valid := u_s1_ways_write_valid(w)
157*11d0c81dSLingrui98    ways(w).io.write_tag   := u_s1_tag
158*11d0c81dSLingrui98    ways(w).io.write_entry := u_s1_ftb_entry
159*11d0c81dSLingrui98  }
160*11d0c81dSLingrui98
161*11d0c81dSLingrui98  // update saturating counters
162*11d0c81dSLingrui98  val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid)
163*11d0c81dSLingrui98  val u_s1_br_takens        = RegEnable(u.bits.br_taken_mask,  u.valid)
164*11d0c81dSLingrui98  for (w <- 0 until numWays) {
165*11d0c81dSLingrui98    when (u_s1_ways_write_valid(w)) {
166*11d0c81dSLingrui98      for (br <- 0 until numBr) {
167*11d0c81dSLingrui98        when (u_s1_br_update_valids(br)) {
168*11d0c81dSLingrui98          ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br))
169*11d0c81dSLingrui98        }
170*11d0c81dSLingrui98      }
171*11d0c81dSLingrui98    }
172*11d0c81dSLingrui98  }
173*11d0c81dSLingrui98
174*11d0c81dSLingrui98  // commit update replacer state
175*11d0c81dSLingrui98  replacer_touch_ways(1).valid := u_s1_valid
176*11d0c81dSLingrui98  replacer_touch_ways(1).bits  := OHToUInt(u_s1_write_way_oh)
177*11d0c81dSLingrui98
178*11d0c81dSLingrui98  /******** update replacer *********/
179*11d0c81dSLingrui98  replacer.access(replacer_touch_ways)
180*11d0c81dSLingrui98
181*11d0c81dSLingrui98
182*11d0c81dSLingrui98  /********************** perf counters **********************/
183*11d0c81dSLingrui98  val s0_fire_next_cycle = RegNext(io.s0_fire)
184*11d0c81dSLingrui98  val u_pred_hit_way_map   = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
185*11d0c81dSLingrui98  val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way === w.U)
186*11d0c81dSLingrui98  XSPerfAccumulate("uftb_read_hits",   s0_fire_next_cycle &&  s1_hit)
187*11d0c81dSLingrui98  XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit)
188*11d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_hits",   u.valid &&  u_meta.hit)
189*11d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit)
190*11d0c81dSLingrui98  XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR)
191*11d0c81dSLingrui98  for (w <- 0 until numWays) {
192*11d0c81dSLingrui98    XSPerfAccumulate(f"uftb_pred_hit_way_${w}",   u_pred_hit_way_map(w))
193*11d0c81dSLingrui98    XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w))
194*11d0c81dSLingrui98    XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U)
195*11d0c81dSLingrui98  }
196*11d0c81dSLingrui98
197*11d0c81dSLingrui98  override val perfEvents = Seq(
198*11d0c81dSLingrui98    ("fauftb_commit_hit       ", u.valid &&  u_meta.hit),
199*11d0c81dSLingrui98    ("fauftb_commit_miss      ", u.valid && !u_meta.hit),
200*11d0c81dSLingrui98  )
201*11d0c81dSLingrui98  generatePerfEvent()
202*11d0c81dSLingrui98
203*11d0c81dSLingrui98}