FauFTB.scala (cabb9f41435550594f71a9193e296f0aa870e057) FauFTB.scala (cf7d6b7a1a781c73aeb87de112de2e7fe5ea3b7c)
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
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 org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
19import chisel3._
20import chisel3.util._
22import utils._
21import org.chipsalliance.cde.config.Parameters
22import scala.{Tuple2 => &}
23import utility._
23import utility._
24import utils._
24import xiangshan._
25import xiangshan._
25import scala.{Tuple2 => &}
26
27trait FauFTBParams extends HasXSParameter with HasBPUConst {
28 val numWays = 32
29 val tagSize = 16
30
31 val TAR_STAT_SZ = 2
26
27trait FauFTBParams extends HasXSParameter with HasBPUConst {
28 val numWays = 32
29 val tagSize = 16
30
31 val TAR_STAT_SZ = 2
32 def TAR_FIT = 0.U(TAR_STAT_SZ.W)
33 def TAR_OVF = 1.U(TAR_STAT_SZ.W)
34 def TAR_UDF = 2.U(TAR_STAT_SZ.W)
32 def TAR_FIT = 0.U(TAR_STAT_SZ.W)
33 def TAR_OVF = 1.U(TAR_STAT_SZ.W)
34 def TAR_UDF = 2.U(TAR_STAT_SZ.W)
35
35
36 def BR_OFFSET_LEN = 12
36 def BR_OFFSET_LEN = 12
37 def JMP_OFFSET_LEN = 20
38
37 def JMP_OFFSET_LEN = 20
38
39 def getTag(pc: UInt) = pc(tagSize+instOffsetBits-1, instOffsetBits)
39 def getTag(pc: UInt) = pc(tagSize + instOffsetBits - 1, instOffsetBits)
40}
41
42class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {}
43
44class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams {
40}
41
42class FauFTBEntry(implicit p: Parameters) extends FTBEntry()(p) {}
43
44class FauFTBWay(implicit p: Parameters) extends XSModule with FauFTBParams {
45 val io = IO(new Bundle{
46 val req_tag = Input(UInt(tagSize.W))
47 val resp = Output(new FauFTBEntry)
48 val resp_hit = Output(Bool())
45 val io = IO(new Bundle {
46 val req_tag = Input(UInt(tagSize.W))
47 val resp = Output(new FauFTBEntry)
48 val resp_hit = Output(Bool())
49 val update_req_tag = Input(UInt(tagSize.W))
49 val update_req_tag = Input(UInt(tagSize.W))
50 val update_hit = Output(Bool())
51 val write_valid = Input(Bool())
52 val write_entry = Input(new FauFTBEntry)
53 val write_tag = Input(UInt(tagSize.W))
54 val tag_read = Output(UInt(tagSize.W))
50 val update_hit = Output(Bool())
51 val write_valid = Input(Bool())
52 val write_entry = Input(new FauFTBEntry)
53 val write_tag = Input(UInt(tagSize.W))
54 val tag_read = Output(UInt(tagSize.W))
55 })
56
55 })
56
57 val data = Reg(new FauFTBEntry)
58 val tag = Reg(UInt(tagSize.W))
57 val data = Reg(new FauFTBEntry)
58 val tag = Reg(UInt(tagSize.W))
59 val valid = RegInit(false.B)
60
59 val valid = RegInit(false.B)
60
61 io.resp := data
61 io.resp := data
62 io.resp_hit := tag === io.req_tag && valid
63 // write bypass to avoid multiple hit
64 io.update_hit := ((tag === io.update_req_tag) && valid) ||
62 io.resp_hit := tag === io.req_tag && valid
63 // write bypass to avoid multiple hit
64 io.update_hit := ((tag === io.update_req_tag) && valid) ||
65 ((io.write_tag === io.update_req_tag) && io.write_valid)
65 ((io.write_tag === io.update_req_tag) && io.write_valid)
66 io.tag_read := tag
67
66 io.tag_read := tag
67
68 when (io.write_valid) {
69 when (!valid) {
68 when(io.write_valid) {
69 when(!valid) {
70 valid := true.B
71 }
70 valid := true.B
71 }
72 tag := io.write_tag
73 data := io.write_entry
72 tag := io.write_tag
73 data := io.write_entry
74 }
75}
76
74 }
75}
76
77
78class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
79
80 class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams {
81 val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None
77class FauFTB(implicit p: Parameters) extends BasePredictor with FauFTBParams {
78
79 class FauFTBMeta(implicit p: Parameters) extends XSBundle with FauFTBParams {
80 val pred_way = if (!env.FPGAPlatform) Some(UInt(log2Ceil(numWays).W)) else None
82 val hit = Bool()
81 val hit = Bool()
83 }
82 }
84 val resp_meta = Wire(new FauFTBMeta)
85 override val meta_size = resp_meta.getWidth
83 val resp_meta = Wire(new FauFTBMeta)
84 override val meta_size = resp_meta.getWidth
86 override val is_fast_pred = true
87
85 override val is_fast_pred = true
86
88
89
90 val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay))
91 // numWays * numBr
87 val ways = Seq.tabulate(numWays)(w => Module(new FauFTBWay))
88 // numWays * numBr
92 val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
93 val replacer = ReplacementPolicy.fromString("plru", numWays)
89 val ctrs = Seq.tabulate(numWays)(w => Seq.tabulate(numBr)(b => RegInit(2.U(2.W))))
90 val replacer = ReplacementPolicy.fromString("plru", numWays)
94 val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W))))
95
91 val replacer_touch_ways = Wire(Vec(2, Valid(UInt(log2Ceil(numWays).W))))
92
96
97 // pred req
98 ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0)))
99
100 // pred resp
93 // pred req
94 ways.foreach(_.io.req_tag := getTag(s1_pc_dup(0)))
95
96 // pred resp
101 val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
102 val s1_hit = s1_hit_oh.orR
103 val s1_hit_way = OHToUInt(s1_hit_oh)
97 val s1_hit_oh = VecInit(ways.map(_.io.resp_hit)).asUInt
98 val s1_hit = s1_hit_oh.orR
99 val s1_hit_way = OHToUInt(s1_hit_oh)
104 val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction(isNotS3 = true)))
105
106 val s1_all_entries = VecInit(ways.map(_.io.resp))
107 for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) {
100 val s1_possible_full_preds = Wire(Vec(numWays, new FullBranchPrediction(isNotS3 = true)))
101
102 val s1_all_entries = VecInit(ways.map(_.io.resp))
103 for (c & fp & e <- ctrs zip s1_possible_full_preds zip s1_all_entries) {
108 fp.hit := DontCare
104 fp.hit := DontCare
109 fp.multiHit := false.B
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 }
105 fp.multiHit := false.B
106 fp.fromFtbEntry(e, s1_pc_dup(0))
107 for (i <- 0 until numBr) {
108 fp.br_taken_mask(i) := c(i)(1) || e.always_taken(i)
109 }
110 }
115 val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
116 val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries)
111 val s1_hit_full_pred = Mux1H(s1_hit_oh, s1_possible_full_preds)
112 val s1_hit_fauftbentry = Mux1H(s1_hit_oh, s1_all_entries)
117 XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n")
118 val fauftb_enable = RegNext(io.ctrl.ubtb_enable)
119 io.out.s1.full_pred.map(_ := s1_hit_full_pred)
113 XSError(PopCount(s1_hit_oh) > 1.U, "fauftb has multiple hits!\n")
114 val fauftb_enable = RegNext(io.ctrl.ubtb_enable)
115 io.out.s1.full_pred.map(_ := s1_hit_full_pred)
120 io.out.s1.full_pred.map(_ .hit := s1_hit && fauftb_enable)
121 io.fauftb_entry_out := s1_hit_fauftbentry
116 io.out.s1.full_pred.map(_.hit := s1_hit && fauftb_enable)
117 io.fauftb_entry_out := s1_hit_fauftbentry
122 io.fauftb_entry_hit_out := s1_hit && fauftb_enable
123
124 // Illegal check for FTB entry reading
118 io.fauftb_entry_hit_out := s1_hit && fauftb_enable
119
120 // Illegal check for FTB entry reading
125 val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits))
121 val s1_pc_startLower = Cat(0.U(1.W), s1_pc_dup(0)(instOffsetBits + log2Ceil(PredictWidth) - 1, instOffsetBits))
126 val uftb_entry_endLowerwithCarry = Cat(s1_hit_fauftbentry.carry, s1_hit_fauftbentry.pftAddr)
122 val uftb_entry_endLowerwithCarry = Cat(s1_hit_fauftbentry.carry, s1_hit_fauftbentry.pftAddr)
127 val fallThroughErr = s1_pc_startLower + (PredictWidth).U >= uftb_entry_endLowerwithCarry
128 when(io.s1_fire(0) && s1_hit){
123 val fallThroughErr = s1_pc_startLower + PredictWidth.U >= uftb_entry_endLowerwithCarry
124 when(io.s1_fire(0) && s1_hit) {
129 assert(fallThroughErr, s"FauFTB read entry fallThrough address error!")
130 }
131
132 // assign metas
133 io.out.last_stage_meta := resp_meta.asUInt
125 assert(fallThroughErr, s"FauFTB read entry fallThrough address error!")
126 }
127
128 // assign metas
129 io.out.last_stage_meta := resp_meta.asUInt
134 resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0))
135 if(resp_meta.pred_way.isDefined) {resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0))}
130 resp_meta.hit := RegEnable(RegEnable(s1_hit, io.s1_fire(0)), io.s2_fire(0))
131 if (resp_meta.pred_way.isDefined) {
132 resp_meta.pred_way.get := RegEnable(RegEnable(s1_hit_way, io.s1_fire(0)), io.s2_fire(0))
133 }
136
137 // pred update replacer state
138 val s1_fire = io.s1_fire(0)
139 replacer_touch_ways(0).valid := RegNext(s1_fire(0) && s1_hit)
140 replacer_touch_ways(0).bits := RegEnable(s1_hit_way, s1_fire(0) && s1_hit)
141
142 /********************** update ***********************/
143 // s0: update_valid, read and tag comparison
144 // s1: alloc_way and write
145
146 // s0
134
135 // pred update replacer state
136 val s1_fire = io.s1_fire(0)
137 replacer_touch_ways(0).valid := RegNext(s1_fire(0) && s1_hit)
138 replacer_touch_ways(0).bits := RegEnable(s1_hit_way, s1_fire(0) && s1_hit)
139
140 /********************** update ***********************/
141 // s0: update_valid, read and tag comparison
142 // s1: alloc_way and write
143
144 // s0
147 val u = io.update
148 val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
145 val u = io.update
146 val u_meta = u.bits.meta.asTypeOf(new FauFTBMeta)
149 val u_s0_tag = getTag(u.bits.pc)
150 ways.foreach(_.io.update_req_tag := u_s0_tag)
151 val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt
147 val u_s0_tag = getTag(u.bits.pc)
148 ways.foreach(_.io.update_req_tag := u_s0_tag)
149 val u_s0_hit_oh = VecInit(ways.map(_.io.update_hit)).asUInt
152 val u_s0_hit = u_s0_hit_oh.orR
150 val u_s0_hit = u_s0_hit_oh.orR
153 val u_s0_br_update_valids =
154 VecInit((0 until numBr).map(w =>
155 u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) &&
151 val u_s0_br_update_valids =
152 VecInit((0 until numBr).map(w =>
153 u.bits.ftb_entry.brValids(w) && u.valid && !u.bits.ftb_entry.always_taken(w) &&
156 !(PriorityEncoder(u.bits.br_taken_mask) < w.U)))
154 !(PriorityEncoder(u.bits.br_taken_mask) < w.U)
155 ))
157
158 // s1
156
157 // s1
159 val u_s1_valid = RegNext(u.valid)
160 val u_s1_tag = RegEnable(u_s0_tag, u.valid)
161 val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u.valid)
162 val u_s1_hit = RegEnable(u_s0_hit, u.valid)
163 val u_s1_alloc_way = replacer.way
164 val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
165 val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
158 val u_s1_valid = RegNext(u.valid)
159 val u_s1_tag = RegEnable(u_s0_tag, u.valid)
160 val u_s1_hit_oh = RegEnable(u_s0_hit_oh, u.valid)
161 val u_s1_hit = RegEnable(u_s0_hit, u.valid)
162 val u_s1_alloc_way = replacer.way
163 val u_s1_write_way_oh = Mux(u_s1_hit, u_s1_hit_oh, UIntToOH(u_s1_alloc_way))
164 val u_s1_ftb_entry = RegEnable(u.bits.ftb_entry, u.valid)
166 val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid))
167 for (w <- 0 until numWays) {
168 ways(w).io.write_valid := u_s1_ways_write_valid(w)
169 ways(w).io.write_tag := u_s1_tag
170 ways(w).io.write_entry := u_s1_ftb_entry
171 }
172
173 // Illegal check for FTB entry writing
165 val u_s1_ways_write_valid = VecInit((0 until numWays).map(w => u_s1_write_way_oh(w).asBool && u_s1_valid))
166 for (w <- 0 until numWays) {
167 ways(w).io.write_valid := u_s1_ways_write_valid(w)
168 ways(w).io.write_tag := u_s1_tag
169 ways(w).io.write_entry := u_s1_ftb_entry
170 }
171
172 // Illegal check for FTB entry writing
174 val uftb_write_pc = RegEnable(u.bits.pc, u.valid)
173 val uftb_write_pc = RegEnable(u.bits.pc, u.valid)
175 val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc)
174 val uftb_write_fallThrough = u_s1_ftb_entry.getFallThrough(uftb_write_pc)
176 when(u_s1_valid && u_s1_hit){
177 assert(uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough, s"FauFTB write entry fallThrough address error!")
175 when(u_s1_valid && u_s1_hit) {
176 assert(
177 uftb_write_pc + (FetchWidth * 4).U >= uftb_write_fallThrough,
178 s"FauFTB write entry fallThrough address error!"
179 )
178 }
179
180 // update saturating counters
181 val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid)
180 }
181
182 // update saturating counters
183 val u_s1_br_update_valids = RegEnable(u_s0_br_update_valids, u.valid)
182 val u_s1_br_takens = RegEnable(u.bits.br_taken_mask, u.valid)
184 val u_s1_br_takens = RegEnable(u.bits.br_taken_mask, u.valid)
183 for (w <- 0 until numWays) {
185 for (w <- 0 until numWays) {
184 when (u_s1_ways_write_valid(w)) {
186 when(u_s1_ways_write_valid(w)) {
185 for (br <- 0 until numBr) {
187 for (br <- 0 until numBr) {
186 when (u_s1_br_update_valids(br)) {
188 when(u_s1_br_update_valids(br)) {
187 ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br))
188 }
189 }
190 }
191 }
192
193 // commit update replacer state
194 replacer_touch_ways(1).valid := u_s1_valid
195 replacer_touch_ways(1).bits := OHToUInt(u_s1_write_way_oh)
196
197 /******** update replacer *********/
198 replacer.access(replacer_touch_ways)
199
189 ctrs(w)(br) := satUpdate(ctrs(w)(br), 2, u_s1_br_takens(br))
190 }
191 }
192 }
193 }
194
195 // commit update replacer state
196 replacer_touch_ways(1).valid := u_s1_valid
197 replacer_touch_ways(1).bits := OHToUInt(u_s1_write_way_oh)
198
199 /******** update replacer *********/
200 replacer.access(replacer_touch_ways)
201
200
201 /********************** perf counters **********************/
202 val s0_fire_next_cycle = RegNext(io.s0_fire(0))
202 /********************** perf counters **********************/
203 val s0_fire_next_cycle = RegNext(io.s0_fire(0))
203 val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
204 XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit)
204 val u_pred_hit_way_map = (0 until numWays).map(w => s0_fire_next_cycle && s1_hit && s1_hit_way === w.U)
205 XSPerfAccumulate("uftb_read_hits", s0_fire_next_cycle && s1_hit)
205 XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit)
206 XSPerfAccumulate("uftb_read_misses", s0_fire_next_cycle && !s1_hit)
206 XSPerfAccumulate("uftb_commit_hits", u.valid && u_meta.hit)
207 XSPerfAccumulate("uftb_commit_hits", u.valid && u_meta.hit)
207 XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit)
208 XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR)
209 for (w <- 0 until numWays) {
208 XSPerfAccumulate("uftb_commit_misses", u.valid && !u_meta.hit)
209 XSPerfAccumulate("uftb_commit_read_hit_pred_miss", u.valid && !u_meta.hit && u_s0_hit_oh.orR)
210 for (w <- 0 until numWays) {
210 XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w))
211 XSPerfAccumulate(f"uftb_pred_hit_way_${w}", u_pred_hit_way_map(w))
211 XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U)
212 }
213
212 XSPerfAccumulate(f"uftb_replace_way_${w}", !u_s1_hit && u_s1_alloc_way === w.U)
213 }
214
214 if(u_meta.pred_way.isDefined) {
215 if (u_meta.pred_way.isDefined) {
215 val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way.get === w.U)
216 for (w <- 0 until numWays) {
217 XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w))
218 }
219 }
220
221 override val perfEvents = Seq(
216 val u_commit_hit_way_map = (0 until numWays).map(w => u.valid && u_meta.hit && u_meta.pred_way.get === w.U)
217 for (w <- 0 until numWays) {
218 XSPerfAccumulate(f"uftb_commit_hit_way_${w}", u_commit_hit_way_map(w))
219 }
220 }
221
222 override val perfEvents = Seq(
222 ("fauftb_commit_hit ", u.valid && u_meta.hit),
223 ("fauftb_commit_miss ", u.valid && !u_meta.hit),
223 ("fauftb_commit_hit ", u.valid && u_meta.hit),
224 ("fauftb_commit_miss ", u.valid && !u_meta.hit)
224 )
225 generatePerfEvent()
226
227}
225 )
226 generatePerfEvent()
227
228}