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