xref: /XiangShan/src/main/scala/xiangshan/frontend/IFU.scala (revision 3e52bed1735f5821bebb79dbb9b148cbb019938d)
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