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