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***************************************************************************************/ 16package xiangshan.frontend 17 18import chipsalliance.rocketchip.config.Parameters 19import chisel3._ 20import chisel3.util._ 21import chisel3.experimental.chiselName 22import xiangshan._ 23import utils._ 24 25@chiselName 26class FetchRequestBundle(implicit p: Parameters) extends XSBundle { 27 val startAddr = UInt(VAddrBits.W) 28 val fallThruAddr = UInt(VAddrBits.W) 29 val fallThruError = Bool() 30 val ftqIdx = new FtqPtr 31 val ftqOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 32 val target = UInt(VAddrBits.W) 33 val oversize = Bool() 34 35 def fallThroughError() = { 36 def carryPos = instOffsetBits+log2Ceil(PredictWidth)+1 37 def getLower(pc: UInt) = pc(instOffsetBits+log2Ceil(PredictWidth), instOffsetBits) 38 val carry = (startAddr(carryPos) =/= fallThruAddr(carryPos)).asUInt 39 val startLower = Cat(0.U(1.W), getLower(startAddr)) 40 val endLowerwithCarry = Cat(carry, getLower(fallThruAddr)) 41 require(startLower.getWidth == log2Ceil(PredictWidth)+2) 42 require(endLowerwithCarry.getWidth == log2Ceil(PredictWidth)+2) 43 startLower >= endLowerwithCarry || (endLowerwithCarry - startLower) > (PredictWidth+1).U 44 } 45 def fromFtqPcBundle(b: Ftq_RF_Components) = { 46 this.startAddr := b.startAddr 47 this.fallThruAddr := b.getFallThrough() 48 this.oversize := b.oversize 49 this 50 } 51 def fromBpuResp(resp: BranchPredictionBundle) = { 52 // only used to bypass, so some fields remains unchanged 53 this.startAddr := resp.pc 54 this.target := resp.target 55 this.ftqOffset := resp.genCfiIndex 56 this.fallThruAddr := resp.fallThroughAddr 57 this.oversize := resp.ftb_entry.oversize 58 this 59 } 60 override def toPrintable: Printable = { 61 p"[start] ${Hexadecimal(startAddr)} [pft] ${Hexadecimal(fallThruAddr)}" + 62 p"[tgt] ${Hexadecimal(target)} [ftqIdx] $ftqIdx [jmp] v:${ftqOffset.valid}" + 63 p" offset: ${ftqOffset.bits}\n" 64 } 65} 66 67class PredecodeWritebackBundle(implicit p:Parameters) extends XSBundle { 68 val pc = Vec(PredictWidth, UInt(VAddrBits.W)) 69 val pd = Vec(PredictWidth, new PreDecodeInfo) // TODO: redefine Predecode 70 val ftqIdx = new FtqPtr 71 val ftqOffset = UInt(log2Ceil(PredictWidth).W) 72 val misOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 73 val cfiOffset = ValidUndirectioned(UInt(log2Ceil(PredictWidth).W)) 74 val target = UInt(VAddrBits.W) 75 val jalTarget = UInt(VAddrBits.W) 76 val instrRange = Vec(PredictWidth, Bool()) 77} 78 79class Exception(implicit p: Parameters) extends XSBundle { 80 81} 82 83class FetchToIBuffer(implicit p: Parameters) extends XSBundle { 84 val instrs = Vec(PredictWidth, UInt(32.W)) 85 val valid = UInt(PredictWidth.W) 86 val pd = Vec(PredictWidth, new PreDecodeInfo) 87 val pc = Vec(PredictWidth, UInt(VAddrBits.W)) 88 val foldpc = Vec(PredictWidth, UInt(MemPredPCWidth.W)) 89 //val exception = new Exception 90 val ftqPtr = new FtqPtr 91 val ftqOffset = Vec(PredictWidth, ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) 92 val ipf = Vec(PredictWidth, Bool()) 93 val acf = Vec(PredictWidth, Bool()) 94 val crossPageIPFFix = Vec(PredictWidth, Bool()) 95} 96 97// Move from BPU 98class GlobalHistory(implicit p: Parameters) extends XSBundle with HasBPUConst { 99 val predHist = UInt(HistoryLength.W) 100 // def update(sawNTBr: Bool, takenOnBr: Bool, hist: UInt = predHist): GlobalHistory = { 101 // val g = Wire(new GlobalHistory) 102 // val shifted = takenOnBr || sawNTBr 103 // g.predHist := Mux(shifted, (hist << 1) | takenOnBr.asUInt, hist) 104 // g 105 // } 106 107 // def update(brValids: UInt, taken_mask: UInt, hist: UInt = predHist): GlobalHistory = { 108 // val shift = PopCount(brValids & Mux(taken_mask =/= 0.U, LowerMask(taken_mask), ((1.U<<numBr) - 1.U))) 109 // val g = Wire(new GlobalHistory) 110 // g.predHist := (hist << shift) | (taken_mask =/= 0.U) 111 // g 112 // } 113 114 def update(shift: UInt, taken: Bool, hist: UInt = this.predHist): GlobalHistory = { 115 val g = Wire(new GlobalHistory) 116 g.predHist := (hist << shift) | taken 117 g 118 } 119 120 def update(br_valids: Vec[Bool], real_taken_mask: Vec[Bool]): GlobalHistory = { 121 require(br_valids.length == numBr) 122 require(real_taken_mask.length == numBr) 123 val last_valid_idx = PriorityMux( 124 br_valids.reverse :+ true.B, 125 (numBr to 0 by -1).map(_.U(log2Ceil(numBr+1).W)) 126 ) 127 val first_taken_idx = PriorityEncoder(false.B +: real_taken_mask) 128 val smaller = Mux(last_valid_idx < first_taken_idx, 129 last_valid_idx, 130 first_taken_idx 131 ) 132 val shift = smaller 133 val taken = real_taken_mask.reduce(_||_) 134 update(shift, taken, this.predHist) 135 } 136 137 final def === (that: GlobalHistory): Bool = { 138 predHist === that.predHist 139 } 140 141 final def =/= (that: GlobalHistory): Bool = !(this === that) 142 143 implicit val name = "IFU" 144 def debug(where: String) = XSDebug(p"[${where}_GlobalHistory] hist=${Binary(predHist)}\n") 145 // override def toString(): String = "histPtr=%d, sawNTBr=%d, takenOnBr=%d, saveHalfRVI=%d".format(histPtr, sawNTBr, takenOnBr, saveHalfRVI) 146} 147 148class TableAddr(val idxBits: Int, val banks: Int)(implicit p: Parameters) extends XSBundle{ 149 def tagBits = VAddrBits - idxBits - instOffsetBits 150 151 val tag = UInt(tagBits.W) 152 val idx = UInt(idxBits.W) 153 val offset = UInt(instOffsetBits.W) 154 155 def fromUInt(x: UInt) = x.asTypeOf(UInt(VAddrBits.W)).asTypeOf(this) 156 def getTag(x: UInt) = fromUInt(x).tag 157 def getIdx(x: UInt) = fromUInt(x).idx 158 def getBank(x: UInt) = if (banks > 1) getIdx(x)(log2Up(banks) - 1, 0) else 0.U 159 def getBankIdx(x: UInt) = if (banks > 1) getIdx(x)(idxBits - 1, log2Up(banks)) else getIdx(x) 160} 161 162@chiselName 163class BranchPrediction(implicit p: Parameters) extends XSBundle with HasBPUConst { 164 val br_taken_mask = Vec(numBr, Bool()) 165 166 val slot_valids = Vec(totalSlot, Bool()) 167 168 val targets = Vec(totalSlot, UInt(VAddrBits.W)) 169 170 val is_jal = Bool() 171 val is_jalr = Bool() 172 val is_call = Bool() 173 val is_ret = Bool() 174 val is_br_sharing = Bool() 175 176 // val call_is_rvc = Bool() 177 val hit = Bool() 178 179 def br_slot_valids = slot_valids.init 180 def tail_slot_valid = slot_valids.last 181 182 def br_valids = { 183 VecInit( 184 if (shareTailSlot) 185 br_slot_valids :+ (tail_slot_valid && is_br_sharing) 186 else 187 br_slot_valids 188 ) 189 } 190 191 def taken_mask_on_slot = { 192 VecInit( 193 if (shareTailSlot) 194 (br_slot_valids zip br_taken_mask.init).map{ case (t, v) => t && v } :+ ( 195 (br_taken_mask.last && tail_slot_valid && is_br_sharing) || 196 tail_slot_valid && !is_br_sharing 197 ) 198 else 199 (br_slot_valids zip br_taken_mask).map{ case (v, t) => v && t } :+ 200 tail_slot_valid 201 ) 202 } 203 204 def taken = br_taken_mask.reduce(_||_) || slot_valids.last // || (is_jal || is_jalr) 205 206 def fromFtbEntry(entry: FTBEntry, pc: UInt) = { 207 slot_valids := entry.brSlots.map(_.valid) :+ entry.tailSlot.valid 208 targets := entry.getTargetVec(pc) 209 is_jal := entry.tailSlot.valid && entry.isJal 210 is_jalr := entry.tailSlot.valid && entry.isJalr 211 is_call := entry.tailSlot.valid && entry.isCall 212 is_ret := entry.tailSlot.valid && entry.isRet 213 is_br_sharing := entry.tailSlot.valid && entry.tailSlot.sharing 214 } 215 // override def toPrintable: Printable = { 216 // p"-----------BranchPrediction----------- " + 217 // p"[taken_mask] ${Binary(taken_mask.asUInt)} " + 218 // p"[is_br] ${Binary(is_br.asUInt)}, [is_jal] ${Binary(is_jal.asUInt)} " + 219 // p"[is_jalr] ${Binary(is_jalr.asUInt)}, [is_call] ${Binary(is_call.asUInt)}, [is_ret] ${Binary(is_ret.asUInt)} " + 220 // p"[target] ${Hexadecimal(target)}}, [hit] $hit " 221 // } 222 223 def display(cond: Bool): Unit = { 224 XSDebug(cond, p"[taken_mask] ${Binary(br_taken_mask.asUInt)} [hit] $hit\n") 225 } 226} 227 228@chiselName 229class BranchPredictionBundle(implicit p: Parameters) extends XSBundle with HasBPUConst with BPUUtils{ 230 val pc = UInt(VAddrBits.W) 231 232 val valid = Bool() 233 234 val hasRedirect = Bool() 235 val ftq_idx = new FtqPtr 236 // val hit = Bool() 237 val preds = new BranchPrediction 238 239 val ghist = new GlobalHistory() 240 val phist = UInt(PathHistoryLength.W) 241 val rasSp = UInt(log2Ceil(RasSize).W) 242 val rasTop = new RASEntry 243 val specCnt = Vec(numBr, UInt(10.W)) 244 // val meta = UInt(MaxMetaLength.W) 245 246 val ftb_entry = new FTBEntry() // TODO: Send this entry to ftq 247 248 def real_slot_taken_mask(): Vec[Bool] = { 249 VecInit(preds.taken_mask_on_slot.map(_ && preds.hit)) 250 } 251 252 // len numBr 253 def real_br_taken_mask(): Vec[Bool] = { 254 if (shareTailSlot) 255 VecInit( 256 preds.taken_mask_on_slot.map(_ && preds.hit).init :+ 257 (preds.br_taken_mask.last && preds.tail_slot_valid && preds.is_br_sharing && preds.hit) 258 ) 259 else 260 VecInit(real_slot_taken_mask().init) 261 } 262 263 def hit_taken_on_jmp = 264 !real_slot_taken_mask().init.reduce(_||_) && 265 real_slot_taken_mask().last && !preds.is_br_sharing 266 def hit_taken_on_call = hit_taken_on_jmp && preds.is_call 267 def hit_taken_on_ret = hit_taken_on_jmp && preds.is_ret 268 def hit_taken_on_jalr = hit_taken_on_jmp && preds.is_jalr 269 270 def fallThroughAddr = getFallThroughAddr(pc, ftb_entry.carry, ftb_entry.pftAddr) 271 272 def target(): UInt = { 273 val targetVec = preds.targets :+ fallThroughAddr :+ (pc + (FetchWidth*4).U) 274 val selVec = real_slot_taken_mask() :+ (preds.hit && !real_slot_taken_mask().asUInt.orR) :+ true.B 275 PriorityMux(selVec zip targetVec) 276 } 277 def genCfiIndex = { 278 val cfiIndex = Wire(ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) 279 cfiIndex.valid := real_slot_taken_mask().asUInt.orR 280 // when no takens, set cfiIndex to PredictWidth-1 281 cfiIndex.bits := 282 ParallelPriorityMux(real_slot_taken_mask(), ftb_entry.getOffsetVec) | 283 Fill(log2Ceil(PredictWidth), (!real_slot_taken_mask().asUInt.orR).asUInt) 284 cfiIndex 285 } 286 287 288 // override def toPrintable: Printable = { 289 // p"-----------BranchPredictionBundle----------- " + 290 // p"[pc] ${Hexadecimal(pc)} " + 291 // p"[ghist] ${Binary(ghist.predHist)} " + 292 // preds.toPrintable + 293 // ftb_entry.toPrintable 294 // } 295 296 def display(cond: Bool): Unit = { 297 XSDebug(cond, p"[pc] ${Hexadecimal(pc)}\n") 298 XSDebug(cond, p"[ghist] ${Binary(ghist.predHist)}\n") 299 preds.display(cond) 300 ftb_entry.display(cond) 301 } 302} 303 304@chiselName 305class BranchPredictionResp(implicit p: Parameters) extends XSBundle with HasBPUConst { 306 // val valids = Vec(3, Bool()) 307 val s1 = new BranchPredictionBundle() 308 val s2 = new BranchPredictionBundle() 309 val s3 = new BranchPredictionBundle() 310 311 def selectedResp = 312 PriorityMux(Seq( 313 ((s3.valid && s3.hasRedirect) -> s3), 314 ((s2.valid && s2.hasRedirect) -> s2), 315 (s1.valid -> s1) 316 )) 317 def selectedRespIdx = 318 PriorityMux(Seq( 319 ((s3.valid && s3.hasRedirect) -> BP_S3), 320 ((s2.valid && s2.hasRedirect) -> BP_S2), 321 (s1.valid -> BP_S1) 322 )) 323 def lastStage = s3 324} 325 326class BpuToFtqBundle(implicit p: Parameters) extends BranchPredictionResp with HasBPUConst { 327 val meta = UInt(MaxMetaLength.W) 328} 329 330object BpuToFtqBundle { 331 def apply(resp: BranchPredictionResp)(implicit p: Parameters): BpuToFtqBundle = { 332 val e = Wire(new BpuToFtqBundle()) 333 e.s1 := resp.s1 334 e.s2 := resp.s2 335 e.s3 := resp.s3 336 337 e.meta := DontCare 338 e 339 } 340} 341 342class BranchPredictionUpdate(implicit p: Parameters) extends BranchPredictionBundle with HasBPUConst { 343 val mispred_mask = Vec(numBr+1, Bool()) 344 val false_hit = Bool() 345 val new_br_insert_pos = Vec(numBr, Bool()) 346 val old_entry = Bool() 347 val meta = UInt(MaxMetaLength.W) 348 val full_target = UInt(VAddrBits.W) 349 // val ghist = new GlobalHistory() This in spec_meta 350 351 def fromFtqRedirectSram(entry: Ftq_Redirect_SRAMEntry) = { 352 ghist := entry.ghist 353 phist := entry.phist 354 rasSp := entry.rasSp 355 rasTop := entry.rasEntry 356 specCnt := entry.specCnt 357 this 358 } 359 // override def toPrintable: Printable = { 360 // p"-----------BranchPredictionUpdate----------- " + 361 // p"[mispred_mask] ${Binary(mispred_mask.asUInt)} [false_hit] ${Binary(false_hit)} " + 362 // p"[new_br_insert_pos] ${Binary(new_br_insert_pos.asUInt)} " + 363 // super.toPrintable + 364 // p"\n" 365 // } 366 367 override def display(cond: Bool) { 368 XSDebug(cond, p"-----------BranchPredictionUpdate-----------\n") 369 XSDebug(cond, p"[mispred_mask] ${Binary(mispred_mask.asUInt)} [false_hit] $false_hit\n") 370 XSDebug(cond, p"[new_br_insert_pos] ${Binary(new_br_insert_pos.asUInt)}\n") 371 super.display(cond) 372 XSDebug(cond, p"--------------------------------------------\n") 373 } 374} 375 376class BranchPredictionRedirect(implicit p: Parameters) extends Redirect with HasBPUConst { 377 // override def toPrintable: Printable = { 378 // p"-----------BranchPredictionRedirect----------- " + 379 // p"-----------cfiUpdate----------- " + 380 // p"[pc] ${Hexadecimal(cfiUpdate.pc)} " + 381 // p"[predTaken] ${cfiUpdate.predTaken}, [taken] ${cfiUpdate.taken}, [isMisPred] ${cfiUpdate.isMisPred} " + 382 // p"[target] ${Hexadecimal(cfiUpdate.target)} " + 383 // p"------------------------------- " + 384 // p"[robPtr] f=${robIdx.flag} v=${robIdx.value} " + 385 // p"[ftqPtr] f=${ftqIdx.flag} v=${ftqIdx.value} " + 386 // p"[ftqOffset] ${ftqOffset} " + 387 // p"[level] ${level}, [interrupt] ${interrupt} " + 388 // p"[stFtqIdx] f=${stFtqIdx.flag} v=${stFtqIdx.value} " + 389 // p"[stFtqOffset] ${stFtqOffset} " + 390 // p"\n" 391 392 // } 393 394 def display(cond: Bool): Unit = { 395 XSDebug(cond, p"-----------BranchPredictionRedirect----------- \n") 396 XSDebug(cond, p"-----------cfiUpdate----------- \n") 397 XSDebug(cond, p"[pc] ${Hexadecimal(cfiUpdate.pc)}\n") 398 XSDebug(cond, p"[hist] ${Binary(cfiUpdate.hist.predHist)}\n") 399 XSDebug(cond, p"[br_hit] ${cfiUpdate.br_hit} [isMisPred] ${cfiUpdate.isMisPred}\n") 400 XSDebug(cond, p"[pred_taken] ${cfiUpdate.predTaken} [taken] ${cfiUpdate.taken} [isMisPred] ${cfiUpdate.isMisPred}\n") 401 XSDebug(cond, p"[target] ${Hexadecimal(cfiUpdate.target)} \n") 402 XSDebug(cond, p"[shift] ${cfiUpdate.shift}\n") 403 XSDebug(cond, p"------------------------------- \n") 404 XSDebug(cond, p"[robPtr] f=${robIdx.flag} v=${robIdx.value}\n") 405 XSDebug(cond, p"[ftqPtr] f=${ftqIdx.flag} v=${ftqIdx.value} \n") 406 XSDebug(cond, p"[ftqOffset] ${ftqOffset} \n") 407 XSDebug(cond, p"[stFtqIdx] f=${stFtqIdx.flag} v=${stFtqIdx.value}\n") 408 XSDebug(cond, p"[stFtqOffset] ${stFtqOffset}\n") 409 XSDebug(cond, p"---------------------------------------------- \n") 410 } 411} 412