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 xiangshan._ 23import xiangshan.cache._ 24import xiangshan.cache.mmu._ 25import chisel3.experimental.verification 26import utils._ 27import xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle} 28 29trait HasInstrMMIOConst extends HasXSParameter with HasIFUConst{ 30 def mmioBusWidth = 64 31 def mmioBusBytes = mmioBusWidth / 8 32 def maxInstrLen = 32 33} 34 35trait HasIFUConst extends HasXSParameter { 36 def align(pc: UInt, bytes: Int): UInt = Cat(pc(VAddrBits-1, log2Ceil(bytes)), 0.U(log2Ceil(bytes).W)) 37 // def groupAligned(pc: UInt) = align(pc, groupBytes) 38 // def packetAligned(pc: UInt) = align(pc, packetBytes) 39} 40 41class IfuToFtqIO(implicit p:Parameters) extends XSBundle { 42 val pdWb = Valid(new PredecodeWritebackBundle) 43} 44 45class FtqInterface(implicit p: Parameters) extends XSBundle { 46 val fromFtq = Flipped(new FtqToIfuIO) 47 val toFtq = new IfuToFtqIO 48} 49 50class UncacheInterface(implicit p: Parameters) extends XSBundle { 51 val fromUncache = Flipped(DecoupledIO(new InsUncacheResp)) 52 val toUncache = DecoupledIO( new InsUncacheReq ) 53} 54 55class ICacheInterface(implicit p: Parameters) extends XSBundle { 56 val toIMeta = Decoupled(new ICacheReadBundle) 57 val toIData = Decoupled(new ICacheReadBundle) 58 val toMissQueue = Vec(2,Decoupled(new ICacheMissReq)) 59 val fromIMeta = Input(new ICacheMetaRespBundle) 60 val fromIData = Input(new ICacheDataRespBundle) 61 val fromMissQueue = Vec(2,Flipped(Decoupled(new ICacheMissResp))) 62} 63 64class NewIFUIO(implicit p: Parameters) extends XSBundle { 65 val ftqInter = new FtqInterface 66 val icacheInter = new ICacheInterface 67 val toIbuffer = Decoupled(new FetchToIBuffer) 68 val iTLBInter = Vec(2, new BlockTlbRequestIO) 69 val uncacheInter = new UncacheInterface 70 val pmp = Vec(2, new Bundle { 71 val req = Valid(new PMPReqBundle()) 72 val resp = Flipped(new PMPRespBundle()) 73 }) 74 val frontendTrigger = Flipped(new FrontendTdataDistributeIO) 75 val csrTriggerEnable = Input(Vec(4, Bool())) 76 val rob_commits = Flipped(Vec(CommitWidth, Valid(new RobCommitInfo))) 77} 78 79// record the situation in which fallThruAddr falls into 80// the middle of an RVI inst 81class LastHalfInfo(implicit p: Parameters) extends XSBundle { 82 val valid = Bool() 83 val middlePC = UInt(VAddrBits.W) 84 def matchThisBlock(startAddr: UInt) = valid && middlePC === startAddr 85} 86 87class IfuToPreDecode(implicit p: Parameters) extends XSBundle { 88 val data = if(HasCExtension) Vec(PredictWidth + 1, UInt(16.W)) else Vec(PredictWidth, UInt(32.W)) 89 val startAddr = UInt(VAddrBits.W) 90 val fallThruAddr = UInt(VAddrBits.W) 91 val fallThruError = Bool() 92 val isDoubleLine = Bool() 93 val ftqOffset = Valid(UInt(log2Ceil(PredictWidth).W)) 94 val target = UInt(VAddrBits.W) 95 val pageFault = Vec(2, Bool()) 96 val accessFault = Vec(2, Bool()) 97 val instValid = Bool() 98 val lastHalfMatch = Bool() 99 val oversize = Bool() 100 val mmio = Bool() 101 val frontendTrigger = new FrontendTdataDistributeIO 102 val csrTriggerEnable = Vec(4, Bool()) 103} 104 105class NewIFU(implicit p: Parameters) extends XSModule with HasICacheParameters 106with HasCircularQueuePtrHelper 107{ 108 println(s"icache ways: ${nWays} sets:${nSets}") 109 val io = IO(new NewIFUIO) 110 val (toFtq, fromFtq) = (io.ftqInter.toFtq, io.ftqInter.fromFtq) 111 val (toMeta, toData, meta_resp, data_resp) = (io.icacheInter.toIMeta, io.icacheInter.toIData, io.icacheInter.fromIMeta, io.icacheInter.fromIData) 112 val (toMissQueue, fromMissQueue) = (io.icacheInter.toMissQueue, io.icacheInter.fromMissQueue) 113 val (toUncache, fromUncache) = (io.uncacheInter.toUncache , io.uncacheInter.fromUncache) 114 val (toITLB, fromITLB) = (VecInit(io.iTLBInter.map(_.req)), VecInit(io.iTLBInter.map(_.resp))) 115 val fromPMP = io.pmp.map(_.resp) 116 117 def isCrossLineReq(start: UInt, end: UInt): Bool = start(blockOffBits) ^ end(blockOffBits) 118 119 def isLastInCacheline(fallThruAddr: UInt): Bool = fallThruAddr(blockOffBits - 1, 1) === 0.U 120 121 def ResultHoldBypass[T<:Data](data: T, valid: Bool): T = { 122 Mux(valid, data, RegEnable(data, valid)) 123 } 124 125 //--------------------------------------------- 126 // Fetch Stage 1 : 127 // * Send req to ICache Meta/Data 128 // * Check whether need 2 line fetch 129 //--------------------------------------------- 130 131 val f0_valid = fromFtq.req.valid 132 val f0_ftq_req = fromFtq.req.bits 133 val f0_situation = VecInit(Seq(isCrossLineReq(f0_ftq_req.startAddr, f0_ftq_req.fallThruAddr), isLastInCacheline(f0_ftq_req.fallThruAddr))) 134 val f0_doubleLine = f0_situation(0) || f0_situation(1) 135 val f0_vSetIdx = VecInit(get_idx((f0_ftq_req.startAddr)), get_idx(f0_ftq_req.fallThruAddr)) 136 val f0_fire = fromFtq.req.fire() 137 138 val f0_flush, f1_flush, f2_flush, f3_flush = WireInit(false.B) 139 val from_bpu_f0_flush, from_bpu_f1_flush, from_bpu_f2_flush, from_bpu_f3_flush = WireInit(false.B) 140 141 from_bpu_f0_flush := fromFtq.flushFromBpu.shouldFlushByStage2(f0_ftq_req.ftqIdx)/* || 142 fromFtq.flushFromBpu.shouldFlushByStage3(f0_ftq_req.ftqIdx) */ 143 144 val f3_redirect = WireInit(false.B) 145 f3_flush := fromFtq.redirect.valid 146 f2_flush := f3_flush || f3_redirect 147 f1_flush := f2_flush || from_bpu_f1_flush 148 f0_flush := f1_flush || from_bpu_f0_flush 149 150 val f1_ready, f2_ready, f3_ready = WireInit(false.B) 151 152 //fetch: send addr to Meta/TLB and Data simultaneously 153 val fetch_req = List(toMeta, toData) 154 for(i <- 0 until 2) { 155 fetch_req(i).valid := f0_fire 156 fetch_req(i).bits.isDoubleLine := f0_doubleLine 157 fetch_req(i).bits.vSetIdx := f0_vSetIdx 158 } 159 160 fromFtq.req.ready := fetch_req(0).ready && fetch_req(1).ready && f1_ready && GTimer() > 500.U 161 162 XSPerfAccumulate("ifu_bubble_ftq_not_valid", !f0_valid ) 163 XSPerfAccumulate("ifu_bubble_pipe_stall", f0_valid && fetch_req(0).ready && fetch_req(1).ready && !f1_ready ) 164 XSPerfAccumulate("ifu_bubble_sram_0_busy", f0_valid && !fetch_req(0).ready ) 165 XSPerfAccumulate("ifu_bubble_sram_1_busy", f0_valid && !fetch_req(1).ready ) 166 167 //--------------------------------------------- 168 // Fetch Stage 2 : 169 // * Send req to ITLB and TLB Response (Get Paddr) 170 // * ICache Response (Get Meta and Data) 171 // * Hit Check (Generate hit signal and hit vector) 172 // * Get victim way 173 //--------------------------------------------- 174 175 //TODO: handle fetch exceptions 176 177 val tlbRespAllValid = WireInit(false.B) 178 179 val f1_valid = RegInit(false.B) 180 val f1_ftq_req = RegEnable(next = f0_ftq_req, enable=f0_fire) 181 val f1_situation = RegEnable(next = f0_situation, enable=f0_fire) 182 val f1_doubleLine = RegEnable(next = f0_doubleLine, enable=f0_fire) 183 val f1_vSetIdx = RegEnable(next = f0_vSetIdx, enable=f0_fire) 184 val f1_fire = f1_valid && tlbRespAllValid && f2_ready 185 186 f1_ready := f2_ready && tlbRespAllValid || !f1_valid 187 188 // from_bpu_f1_flush := fromFtq.flushFromBpu.shouldFlushByStage3(f1_ftq_req.ftqIdx) 189 from_bpu_f1_flush := false.B 190 191 val preDecoder = Module(new PreDecode) 192 val (preDecoderIn, preDecoderOut) = (preDecoder.io.in, preDecoder.io.out) 193 194 //flush generate and to Ftq 195 val predecodeOutValid = WireInit(false.B) 196 197 when(f1_flush) {f1_valid := false.B} 198 .elsewhen(f0_fire && !f0_flush) {f1_valid := true.B} 199 .elsewhen(f1_fire) {f1_valid := false.B} 200 201 toITLB(0).valid := f1_valid 202 toITLB(0).bits.size := 3.U // TODO: fix the size 203 toITLB(0).bits.vaddr := f1_ftq_req.startAddr 204 toITLB(0).bits.debug.pc := f1_ftq_req.startAddr 205 206 toITLB(1).valid := f1_valid && f1_doubleLine 207 toITLB(1).bits.size := 3.U // TODO: fix the size 208 toITLB(1).bits.vaddr := f1_ftq_req.fallThruAddr 209 toITLB(1).bits.debug.pc := f1_ftq_req.fallThruAddr 210 211 toITLB.map{port => 212 port.bits.cmd := TlbCmd.exec 213 port.bits.robIdx := DontCare 214 port.bits.debug.isFirstIssue := DontCare 215 } 216 217 fromITLB.map(_.ready := true.B) 218 219 val (tlbRespValid, tlbRespPAddr) = (fromITLB.map(_.valid), VecInit(fromITLB.map(_.bits.paddr))) 220 val (tlbRespMiss) = (fromITLB.map(port => port.bits.miss && port.valid)) 221 val (tlbExcpPF, tlbExcpAF) = (fromITLB.map(port => port.bits.excp.pf.instr && port.valid), 222 fromITLB.map(port => (port.bits.excp.af.instr) && port.valid)) //TODO: Temp treat mmio req as access fault 223 224 tlbRespAllValid := tlbRespValid(0) && (tlbRespValid(1) || !f1_doubleLine) 225 226 val f1_pAddrs = tlbRespPAddr 227 val f1_pTags = VecInit(f1_pAddrs.map(get_phy_tag(_))) 228 229 val f1_tags = ResultHoldBypass(data = meta_resp.tags, valid = RegNext(toMeta.fire())) 230 val f1_cacheline_valid = ResultHoldBypass(data = meta_resp.valid, valid = RegNext(toMeta.fire())) 231 val f1_datas = ResultHoldBypass(data = data_resp.datas, valid = RegNext(toData.fire())) 232 233 val bank0_hit_vec = VecInit(f1_tags(0).zipWithIndex.map{ case(way_tag,i) => f1_cacheline_valid(0)(i) && way_tag === f1_pTags(0) }) 234 val bank1_hit_vec = VecInit(f1_tags(1).zipWithIndex.map{ case(way_tag,i) => f1_cacheline_valid(1)(i) && way_tag === f1_pTags(1) }) 235 val (bank0_hit,bank1_hit) = (ParallelOR(bank0_hit_vec) && !tlbExcpPF(0) && !tlbExcpAF(0), ParallelOR(bank1_hit_vec) && !tlbExcpPF(1) && !tlbExcpAF(1)) 236 val f1_hit = (bank0_hit && bank1_hit && f1_valid && f1_doubleLine) || (f1_valid && !f1_doubleLine && bank0_hit) 237 val f1_bank_hit_vec = VecInit(Seq(bank0_hit_vec, bank1_hit_vec)) 238 val f1_bank_hit = VecInit(Seq(bank0_hit, bank1_hit)) 239 240 241 val replacers = Seq.fill(2)(ReplacementPolicy.fromString(Some("random"),nWays,nSets/2)) 242 val f1_victim_masks = VecInit(replacers.zipWithIndex.map{case (replacer, i) => UIntToOH(replacer.way(f1_vSetIdx(i)))}) 243 244 val touch_sets = Seq.fill(2)(Wire(Vec(2, UInt(log2Ceil(nSets/2).W)))) 245 val touch_ways = Seq.fill(2)(Wire(Vec(2, Valid(UInt(log2Ceil(nWays).W)))) ) 246 247 ((replacers zip touch_sets) zip touch_ways).map{case ((r, s),w) => r.access(s,w)} 248 249 val f1_hit_data = VecInit(f1_datas.zipWithIndex.map { case(bank, i) => 250 val bank_hit_data = Mux1H(f1_bank_hit_vec(i).asUInt, bank) 251 bank_hit_data 252 }) 253 254 (0 until nWays).map{ w => 255 XSPerfAccumulate("line_0_hit_way_" + Integer.toString(w, 10), f1_fire && f1_bank_hit(0) && OHToUInt(f1_bank_hit_vec(0)) === w.U) 256 } 257 258 (0 until nWays).map{ w => 259 XSPerfAccumulate("line_0_victim_way_" + Integer.toString(w, 10), f1_fire && !f1_bank_hit(0) && OHToUInt(f1_victim_masks(0)) === w.U) 260 } 261 262 (0 until nWays).map{ w => 263 XSPerfAccumulate("line_1_hit_way_" + Integer.toString(w, 10), f1_fire && f1_doubleLine && f1_bank_hit(1) && OHToUInt(f1_bank_hit_vec(1)) === w.U) 264 } 265 266 (0 until nWays).map{ w => 267 XSPerfAccumulate("line_1_victim_way_" + Integer.toString(w, 10), f1_fire && f1_doubleLine && !f1_bank_hit(1) && OHToUInt(f1_victim_masks(1)) === w.U) 268 } 269 270 XSPerfAccumulate("ifu_bubble_f1_tlb_miss", f1_valid && !tlbRespAllValid ) 271 272 //--------------------------------------------- 273 // Fetch Stage 3 : 274 // * get data from last stage (hit from f1_hit_data/miss from missQueue response) 275 // * if at least one needed cacheline miss, wait for miss queue response (a wait_state machine) THIS IS TOO UGLY!!! 276 // * cut cacheline(s) and send to PreDecode 277 // * check if prediction is right (branch target and type, jump direction and type , jal target ) 278 //--------------------------------------------- 279 val f2_fetchFinish = Wire(Bool()) 280 281 val f2_valid = RegInit(false.B) 282 val f2_ftq_req = RegEnable(next = f1_ftq_req, enable = f1_fire) 283 val f2_situation = RegEnable(next = f1_situation, enable=f1_fire) 284 val f2_doubleLine = RegEnable(next = f1_doubleLine, enable=f1_fire) 285 val f2_fire = f2_valid && f2_fetchFinish && f3_ready 286 287 when(f2_flush) {f2_valid := false.B} 288 .elsewhen(f1_fire && !f1_flush) {f2_valid := true.B } 289 .elsewhen(f2_fire) {f2_valid := false.B} 290 291 val pmpExcpAF = fromPMP.map(port => port.instr) 292 val mmio = fromPMP.map(port => port.mmio) // TODO: handle it 293 294 295 val f2_pAddrs = RegEnable(next = f1_pAddrs, enable = f1_fire) 296 val f2_hit = RegEnable(next = f1_hit , enable = f1_fire) 297 val f2_bank_hit = RegEnable(next = f1_bank_hit, enable = f1_fire) 298 val f2_miss = f2_valid && !f2_hit 299 val (f2_vSetIdx, f2_pTags) = (RegEnable(next = f1_vSetIdx, enable = f1_fire), RegEnable(next = f1_pTags, enable = f1_fire)) 300 val f2_waymask = RegEnable(next = f1_victim_masks, enable = f1_fire) 301 //exception information 302 val f2_except_pf = RegEnable(next = VecInit(tlbExcpPF), enable = f1_fire) 303 val f2_except_af = VecInit(RegEnable(next = VecInit(tlbExcpAF), enable = f1_fire).zip(pmpExcpAF).map(a => a._1 || DataHoldBypass(a._2, RegNext(f1_fire)).asBool)) 304 val f2_except = VecInit((0 until 2).map{i => f2_except_pf(i) || f2_except_af(i)}) 305 val f2_has_except = f2_valid && (f2_except_af.reduce(_||_) || f2_except_pf.reduce(_||_)) 306 val f2_mmio = io.pmp(0).resp.mmio && !f2_except_af(0) && !f2_except_pf(0) && f2_valid 307 308 f2_ready := (f3_ready && f2_fetchFinish) || !f2_valid 309 310 311 io.pmp.zipWithIndex.map { case (p, i) => 312 p.req.valid := f2_fire 313 p.req.bits.addr := f2_pAddrs(i) 314 p.req.bits.size := 3.U // TODO 315 p.req.bits.cmd := TlbCmd.exec 316 } 317 318 //instruction 319 val wait_idle :: wait_queue_ready :: wait_send_req :: wait_two_resp :: wait_0_resp :: wait_1_resp :: wait_one_resp ::wait_finish ::Nil = Enum(8) 320 val wait_state = RegInit(wait_idle) 321 322 fromMissQueue.map{port => port.ready := true.B} 323 324 val (miss0_resp, miss1_resp) = (fromMissQueue(0).fire(), fromMissQueue(1).fire()) 325 val (bank0_fix, bank1_fix) = (miss0_resp && !f2_bank_hit(0), miss1_resp && f2_doubleLine && !f2_bank_hit(1)) 326 327 val only_0_miss = f2_valid && !f2_hit && !f2_doubleLine && !f2_has_except && !f2_mmio 328 val only_0_hit = f2_valid && f2_hit && !f2_doubleLine && !f2_mmio 329 val hit_0_hit_1 = f2_valid && f2_hit && f2_doubleLine && !f2_mmio 330 val (hit_0_miss_1 , miss_0_hit_1, miss_0_miss_1) = ( (f2_valid && !f2_bank_hit(1) && f2_bank_hit(0) && f2_doubleLine && !f2_has_except && !f2_mmio), 331 (f2_valid && !f2_bank_hit(0) && f2_bank_hit(1) && f2_doubleLine && !f2_has_except && !f2_mmio), 332 (f2_valid && !f2_bank_hit(0) && !f2_bank_hit(1) && f2_doubleLine && !f2_has_except && !f2_mmio), 333 ) 334 335 val hit_0_except_1 = f2_valid && f2_doubleLine && !f2_except(0) && f2_except(1) && f2_bank_hit(0) 336 val miss_0_except_1 = f2_valid && f2_doubleLine && !f2_except(0) && f2_except(1) && !f2_bank_hit(0) 337 //val fetch0_except_1 = hit_0_except_1 || miss_0_except_1 338 val except_0 = f2_valid && f2_except(0) 339 340 val f2_mq_datas = Reg(Vec(2, UInt(blockBits.W))) 341 342 when(fromMissQueue(0).fire) {f2_mq_datas(0) := fromMissQueue(0).bits.data} 343 when(fromMissQueue(1).fire) {f2_mq_datas(1) := fromMissQueue(1).bits.data} 344 345 switch(wait_state){ 346 is(wait_idle){ 347 when(miss_0_except_1){ 348 wait_state := Mux(toMissQueue(0).ready, wait_queue_ready ,wait_idle ) 349 }.elsewhen( only_0_miss || miss_0_hit_1){ 350 wait_state := Mux(toMissQueue(0).ready, wait_queue_ready ,wait_idle ) 351 }.elsewhen(hit_0_miss_1){ 352 wait_state := Mux(toMissQueue(1).ready, wait_queue_ready ,wait_idle ) 353 }.elsewhen( miss_0_miss_1 ){ 354 wait_state := Mux(toMissQueue(0).ready && toMissQueue(1).ready, wait_queue_ready ,wait_idle) 355 } 356 } 357 358 //TODO: naive logic for wait icache response 359 is(wait_queue_ready){ 360 wait_state := wait_send_req 361 } 362 363 is(wait_send_req) { 364 when(miss_0_except_1 || only_0_miss || hit_0_miss_1 || miss_0_hit_1){ 365 wait_state := wait_one_resp 366 }.elsewhen( miss_0_miss_1 ){ 367 wait_state := wait_two_resp 368 } 369 } 370 371 is(wait_one_resp) { 372 when( (miss_0_except_1 ||only_0_miss || miss_0_hit_1) && fromMissQueue(0).fire()){ 373 wait_state := wait_finish 374 }.elsewhen( hit_0_miss_1 && fromMissQueue(1).fire()){ 375 wait_state := wait_finish 376 } 377 } 378 379 is(wait_two_resp) { 380 when(fromMissQueue(0).fire() && fromMissQueue(1).fire()){ 381 wait_state := wait_finish 382 }.elsewhen( !fromMissQueue(0).fire() && fromMissQueue(1).fire() ){ 383 wait_state := wait_0_resp 384 }.elsewhen(fromMissQueue(0).fire() && !fromMissQueue(1).fire()){ 385 wait_state := wait_1_resp 386 } 387 } 388 389 is(wait_0_resp) { 390 when(fromMissQueue(0).fire()){ 391 wait_state := wait_finish 392 } 393 } 394 395 is(wait_1_resp) { 396 when(fromMissQueue(1).fire()){ 397 wait_state := wait_finish 398 } 399 } 400 401 is(wait_finish) { 402 when(f2_fire) {wait_state := wait_idle } 403 } 404 } 405 406 when(f2_flush) { wait_state := wait_idle } 407 408 (0 until 2).map { i => 409 if(i == 1) toMissQueue(i).valid := (hit_0_miss_1 || miss_0_miss_1) && wait_state === wait_queue_ready 410 else toMissQueue(i).valid := (only_0_miss || miss_0_hit_1 || miss_0_miss_1 || miss_0_except_1) && wait_state === wait_queue_ready 411 toMissQueue(i).bits.addr := f2_pAddrs(i) 412 toMissQueue(i).bits.vSetIdx := f2_vSetIdx(i) 413 toMissQueue(i).bits.waymask := f2_waymask(i) 414 toMissQueue(i).bits.clientID :=0.U 415 } 416 417 418 val miss_all_fix = (wait_state === wait_finish) 419 420 f2_fetchFinish := ((f2_valid && f2_hit) || (f2_valid && f2_mmio) || miss_all_fix || hit_0_except_1 || except_0) 421 422 XSPerfAccumulate("ifu_bubble_f2_miss", f2_valid && !f2_fetchFinish ) 423 424 (touch_ways zip touch_sets).zipWithIndex.map{ case((t_w,t_s), i) => 425 t_s(0) := f1_vSetIdx(i) 426 t_w(0).valid := f1_bank_hit(i) 427 t_w(0).bits := OHToUInt(f1_bank_hit_vec(i)) 428 429 t_s(1) := f2_vSetIdx(i) 430 t_w(1).valid := f2_valid && !f2_bank_hit(i) 431 t_w(1).bits := OHToUInt(f2_waymask(i)) 432 } 433 434 val sec_miss_reg = RegInit(0.U.asTypeOf(Vec(4, Bool()))) 435 val reservedRefillData = Reg(Vec(2, UInt(blockBits.W))) 436 val f2_hit_datas = RegEnable(next = f1_hit_data, enable = f1_fire) 437 val f2_datas = Wire(Vec(2, UInt(blockBits.W))) 438 439 f2_datas.zipWithIndex.map{case(bank,i) => 440 if(i == 0) bank := Mux(f2_bank_hit(i), f2_hit_datas(i),Mux(sec_miss_reg(2),reservedRefillData(1),Mux(sec_miss_reg(0),reservedRefillData(0), f2_mq_datas(i)))) 441 else bank := Mux(f2_bank_hit(i), f2_hit_datas(i),Mux(sec_miss_reg(3),reservedRefillData(1),Mux(sec_miss_reg(1),reservedRefillData(0), f2_mq_datas(i)))) 442 } 443 444 val f2_jump_valids = Fill(PredictWidth, !preDecoderOut.cfiOffset.valid) | Fill(PredictWidth, 1.U(1.W)) >> (~preDecoderOut.cfiOffset.bits) 445 val f2_predecode_valids = VecInit(preDecoderOut.pd.map(instr => instr.valid)).asUInt & f2_jump_valids 446 447 def cut(cacheline: UInt, start: UInt) : Vec[UInt] ={ 448 if(HasCExtension){ 449 val result = Wire(Vec(PredictWidth + 1, UInt(16.W))) 450 val dataVec = cacheline.asTypeOf(Vec(blockBytes * 2/ 2, UInt(16.W))) 451 val startPtr = Cat(0.U(1.W), start(blockOffBits-1, 1)) 452 (0 until PredictWidth + 1).foreach( i => 453 result(i) := dataVec(startPtr + i.U) 454 ) 455 result 456 } else { 457 val result = Wire(Vec(PredictWidth, UInt(32.W)) ) 458 val dataVec = cacheline.asTypeOf(Vec(blockBytes * 2/ 4, UInt(32.W))) 459 val startPtr = Cat(0.U(1.W), start(blockOffBits-1, 2)) 460 (0 until PredictWidth).foreach( i => 461 result(i) := dataVec(startPtr + i.U) 462 ) 463 result 464 } 465 } 466 467 val f2_cut_data = cut( Cat(f2_datas.map(cacheline => cacheline.asUInt ).reverse).asUInt, f2_ftq_req.startAddr ) 468 469 // deal with secondary miss in f1 470 val f2_0_f1_0 = ((f2_valid && !f2_bank_hit(0)) && f1_valid && (get_block_addr(f2_ftq_req.startAddr) === get_block_addr(f1_ftq_req.startAddr))) 471 val f2_0_f1_1 = ((f2_valid && !f2_bank_hit(0)) && f1_valid && f1_doubleLine && (get_block_addr(f2_ftq_req.startAddr) === get_block_addr(f1_ftq_req.startAddr + blockBytes.U))) 472 val f2_1_f1_0 = ((f2_valid && !f2_bank_hit(1) && f2_doubleLine) && f1_valid && (get_block_addr(f2_ftq_req.startAddr+ blockBytes.U) === get_block_addr(f1_ftq_req.startAddr) )) 473 val f2_1_f1_1 = ((f2_valid && !f2_bank_hit(1) && f2_doubleLine) && f1_valid && f1_doubleLine && (get_block_addr(f2_ftq_req.startAddr+ blockBytes.U) === get_block_addr(f1_ftq_req.startAddr + blockBytes.U) )) 474 475 val isSameLine = f2_0_f1_0 || f2_0_f1_1 || f2_1_f1_0 || f2_1_f1_1 476 val sec_miss_sit = VecInit(Seq(f2_0_f1_0, f2_0_f1_1, f2_1_f1_0, f2_1_f1_1)) 477 val hasSecMiss = RegInit(false.B) 478 479 when(f2_flush){ 480 sec_miss_reg.map(sig => sig := false.B) 481 hasSecMiss := false.B 482 }.elsewhen(isSameLine && !f1_flush && f2_fire){ 483 sec_miss_reg.zipWithIndex.map{case(sig, i) => sig := sec_miss_sit(i)} 484 hasSecMiss := true.B 485 }.elsewhen((!isSameLine || f1_flush) && hasSecMiss && f2_fire){ 486 sec_miss_reg.map(sig => sig := false.B) 487 hasSecMiss := false.B 488 } 489 490 when((f2_0_f1_0 || f2_0_f1_1) && f2_fire){ 491 reservedRefillData(0) := f2_mq_datas(0) 492 } 493 494 when((f2_1_f1_0 || f2_1_f1_1) && f2_fire){ 495 reservedRefillData(1) := f2_mq_datas(1) 496 } 497 498 499 //--------------------------------------------- 500 // Fetch Stage 4 : 501 // * get data from last stage (hit from f1_hit_data/miss from missQueue response) 502 // * if at least one needed cacheline miss, wait for miss queue response (a wait_state machine) THIS IS TOO UGLY!!! 503 // * cut cacheline(s) and send to PreDecode 504 // * check if prediction is right (branch target and type, jump direction and type , jal target ) 505 //--------------------------------------------- 506 val f3_valid = RegInit(false.B) 507 val f3_ftq_req = RegEnable(next = f2_ftq_req, enable=f2_fire) 508 val f3_situation = RegEnable(next = f2_situation, enable=f2_fire) 509 val f3_doubleLine = RegEnable(next = f2_doubleLine, enable=f2_fire) 510 511 val f3_cut_data = RegEnable(next = f2_cut_data, enable=f2_fire) 512 val f3_except_pf = RegEnable(next = f2_except_pf, enable = f2_fire) 513 val f3_except_af = RegEnable(next = f2_except_af, enable = f2_fire) 514 val f3_hit = RegEnable(next = f2_hit , enable = f2_fire) 515 val f3_mmio = RegEnable(next = f2_mmio , enable = f2_fire) 516 517 //assert((f3_ftq_req.startAddr + 34.U) >= f3_ftq_req.fallThruAddr, "Fall through address exceeds the limit") 518 519 val f3_lastHalf = RegInit(0.U.asTypeOf(new LastHalfInfo)) 520 val f3_lastHalfMatch = f3_lastHalf.matchThisBlock(f3_ftq_req.startAddr) 521 val f3_except = VecInit((0 until 2).map{i => f3_except_pf(i) || f3_except_af(i)}) 522 val f3_has_except = f3_valid && (f3_except_af.reduce(_||_) || f3_except_pf.reduce(_||_)) 523 val f3_pAddrs = RegEnable(next = f2_pAddrs, enable = f2_fire) 524 525 val f3_mmio_data = Reg(UInt(maxInstrLen.W)) 526 527 val f3_data = if(HasCExtension) Wire(Vec(PredictWidth + 1, UInt(16.W))) else Wire(Vec(PredictWidth, UInt(32.W))) 528 f3_data := f3_cut_data 529 530 //performance counter 531 val f3_only_0_hit = RegEnable(next = only_0_hit, enable = f2_fire) 532 val f3_only_0_miss = RegEnable(next = only_0_miss, enable = f2_fire) 533 val f3_hit_0_hit_1 = RegEnable(next = hit_0_hit_1, enable = f2_fire) 534 val f3_hit_0_miss_1 = RegEnable(next = hit_0_miss_1, enable = f2_fire) 535 val f3_miss_0_hit_1 = RegEnable(next = miss_0_hit_1, enable = f2_fire) 536 val f3_miss_0_miss_1 = RegEnable(next = miss_0_miss_1, enable = f2_fire) 537 538 val mmio_idle :: mmio_send_req :: mmio_w_resp :: mmio_resend :: mmio_resend_w_resp :: mmio_w_commit :: Nil = Enum(6) 539 val mmio_state = RegInit(mmio_idle) 540 541 val f3_req_is_mmio = f3_mmio && f3_valid 542 val mmio_has_commited = VecInit(io.rob_commits.map{commit => commit.valid && commit.bits.ftqIdx === f3_ftq_req.ftqIdx && commit.bits.ftqOffset === 0.U}).asUInt.orR 543 val f3_mmio_req_commit = f3_req_is_mmio && mmio_state === mmio_w_commit && mmio_has_commited 544 545 val f3_mmio_to_commit = f3_req_is_mmio && mmio_state === mmio_w_commit 546 val f3_mmio_to_commit_next = RegNext(f3_mmio_to_commit) 547 val f3_mmio_can_go = f3_mmio_to_commit && !f3_mmio_to_commit_next 548 549 val f3_ftq_flush_self = fromFtq.redirect.valid && RedirectLevel.flushItself(fromFtq.redirect.bits.level) 550 val f3_ftq_flush_by_older = fromFtq.redirect.valid && isBefore(fromFtq.redirect.bits.ftqIdx, f3_ftq_req.ftqIdx) 551 552 val f3_need_not_flush = f3_req_is_mmio && fromFtq.redirect.valid && !f3_ftq_flush_self && !f3_ftq_flush_by_older 553 554 when(f3_flush && !f3_need_not_flush) {f3_valid := false.B} 555 .elsewhen(f2_fire && !f2_flush) {f3_valid := true.B } 556 .elsewhen(io.toIbuffer.fire() && !f3_req_is_mmio) {f3_valid := false.B} 557 .elsewhen{f3_req_is_mmio && f3_mmio_req_commit} {f3_valid := false.B} 558 559 val f3_mmio_use_seq_pc = RegInit(false.B) 560 561 val (redirect_ftqIdx, redirect_ftqOffset) = (fromFtq.redirect.bits.ftqIdx,fromFtq.redirect.bits.ftqOffset) 562 val redirect_mmio_req = fromFtq.redirect.valid && redirect_ftqIdx === f3_ftq_req.ftqIdx && redirect_ftqOffset === 0.U 563 564 when(RegNext(f2_fire && !f2_flush) && f3_req_is_mmio) { f3_mmio_use_seq_pc := true.B } 565 .elsewhen(redirect_mmio_req) { f3_mmio_use_seq_pc := false.B } 566 567 f3_ready := Mux(f3_req_is_mmio, io.toIbuffer.ready && f3_mmio_req_commit || !f3_valid , io.toIbuffer.ready || !f3_valid) 568 569 when(f3_req_is_mmio){ 570 f3_data(0) := f3_mmio_data(15, 0) 571 f3_data(1) := f3_mmio_data(31, 16) 572 } 573 574 when(fromUncache.fire()) {f3_mmio_data := fromUncache.bits.data} 575 576 577 switch(mmio_state){ 578 is(mmio_idle){ 579 when(f3_req_is_mmio){ 580 mmio_state := mmio_send_req 581 } 582 } 583 584 is(mmio_send_req){ 585 mmio_state := Mux(toUncache.fire(), mmio_w_resp, mmio_send_req ) 586 } 587 588 is(mmio_w_resp){ 589 when(fromUncache.fire()){ 590 val isRVC = fromUncache.bits.data(1,0) =/= 3.U 591 mmio_state := Mux(isRVC, mmio_resend , mmio_w_commit) 592 } 593 } 594 595 is(mmio_resend){ 596 mmio_state := Mux(toUncache.fire(), mmio_resend_w_resp, mmio_resend ) 597 } 598 599 is(mmio_resend_w_resp){ 600 when(fromUncache.fire()){ 601 mmio_state := mmio_w_commit 602 } 603 } 604 605 is(mmio_w_commit){ 606 when(mmio_has_commited){ 607 mmio_state := mmio_idle 608 } 609 } 610 } 611 612 when(f3_ftq_flush_self || f3_ftq_flush_by_older) { 613 mmio_state := mmio_idle 614 f3_mmio_data := 0.U 615 } 616 617 toUncache.valid := ((mmio_state === mmio_send_req) || (mmio_state === mmio_resend)) && f3_req_is_mmio 618 toUncache.bits.addr := Mux((mmio_state === mmio_resend), f3_pAddrs(0) + 2.U, f3_pAddrs(0)) 619 fromUncache.ready := true.B 620 621 val f3_bank_hit = RegEnable(next = f2_bank_hit, enable = f2_fire) 622 val f3_req_0 = io.toIbuffer.fire() 623 val f3_req_1 = io.toIbuffer.fire() && f3_doubleLine 624 val f3_hit_0 = io.toIbuffer.fire() & f3_bank_hit(0) 625 val f3_hit_1 = io.toIbuffer.fire() && f3_doubleLine & f3_bank_hit(1) 626 627 preDecoderIn.instValid := f3_valid && !f3_has_except 628 preDecoderIn.data := f3_data 629 preDecoderIn.startAddr := f3_ftq_req.startAddr 630 preDecoderIn.fallThruAddr := f3_ftq_req.fallThruAddr 631 preDecoderIn.fallThruError := f3_ftq_req.fallThruError 632 preDecoderIn.isDoubleLine := f3_doubleLine 633 preDecoderIn.ftqOffset := f3_ftq_req.ftqOffset 634 preDecoderIn.target := f3_ftq_req.target 635 preDecoderIn.oversize := f3_ftq_req.oversize 636 preDecoderIn.lastHalfMatch := f3_lastHalfMatch 637 preDecoderIn.pageFault := f3_except_pf 638 preDecoderIn.accessFault := f3_except_af 639 preDecoderIn.mmio := f3_mmio 640 preDecoderIn.frontendTrigger := io.frontendTrigger 641 preDecoderIn.csrTriggerEnable := io.csrTriggerEnable 642 643 644 // TODO: What if next packet does not match? 645 when (f3_flush) { 646 f3_lastHalf.valid := false.B 647 }.elsewhen (io.toIbuffer.fire()) { 648 f3_lastHalf.valid := preDecoderOut.hasLastHalf 649 f3_lastHalf.middlePC := preDecoderOut.realEndPC 650 } 651 652 val f3_predecode_range = VecInit(preDecoderOut.pd.map(inst => inst.valid)).asUInt 653 val f3_mmio_range = VecInit((0 until PredictWidth).map(i => if(i ==0) true.B else false.B)) 654 655 io.toIbuffer.valid := f3_valid && (!f3_req_is_mmio || f3_mmio_can_go) 656 io.toIbuffer.bits.instrs := preDecoderOut.instrs 657 io.toIbuffer.bits.valid := Mux(f3_req_is_mmio, f3_mmio_range.asUInt, f3_predecode_range & preDecoderOut.instrRange.asUInt) 658 io.toIbuffer.bits.pd := preDecoderOut.pd 659 io.toIbuffer.bits.ftqPtr := f3_ftq_req.ftqIdx 660 io.toIbuffer.bits.pc := preDecoderOut.pc 661 io.toIbuffer.bits.ftqOffset.zipWithIndex.map{case(a, i) => a.bits := i.U; a.valid := preDecoderOut.takens(i) && !f3_req_is_mmio} 662 io.toIbuffer.bits.foldpc := preDecoderOut.pc.map(i => XORFold(i(VAddrBits-1,1), MemPredPCWidth)) 663 io.toIbuffer.bits.ipf := preDecoderOut.pageFault 664 io.toIbuffer.bits.acf := preDecoderOut.accessFault 665 io.toIbuffer.bits.crossPageIPFFix := preDecoderOut.crossPageIPF 666 io.toIbuffer.bits.triggered := preDecoderOut.triggered 667 668 //Write back to Ftq 669 val f3_cache_fetch = f3_valid && !(f2_fire && !f2_flush) 670 val finishFetchMaskReg = RegNext(f3_cache_fetch) 671 672 673 val f3_mmio_missOffset = Wire(ValidUndirectioned(UInt(log2Ceil(PredictWidth).W))) 674 f3_mmio_missOffset.valid := f3_req_is_mmio 675 f3_mmio_missOffset.bits := 0.U 676 677 toFtq.pdWb.valid := (!finishFetchMaskReg && f3_valid && !f3_req_is_mmio) || (f3_mmio_req_commit && f3_mmio_use_seq_pc) 678 toFtq.pdWb.bits.pc := preDecoderOut.pc 679 toFtq.pdWb.bits.pd := preDecoderOut.pd 680 toFtq.pdWb.bits.pd.zipWithIndex.map{case(instr,i) => instr.valid := Mux(f3_req_is_mmio, f3_mmio_range(i), f3_predecode_range(i))} 681 toFtq.pdWb.bits.ftqIdx := f3_ftq_req.ftqIdx 682 toFtq.pdWb.bits.ftqOffset := f3_ftq_req.ftqOffset.bits 683 toFtq.pdWb.bits.misOffset := Mux(f3_req_is_mmio, f3_mmio_missOffset, preDecoderOut.misOffset) 684 toFtq.pdWb.bits.cfiOffset := preDecoderOut.cfiOffset 685 toFtq.pdWb.bits.target := Mux(f3_req_is_mmio,Mux((f3_mmio_data(1,0) =/= 3.U), f3_ftq_req.startAddr + 2.U , f3_ftq_req.startAddr + 4.U) ,preDecoderOut.target) 686 toFtq.pdWb.bits.jalTarget := preDecoderOut.jalTarget 687 toFtq.pdWb.bits.instrRange := Mux(f3_req_is_mmio, f3_mmio_range, preDecoderOut.instrRange) 688 689 val predecodeFlush = preDecoderOut.misOffset.valid && f3_valid 690 val predecodeFlushReg = RegNext(predecodeFlush && !(f2_fire && !f2_flush)) 691 692 val perfinfo = IO(new Bundle(){ 693 val perfEvents = Output(new PerfEventsBundle(15)) 694 }) 695 696 val perfEvents = Seq( 697 ("frontendFlush ", f3_redirect ), 698 ("ifu_req ", io.toIbuffer.fire() ), 699 ("ifu_miss ", io.toIbuffer.fire() && !f3_hit ), 700 ("ifu_req_cacheline_0 ", f3_req_0 ), 701 ("ifu_req_cacheline_1 ", f3_req_1 ), 702 ("ifu_req_cacheline_0_hit ", f3_hit_1 ), 703 ("ifu_req_cacheline_1_hit ", f3_hit_1 ), 704 ("only_0_hit ", f3_only_0_hit && io.toIbuffer.fire() ), 705 ("only_0_miss ", f3_only_0_miss && io.toIbuffer.fire() ), 706 ("hit_0_hit_1 ", f3_hit_0_hit_1 && io.toIbuffer.fire() ), 707 ("hit_0_miss_1 ", f3_hit_0_miss_1 && io.toIbuffer.fire() ), 708 ("miss_0_hit_1 ", f3_miss_0_hit_1 && io.toIbuffer.fire() ), 709 ("miss_0_miss_1 ", f3_miss_0_miss_1 && io.toIbuffer.fire() ), 710 ("cross_line_block ", io.toIbuffer.fire() && f3_situation(0) ), 711 ("fall_through_is_cacheline_end", io.toIbuffer.fire() && f3_situation(1) ), 712 ) 713 714 for (((perf_out,(perf_name,perf)),i) <- perfinfo.perfEvents.perf_events.zip(perfEvents).zipWithIndex) { 715 perf_out.incr_step := RegNext(perf) 716 } 717 718 f3_redirect := (!predecodeFlushReg && predecodeFlush && !f3_req_is_mmio) || (f3_mmio_req_commit && f3_mmio_use_seq_pc) 719 720 XSPerfAccumulate("ifu_req", io.toIbuffer.fire() ) 721 XSPerfAccumulate("ifu_miss", io.toIbuffer.fire() && !f3_hit ) 722 XSPerfAccumulate("ifu_req_cacheline_0", f3_req_0 ) 723 XSPerfAccumulate("ifu_req_cacheline_1", f3_req_1 ) 724 XSPerfAccumulate("ifu_req_cacheline_0_hit", f3_hit_0 ) 725 XSPerfAccumulate("ifu_req_cacheline_1_hit", f3_hit_1 ) 726 XSPerfAccumulate("frontendFlush", f3_redirect ) 727 XSPerfAccumulate("only_0_hit", f3_only_0_hit && io.toIbuffer.fire() ) 728 XSPerfAccumulate("only_0_miss", f3_only_0_miss && io.toIbuffer.fire() ) 729 XSPerfAccumulate("hit_0_hit_1", f3_hit_0_hit_1 && io.toIbuffer.fire() ) 730 XSPerfAccumulate("hit_0_miss_1", f3_hit_0_miss_1 && io.toIbuffer.fire() ) 731 XSPerfAccumulate("miss_0_hit_1", f3_miss_0_hit_1 && io.toIbuffer.fire() ) 732 XSPerfAccumulate("miss_0_miss_1", f3_miss_0_miss_1 && io.toIbuffer.fire() ) 733 XSPerfAccumulate("cross_line_block", io.toIbuffer.fire() && f3_situation(0) ) 734 XSPerfAccumulate("fall_through_is_cacheline_end", io.toIbuffer.fire() && f3_situation(1) ) 735} 736