xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala (revision d0de7e4a4bcd4633260dda99dfedc2a5e543b8b4)
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.icache
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import difftest._
23import freechips.rocketchip.tilelink.ClientStates
24import xiangshan._
25import xiangshan.cache.mmu._
26import utils._
27import utility._
28import xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
29import xiangshan.frontend.{FtqICacheInfo, FtqToICacheRequestBundle}
30
31class ICacheMainPipeReq(implicit p: Parameters) extends ICacheBundle
32{
33  val vaddr  = UInt(VAddrBits.W)
34  def vsetIdx = get_idx(vaddr)
35}
36
37class ICacheMainPipeResp(implicit p: Parameters) extends ICacheBundle
38{
39  val vaddr    = UInt(VAddrBits.W)
40  // val registerData = UInt(blockBits.W)
41  // val sramData = UInt(blockBits.W)
42  // val select   = Bool()
43  val data = UInt((blockBits/2).W)
44  val paddr    = UInt(PAddrBits.W)
45  val gpaddr    = UInt(GPAddrBits.W)
46  val tlbExcp  = new Bundle{
47    val pageFault = Bool()
48    val guestPageFault = Bool()
49    val accessFault = Bool()
50    val mmio = Bool()
51  }
52}
53
54class ICacheMainPipeBundle(implicit p: Parameters) extends ICacheBundle
55{
56  val req  = Flipped(Decoupled(new FtqToICacheRequestBundle))
57  val resp = Vec(PortNumber, ValidIO(new ICacheMainPipeResp))
58  val topdownIcacheMiss = Output(Bool())
59  val topdownItlbMiss = Output(Bool())
60}
61
62class ICacheMetaReqBundle(implicit p: Parameters) extends ICacheBundle{
63  val toIMeta       = DecoupledIO(new ICacheReadBundle)
64  val fromIMeta     = Input(new ICacheMetaRespBundle)
65}
66
67class ICacheDataReqBundle(implicit p: Parameters) extends ICacheBundle{
68  val toIData       = DecoupledIO(Vec(partWayNum, new ICacheReadBundle))
69  val fromIData     = Input(new ICacheDataRespBundle)
70}
71
72class ICacheMSHRBundle(implicit p: Parameters) extends ICacheBundle{
73  val toMSHR        = Decoupled(new ICacheMissReq)
74  val fromMSHR      = Flipped(ValidIO(new ICacheMissResp))
75}
76
77class ICachePMPBundle(implicit p: Parameters) extends ICacheBundle{
78  val req  = Valid(new PMPReqBundle())
79  val resp = Input(new PMPRespBundle())
80}
81
82class ICachePerfInfo(implicit p: Parameters) extends ICacheBundle{
83  val only_0_hit     = Bool()
84  val only_0_miss    = Bool()
85  val hit_0_hit_1    = Bool()
86  val hit_0_miss_1   = Bool()
87  val miss_0_hit_1   = Bool()
88  val miss_0_miss_1  = Bool()
89  val hit_0_except_1 = Bool()
90  val miss_0_except_1 = Bool()
91  val except_0       = Bool()
92  val bank_hit       = Vec(2,Bool())
93  val hit            = Bool()
94}
95
96class ICacheMainPipeInterface(implicit p: Parameters) extends ICacheBundle {
97  val hartId = Input(UInt(hartIdLen.W))
98  /*** internal interface ***/
99  val metaArray   = new ICacheMetaReqBundle
100  val dataArray   = new ICacheDataReqBundle
101  /** prefetch io */
102  val IPFBufferRead = Flipped(new IPFBufferRead)
103  val PIQRead       = Flipped(new PIQRead)
104
105  val IPFReplacer         = Flipped(new IPFReplacer)
106  val ICacheMainPipeInfo  = new ICacheMainPipeInfo
107
108  val mshr        = Vec(PortNumber, new ICacheMSHRBundle)
109  val errors      = Output(Vec(PortNumber, new L1CacheErrorInfo))
110  /*** outside interface ***/
111  //val fetch       = Vec(PortNumber, new ICacheMainPipeBundle)
112  /* when ftq.valid is high in T + 1 cycle
113   * the ftq component must be valid in T cycle
114   */
115  val fetch       = new ICacheMainPipeBundle
116  val pmp         = Vec(PortNumber, new ICachePMPBundle)
117  val itlb        = Vec(PortNumber, new TlbRequestIO)
118  val respStall   = Input(Bool())
119  val perfInfo = Output(new ICachePerfInfo)
120
121  val csr_parity_enable = Input(Bool())
122}
123
124class ICacheDB(implicit p: Parameters) extends ICacheBundle {
125  val blk_vaddr   = UInt((VAddrBits - blockOffBits).W)
126  val blk_paddr   = UInt((PAddrBits - blockOffBits).W)
127  val hit         = Bool()
128}
129
130class ICacheMainPipe(implicit p: Parameters) extends ICacheModule
131{
132  val io = IO(new ICacheMainPipeInterface)
133
134  /** Input/Output port */
135  val (fromFtq, toIFU)    = (io.fetch.req,          io.fetch.resp)
136  val (toMeta, metaResp)  = (io.metaArray.toIMeta,  io.metaArray.fromIMeta)
137  val (toData, dataResp)  = (io.dataArray.toIData,  io.dataArray.fromIData)
138  val (toIPF,  fromIPF)   = (io.IPFBufferRead.req,  io.IPFBufferRead.resp)
139  val (toPIQ,  fromPIQ)   = (io.PIQRead.req,        io.PIQRead.resp)
140  val (toMSHR, fromMSHR)  = (io.mshr.map(_.toMSHR), io.mshr.map(_.fromMSHR))
141  val (toITLB, fromITLB)  = (io.itlb.map(_.req),    io.itlb.map(_.resp))
142  val (toPMP,  fromPMP)   = (io.pmp.map(_.req),     io.pmp.map(_.resp))
143
144  val IPFReplacer         = io.IPFReplacer
145  val toIPrefetch         = io.ICacheMainPipeInfo
146
147
148  // Statistics on the frequency distribution of FTQ fire interval
149  val cntFtqFireInterval = RegInit(0.U(32.W))
150  cntFtqFireInterval := Mux(fromFtq.fire, 1.U, cntFtqFireInterval + 1.U)
151  XSPerfHistogram("ftq2icache_fire_" + p(XSCoreParamsKey).HartId.toString,
152                  cntFtqFireInterval, fromFtq.fire,
153                  1, 300, 1, right_strict = true)
154
155  // Ftq RegNext Register
156  val fromFtqReq = fromFtq.bits.pcMemRead
157
158  /** pipeline control signal */
159  val s1_ready, s2_ready = Wire(Bool())
160  val s0_fire,  s1_fire , s2_fire  = Wire(Bool())
161
162  /**
163    ******************************************************************************
164    * ICache Stage 0
165    * - send req to ITLB and wait for tlb miss fixing
166    * - send req to Meta/Data SRAM
167    ******************************************************************************
168    */
169
170  /** s0 control */
171  val s0_valid       = fromFtq.valid
172  val s0_req_vaddr   = (0 until partWayNum + 1).map(i => VecInit(Seq(fromFtqReq(i).startAddr, fromFtqReq(i).nextlineStart)))
173  val s0_req_vsetIdx = (0 until partWayNum + 1).map(i => VecInit(s0_req_vaddr(i).map(get_idx(_))))
174  val s0_only_first  = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && !fromFtqReq(i).crossCacheline)
175  val s0_double_line = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && fromFtqReq(i).crossCacheline)
176
177  val s0_final_valid        = s0_valid
178  val s0_final_vaddr        = s0_req_vaddr.head
179  val s0_final_vsetIdx      = s0_req_vsetIdx.head
180  val s0_final_only_first   = s0_only_first.head
181  val s0_final_double_line  = s0_double_line.head
182
183  /** SRAM request */
184  // 0,1,2,3 -> dataArray(data); 3 -> dataArray(code); 0 -> metaArray; 4 -> itlb
185  val ftq_req_to_data_doubleline  = s0_double_line.init
186  val ftq_req_to_data_vset_idx    = s0_req_vsetIdx.init
187  val ftq_req_to_data_valid       = fromFtq.bits.readValid.init
188
189  val ftq_req_to_meta_doubleline  = s0_double_line.head
190  val ftq_req_to_meta_vset_idx    = s0_req_vsetIdx.head
191  val ftq_req_to_meta_valid       = fromFtq.bits.readValid.head
192
193  val ftq_req_to_itlb_only_first  = s0_only_first.last
194  val ftq_req_to_itlb_doubleline  = s0_double_line.last
195  val ftq_req_to_itlb_vaddr       = s0_req_vaddr.last
196  val ftq_req_to_itlb_vset_idx    = s0_req_vsetIdx.last
197
198  /** Data request */
199  for(i <- 0 until partWayNum) {
200    toData.valid                  := ftq_req_to_data_valid(i)
201    toData.bits(i).isDoubleLine   := ftq_req_to_data_doubleline(i)
202    toData.bits(i).vSetIdx        := ftq_req_to_data_vset_idx(i)
203  }
204
205  /** Meta request */
206  toMeta.valid               := ftq_req_to_meta_valid
207  toMeta.bits.isDoubleLine   := ftq_req_to_meta_doubleline
208  toMeta.bits.vSetIdx        := ftq_req_to_meta_vset_idx
209
210  val toITLB_s0_valid    = VecInit(Seq(s0_valid, s0_valid && ftq_req_to_itlb_doubleline))
211  val toITLB_s0_size     = VecInit(Seq(3.U, 3.U)) // TODO: fix the size
212  val toITLB_s0_vaddr    = ftq_req_to_itlb_vaddr
213  val toITLB_s0_debug_pc = ftq_req_to_itlb_vaddr
214
215  val itlb_can_go    = toITLB(0).ready && toITLB(1).ready
216  val icache_can_go  = toData.ready && toMeta.ready
217  val pipe_can_go    = s1_ready
218  val s0_can_go      = itlb_can_go && icache_can_go && pipe_can_go
219  s0_fire  := s0_valid && s0_can_go
220
221  //TODO: fix GTimer() condition
222  fromFtq.ready := s0_can_go
223
224  /**
225    ******************************************************************************
226    * ICache Stage 1
227    * - get tlb resp data (exceptiong info and physical addresses)
228    * - get Meta/Data SRAM read responses (latched for pipeline stop)
229    * - tag compare/hit check
230    * - check ipf and piq
231    ******************************************************************************
232    */
233
234  /** s1 control */
235  val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = false.B, lastFlush = false.B)
236
237  val s1_req_vaddr   = RegEnable(s0_final_vaddr, s0_fire)
238  val s1_req_vsetIdx = RegEnable(s0_final_vsetIdx, s0_fire)
239  val s1_double_line = RegEnable(s0_final_double_line, s0_fire)
240
241  /** tlb request and response */
242  fromITLB.foreach(_.ready := true.B)
243  val s1_wait_itlb  = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
244
245  (0 until PortNumber).foreach { i =>
246    when(RegNext(s0_fire) && fromITLB(i).bits.miss) {
247      s1_wait_itlb(i) := true.B
248    }.elsewhen(s1_wait_itlb(i) && !fromITLB(i).bits.miss) {
249      s1_wait_itlb(i) := false.B
250    }
251  }
252
253  val s1_need_itlb = Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && fromITLB(0).bits.miss,
254                         (RegNext(s0_fire) || s1_wait_itlb(1)) && fromITLB(1).bits.miss && s1_double_line)
255  val toITLB_s1_valid    = s1_need_itlb
256  val toITLB_s1_size     = VecInit(Seq(3.U, 3.U)) // TODO: fix the size
257  val toITLB_s1_vaddr    = s1_req_vaddr
258  val toITLB_s1_debug_pc = s1_req_vaddr
259
260  // chose tlb req between s0 and s1
261  for (i <- 0 until PortNumber) {
262    toITLB(i).valid         := Mux(s1_need_itlb(i), toITLB_s1_valid(i), toITLB_s0_valid(i))
263    toITLB(i).bits.size     := Mux(s1_need_itlb(i), toITLB_s1_size(i), toITLB_s0_size(i))
264    toITLB(i).bits.vaddr    := Mux(s1_need_itlb(i), toITLB_s1_vaddr(i), toITLB_s0_vaddr(i))
265    toITLB(i).bits.debug.pc := Mux(s1_need_itlb(i), toITLB_s1_debug_pc(i), toITLB_s0_debug_pc(i))
266  }
267  toITLB.map{port =>
268    port.bits.cmd                 := TlbCmd.exec
269    port.bits.memidx              := DontCare
270    port.bits.debug.robIdx        := DontCare
271    port.bits.no_translate        := false.B
272    port.bits.debug.isFirstIssue  := DontCare
273    port.bits.kill                := DontCare
274  }
275  io.itlb.foreach(_.req_kill := false.B)
276
277  /** tlb response latch for pipeline stop */
278  // val tlb_valid_tmp = VecInit((0 until PortNumber).map(i =>
279  //                       (RegNext(s0_fire) || s1_wait_itlb(i)) && !fromITLB(i).bits.miss))
280  val tlb_valid_tmp = VecInit(Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && !fromITLB(0).bits.miss,
281                                  (RegNext(s0_fire) || s1_wait_itlb(1)) && !fromITLB(1).bits.miss && s1_double_line))
282  val tlbRespPAddr  = VecInit((0 until PortNumber).map(i =>
283                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.paddr(0))))
284  val tlbRespGPAddr = VecInit((0 until PortNumber).map(i => ResultHoldBypass(valid = tlb_back(i), data = fromITLB(i).bits.gpaddr(0))))
285  val tlbExcpGPF = VecInit((0 until PortNumber).map(i => ResultHoldBypass(valid = tlb_back(i), data = fromITLB(i).bits.excp(0).gpf.instr) && tlb_need_back(i)))
286  val tlbExcpPF     = VecInit((0 until PortNumber).map(i =>
287                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.excp(0).pf.instr)))
288  val tlbExcpAF     = VecInit((0 until PortNumber).map(i =>
289                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.excp(0).af.instr)))
290  val tlbExcp       = VecInit((0 until PortNumber).map(i => tlbExcpAF(i) || tlbExcpAF(i) || tlbExcpGPF(i)))
291
292  val s1_tlb_valid = VecInit((0 until PortNumber).map(i => ValidHoldBypass(tlb_valid_tmp(i), s1_fire)))
293  val tlbRespAllValid = s1_tlb_valid(0) && (!s1_double_line || s1_double_line && s1_tlb_valid(1))
294
295
296  def numOfStage = 3
297  val itlbMissStage = RegInit(VecInit(Seq.fill(numOfStage - 1)(0.B)))
298  itlbMissStage(0) := !tlbRespAllValid
299  for (i <- 1 until numOfStage - 1) {
300    itlbMissStage(i) := itlbMissStage(i - 1)
301  }
302
303  /** s1 hit check/tag compare */
304  val s1_req_paddr              = tlbRespPAddr
305  val s1_req_gpaddr             = tlbRespGPAddr
306  val s1_req_ptags              = VecInit(s1_req_paddr.map(get_phy_tag(_)))
307
308  val s1_meta_ptags              = ResultHoldBypass(data = metaResp.tags, valid = RegNext(s0_fire))
309  val s1_meta_valids             = ResultHoldBypass(data = metaResp.entryValid, valid = RegNext(s0_fire))
310  val s1_meta_errors             = ResultHoldBypass(data = metaResp.errors, valid = RegNext(s0_fire))
311
312  val s1_data_cacheline          = ResultHoldBypass(data = dataResp.datas, valid = RegNext(s0_fire))
313  val s1_data_errorBits          = ResultHoldBypass(data = dataResp.codes, valid = RegNext(s0_fire))
314
315  val s1_tag_eq_vec        = VecInit((0 until PortNumber).map( p => VecInit((0 until nWays).map( w =>  s1_meta_ptags(p)(w) ===  s1_req_ptags(p)))))
316  val s1_tag_match_vec     = VecInit((0 until PortNumber).map( k => VecInit(s1_tag_eq_vec(k).zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && s1_meta_valids(k)(w)})))
317  val s1_tag_match         = VecInit(s1_tag_match_vec.map(vector => ParallelOR(vector)))
318
319  val s1_port_hit          = VecInit(Seq(s1_tag_match(0) && s1_valid, s1_tag_match(1) && s1_valid && s1_double_line))
320
321  /** choose victim cacheline */
322  val bank_vsetIdx    = VecInit((0 until PortNumber).map( i => Mux(s1_req_vsetIdx(i)(0), s1_req_vsetIdx(1)(highestIdxBit, 1), s1_req_vsetIdx(0)(highestIdxBit, 1))))
323  val replacers       = Seq.fill(PortNumber)(ReplacementPolicy.fromString(cacheParams.replacer,nWays,nSets/PortNumber))
324  val bank_victim_oh  = ResultHoldBypass(data = VecInit(replacers.zipWithIndex.map{case (replacer, i) => UIntToOH(replacer.way(bank_vsetIdx(i)))}), valid = RegNext(s0_fire))
325  val s1_victim_oh    = VecInit((0 until PortNumber).map( i => Mux(s1_req_vsetIdx(i)(0), bank_victim_oh(1), bank_victim_oh(0))))
326
327  when(s1_fire){
328    assert(PopCount(s1_tag_match_vec(0)) <= 1.U && (PopCount(s1_tag_match_vec(1)) <= 1.U || !s1_double_line),
329      "Multiple hit in main pipe, port0:is=%d,ptag=0x%x,vidx=0x%x,vaddr=0x%x port1:is=%d,ptag=0x%x,vidx=0x%x,vaddr=0x%x ",
330      PopCount(s1_tag_match_vec(0)) > 1.U,s1_req_ptags(0), get_idx(s1_req_vaddr(0)), s1_req_vaddr(0),
331      PopCount(s1_tag_match_vec(1)) > 1.U && s1_double_line, s1_req_ptags(1), get_idx(s1_req_vaddr(1)), s1_req_vaddr(1))
332  }
333
334  /** check ipf, get result at the same cycle */
335  (0 until PortNumber).foreach { i =>
336    toIPF(i).valid      := tlb_valid_tmp(i)
337    toIPF(i).bits.paddr := s1_req_paddr(i)
338  }
339  val s1_ipf_hit        = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromIPF(i).ipf_hit))
340  val s1_ipf_hit_latch  = VecInit((0 until PortNumber).map(i => holdReleaseLatch(valid = s1_ipf_hit(i), release = s1_fire, flush = false.B)))
341  val s1_ipf_data       = VecInit((0 until PortNumber).map(i => ResultHoldBypass(data = fromIPF(i).cacheline, valid = s1_ipf_hit(i))))
342
343  /** check in PIQ, if hit, wait until prefetch port hit */
344  (0 until PortNumber).foreach { i =>
345    toPIQ(i).valid      := tlb_valid_tmp(i)
346    toPIQ(i).bits.paddr := s1_req_paddr(i)
347  }
348  val s1_piq_hit        = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromPIQ(i).piq_hit))
349  val s1_piq_hit_latch  = VecInit((0 until PortNumber).map(i => holdReleaseLatch(valid = s1_piq_hit(i), release = s1_fire, flush = false.B)))
350  val wait_piq          = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromPIQ(i).piq_hit && !fromPIQ(i).data_valid))
351  val wait_piq_latch    = VecInit((0 until PortNumber).map(i => holdReleaseLatch(valid = wait_piq(i), release = s1_fire || fromPIQ(i).data_valid, flush = false.B)))
352  val s1_piq_data       = VecInit((0 until PortNumber).map(i => ResultHoldBypass(data = fromPIQ(i).cacheline, valid = (s1_piq_hit(i) || wait_piq_latch(i)) && fromPIQ(i).data_valid)))
353
354  val s1_wait           = (0 until PortNumber).map(i => wait_piq_latch(i) && !fromPIQ(i).data_valid).reduce(_||_)
355
356  val s1_prefetch_hit = VecInit((0 until PortNumber).map(i => s1_ipf_hit_latch(i) || s1_piq_hit_latch(i)))
357  val s1_prefetch_hit_data = VecInit((0 until PortNumber).map(i => Mux(s1_ipf_hit_latch(i), s1_ipf_data(i), s1_piq_data(i))))
358
359  s1_ready := s2_ready && tlbRespAllValid && !s1_wait || !s1_valid
360  s1_fire  := s1_valid && tlbRespAllValid && s2_ready && !s1_wait
361
362  // record cacheline log
363  val isWriteICacheTable = WireInit(Constantin.createRecord("isWriteICacheTable" + p(XSCoreParamsKey).HartId.toString))
364  val ICacheTable = ChiselDB.createTable("ICacheTable" + p(XSCoreParamsKey).HartId.toString, new ICacheDB)
365
366  val ICacheDumpData_req0 = Wire(new ICacheDB)
367  ICacheDumpData_req0.blk_paddr := getBlkAddr(s1_req_paddr(0))
368  ICacheDumpData_req0.blk_vaddr := getBlkAddr(s1_req_vaddr(0))
369  ICacheDumpData_req0.hit       := s1_port_hit(0) || s1_prefetch_hit(0)
370  ICacheTable.log(
371    data = ICacheDumpData_req0,
372    en = isWriteICacheTable.orR && s1_fire,
373    clock = clock,
374    reset = reset
375  )
376
377  val ICacheDumpData_req1 = Wire(new ICacheDB)
378  ICacheDumpData_req1.blk_paddr := getBlkAddr(s1_req_paddr(1))
379  ICacheDumpData_req1.blk_vaddr := getBlkAddr(s1_req_vaddr(1))
380  ICacheDumpData_req1.hit       := s1_port_hit(1) || s1_prefetch_hit(1)
381  ICacheTable.log(
382    data = ICacheDumpData_req1,
383    en = isWriteICacheTable.orR && s1_fire && s1_double_line,
384    clock = clock,
385    reset = reset
386  )
387
388  /** <PERF> replace victim way number */
389
390  (0 until nWays).map{ w =>
391    XSPerfAccumulate("line_0_hit_way_" + Integer.toString(w, 10),  s1_fire && s1_port_hit(0) && OHToUInt(s1_tag_match_vec(0))  === w.U)
392  }
393
394  (0 until nWays).map{ w =>
395    XSPerfAccumulate("line_0_victim_way_" + Integer.toString(w, 10),  s1_fire && !s1_port_hit(0) && OHToUInt(s1_victim_oh(0))  === w.U)
396  }
397
398  (0 until nWays).map{ w =>
399    XSPerfAccumulate("line_1_hit_way_" + Integer.toString(w, 10),  s1_fire && s1_double_line && s1_port_hit(1) && OHToUInt(s1_tag_match_vec(1))  === w.U)
400  }
401
402  (0 until nWays).map{ w =>
403    XSPerfAccumulate("line_1_victim_way_" + Integer.toString(w, 10),  s1_fire && s1_double_line && !s1_port_hit(1) && OHToUInt(s1_victim_oh(1))  === w.U)
404  }
405
406  XSPerfAccumulate("mainPipe_stage1_block_by_piq_cycles", s1_valid && s1_wait)
407
408  /**
409    ******************************************************************************
410    * ICache Stage 2
411    * - send request to MSHR if ICache miss
412    * - generate secondary miss status/data registers
413    * - response to IFU
414    ******************************************************************************
415    */
416
417  /** s2 control */
418  val s2_fetch_finish = Wire(Bool())
419
420  val s2_valid          = generatePipeControl(lastFire = s1_fire, thisFire = s2_fire, thisFlush = false.B, lastFlush = false.B)
421
422  s2_ready      := (s2_valid && s2_fetch_finish && !io.respStall) || !s2_valid
423  s2_fire       := s2_valid && s2_fetch_finish && !io.respStall
424
425  /** s2 data */
426  // val mmio = fromPMP.map(port => port.mmio) // TODO: handle it
427  val (s2_req_paddr , s2_req_vaddr) = (RegEnable(s1_req_paddr, s1_fire), RegEnable(s1_req_vaddr, s1_fire))
428  val s2_req_gpaddr   = RegEnable(s1_req_gpaddr, s1_fire)
429  val s2_req_vsetIdx          = RegEnable(s1_req_vsetIdx,       s1_fire)
430  val s2_req_ptags            = RegEnable(s1_req_ptags,         s1_fire)
431  val s2_double_line          = RegEnable(s1_double_line,       s1_fire)
432  val s2_port_hit             = RegEnable(s1_port_hit,          s1_fire)
433  val s2_waymask              = RegEnable(s1_victim_oh,         s1_fire)
434  val s2_tag_match_vec        = RegEnable(s1_tag_match_vec,     s1_fire)
435
436  val s2_meta_errors          = RegEnable(s1_meta_errors,    s1_fire)
437  val s2_data_errorBits       = RegEnable(s1_data_errorBits, s1_fire)
438  val s2_data_cacheline       = RegEnable(s1_data_cacheline, s1_fire)
439
440  /** send req info of s1 and s2 to IPrefetchPipe for filter request */
441  toIPrefetch.s1Info(0).paddr  := s1_req_paddr(0)
442  toIPrefetch.s1Info(0).valid  := s1_valid
443  toIPrefetch.s1Info(1).paddr  := s1_req_paddr(1)
444  toIPrefetch.s1Info(1).valid  := s1_valid && s1_double_line
445  toIPrefetch.s2Info(0).paddr  := s2_req_paddr(0)
446  toIPrefetch.s2Info(0).valid  := s2_valid
447  toIPrefetch.s2Info(1).paddr  := s2_req_paddr(1)
448  toIPrefetch.s2Info(1).valid  := s2_valid && s2_double_line
449
450  assert(RegNext(!s2_valid || s2_req_paddr(0)(11,0) === s2_req_vaddr(0)(11,0), true.B))
451
452  /**
453    ******************************************************************************
454    * tlb exception and pmp logic
455    ******************************************************************************
456    */
457  // short delay exception signal
458  val s2_except_tlb_pf  = RegEnable(tlbExcpPF, s1_fire)
459  val s2_except_tlb_af  = RegEnable(tlbExcpAF, s1_fire)
460  val s2_except_tlb     = VecInit(Seq(s2_except_tlb_pf(0) || s2_except_tlb_af(0), s2_double_line && (s2_except_tlb_pf(1) || s2_except_tlb_af(1))))
461  val s2_has_except_tlb = s2_valid && s2_except_tlb.reduce(_||_)
462  // long delay exception signal
463  // exception information and mmio
464  val pmpExcpAF = VecInit(Seq(fromPMP(0).instr, fromPMP(1).instr && s2_double_line))
465  val s2_except_pmp_af = DataHoldBypass(pmpExcpAF, RegNext(s1_fire))
466  val s2_mmio = s2_valid && DataHoldBypass(fromPMP(0).mmio && !s2_except_tlb(0) && !s2_except_pmp_af(0), RegNext(s1_fire)).asBool
467  // pmp port
468  toPMP.zipWithIndex.map { case (p, i) =>
469    p.valid     := s2_valid
470    p.bits.addr := s2_req_paddr(i)
471    p.bits.size := 3.U // TODO
472    p.bits.cmd  := TlbCmd.exec
473  }
474
475  /**
476    ******************************************************************************
477    * look last miss data
478    ******************************************************************************
479    */
480  class MissSlot(implicit p: Parameters) extends ICacheBundle {
481    val paddr     = RegInit(0.U(PAddrBits.W))
482    val vSetIdx   = RegInit(0.U(idxBits.W))
483    val waymask   = RegInit(0.U(nWays.W))
484    val data      = RegInit(0.U(blockBits.W))
485    val corrupt   = RegInit(false.B)
486    val finish    = RegInit(true.B)
487    val valid     = RegInit(false.B)
488    def data_vec  = data.asTypeOf(Vec(2, UInt((blockBits/2).W)))
489    def pTag      = get_phy_tag(paddr)
490  }
491  val missSlot    = Seq.fill(2)(new MissSlot)
492
493  // whether hit in last miss req
494  def getMissSituat(missNum : Int, slotNum : Int ) :Bool =  {
495    (missSlot(slotNum).vSetIdx === s1_req_vsetIdx(missNum)) &&
496    (missSlot(slotNum).pTag === s1_req_ptags(missNum)) &&
497    !missSlot(slotNum).corrupt && missSlot(slotNum).finish &&
498    missSlot(slotNum).valid
499  }
500
501  // s2_hit_slot(0)(1): port 0 hit slot 1
502  // Use the signal of S1 to make a judgment for timing, the value of missSlot has benn set when s1 fire
503  val s1_hit_slot_vec = VecInit((0 until PortNumber).map(port => VecInit((0 until PortNumber).map(getMissSituat(port, _)))))
504  val s2_hit_slot_vec = RegEnable(s1_hit_slot_vec, s1_fire)
505
506  // select one from two missSlots to handle miss for every port
507  // slot(0) hit  && slot(1) hit : don't case
508  // slot(0) hit  && slot(1) miss: (a) missed port(0) -> slot(1); (b) missed port(1) -> slot(1)
509  // slot(0) miss && slot(1) hit : (a) missed port(0) -> slot(0); (b) missed port(1) -> slot(0)
510  // slot(0) miss && slot(1) miss: missed port(0) -> slot(0)  missed port(1) -> slot(1)
511  val s1_curr_slot_id = Wire(Vec(2, Bool()))
512  s1_curr_slot_id(0) := s1_hit_slot_vec(0)(0) || s1_hit_slot_vec(1)(0)
513  s1_curr_slot_id(1) := !(s1_hit_slot_vec(0)(1) || s1_hit_slot_vec(1)(1))
514  val s2_curr_slot_id = RegEnable(s1_curr_slot_id, s1_fire)
515
516  /**
517    ******************************************************************************
518    * miss handle
519    ******************************************************************************
520    */
521  val s2_hit_slot = VecInit(s2_hit_slot_vec.map(_.asUInt.orR))
522  val s2_fixed_port_hit = VecInit((0 until PortNumber).map(port => s2_port_hit(port) || s2_hit_slot(port)))
523
524  // only handle port0 miss when port1 have tlb except or pmp except
525  val s2_port_miss = Wire(Vec(PortNumber, Bool()))
526
527  s2_port_miss(0) := !s2_fixed_port_hit(0) && !s2_except_tlb(0) && !s2_except_pmp_af(0) && !s2_mmio
528  s2_port_miss(1) := !s2_fixed_port_hit(1) && s2_double_line && !s2_except_tlb(0) && !s2_except_tlb(1) &&
529                     !s2_except_pmp_af(0) && !s2_except_pmp_af(1) && !s2_mmio
530
531  (0 until PortNumber).map{ i =>
532    when(s2_port_miss(i) && RegNext(s1_fire)) {
533      when(s2_curr_slot_id(i)) {
534        missSlot(1).vSetIdx := s2_req_vsetIdx(i)
535        missSlot(1).paddr   := s2_req_paddr(i)
536        missSlot(1).waymask := s2_waymask(i)
537        missSlot(1).finish  := false.B
538        missSlot(1).valid   := true.B
539      }.otherwise {
540        missSlot(0).vSetIdx := s2_req_vsetIdx(i)
541        missSlot(0).paddr   := s2_req_paddr(i)
542        missSlot(0).waymask := s2_waymask(i)
543        missSlot(0).finish  := false.B
544        missSlot(0).valid   := true.B
545      }
546    }
547  }
548
549  // which missSlot need to be issued
550  val s2_missSlot_issue = Wire(Vec(2, Bool()))
551  s2_missSlot_issue(0) := (s2_port_miss(0) && !s2_curr_slot_id(0)) || (s2_port_miss(1) && !s2_curr_slot_id(1))
552  s2_missSlot_issue(1) := (s2_port_miss(0) && s2_curr_slot_id(0)) || (s2_port_miss(1) && s2_curr_slot_id(1))
553
554  // state machine
555  val m_idle ::m_send_req :: m_wait_resp :: Nil = Enum(3)
556  val missStateQueue = RegInit(VecInit(Seq.fill(2)(m_idle)))
557
558  (0 until PortNumber).map{ i =>
559    switch(missStateQueue(i)){
560      is(m_idle) {
561        missStateQueue(i) := Mux(RegNext(s1_fire) && s2_missSlot_issue(i), m_send_req, m_idle)
562      }
563      is(m_send_req) {
564        missStateQueue(i) := Mux(toMSHR(i).fire, m_wait_resp, m_send_req)
565      }
566      is(m_wait_resp) {
567        missStateQueue(i) := Mux(fromMSHR(i).fire, m_idle, m_wait_resp)
568      }
569    }
570  }
571
572  // send req to MSHR
573  (0 until PortNumber).map{i =>
574    toMSHR(i).valid         := missStateQueue(i) === m_send_req
575    toMSHR(i).bits.paddr    := missSlot(i).paddr
576    toMSHR(i).bits.vSetIdx  := missSlot(i).vSetIdx
577    toMSHR(i).bits.waymask  := missSlot(i).waymask
578  }
579
580  // recrive resp from MSHR to update missSlot
581  (0 until PortNumber).map{ i =>
582    when((missStateQueue(i) === m_wait_resp) && fromMSHR(i).fire) {
583      missSlot(i).finish  := true.B
584      missSlot(i).data    := fromMSHR(i).bits.data
585      missSlot(i).corrupt := fromMSHR(i).bits.corrupt
586    }
587  }
588
589  // handle miss finish
590  s2_fetch_finish := (!s2_port_miss(0) && !s2_port_miss(1)) || (missSlot(0).finish && missSlot(1).finish && !RegNext(s1_fire))
591
592  /**
593    ******************************************************************************
594    * select data from hitted sram data, last missSlot and current missSlot
595    ******************************************************************************
596    */
597  val s2_hit_datas = Wire(Vec(2, UInt((blockBits/2).W)))
598  s2_hit_datas(0) := Mux1H(s2_tag_match_vec(0).asUInt, s2_data_cacheline(0))
599  s2_hit_datas(1) := Mux1H(Mux(s2_double_line, s2_tag_match_vec(1).asUInt, s2_tag_match_vec(0).asUInt), s2_data_cacheline(1))
600
601  // get cacheline from last slot
602  val s2_last_slot_cacheline = (0 until PortNumber).map(port => Mux1H(s2_hit_slot_vec(port).asUInt, missSlot.map(_.data_vec)))
603  // get cacheline from curr slot
604  val s2_curr_slot_cacheline = (0 until PortNumber).map(port => Mux(s2_curr_slot_id(port), missSlot(1).data_vec, missSlot(0).data_vec))
605  val s2_slot_cacheline = (0 until PortNumber).map(port => Mux(s2_hit_slot(port), s2_last_slot_cacheline(port), s2_curr_slot_cacheline(port)))
606  val s2_slot_data = Wire(Vec(PortNumber, UInt((blockBits/2).W)))
607  s2_slot_data(0) := Mux(s2_double_line, s2_slot_cacheline(0)(1), s2_slot_cacheline(0)(0))
608  s2_slot_data(1) := Mux(s2_double_line, s2_slot_cacheline(1)(0), s2_slot_cacheline(0)(1))
609
610  val s2_fetch_data = Wire(Vec(2, UInt((blockBits/2).W)))
611  s2_fetch_data(0) := Mux(s2_port_hit(0), s2_hit_datas(0), s2_slot_data(0))
612  s2_fetch_data(1) := Mux(s2_port_hit(1) || (s2_port_hit(0) && !s2_double_line), s2_hit_datas(1), s2_slot_data(1))
613
614  val s2_corrupt = (0 until PortNumber).map(port => s2_port_miss(port) && Mux(s2_curr_slot_id(port), missSlot(1).corrupt, missSlot(0).corrupt))
615
616  /**
617    ******************************************************************************
618    * IFU data resp
619    ******************************************************************************
620    */
621  (0 until PortNumber).map{ i =>
622    if(i ==0) toIFU(i).valid          := s2_fire
623      else   toIFU(i).valid           := s2_fire && s2_double_line
624    toIFU(i).bits.paddr               := s2_req_paddr(i)
625    toIFU(i).bits.vaddr               := s2_req_vaddr(i)
626    toIFU(i).bits.data                := s2_fetch_data(i)
627    toIFU(i).bits.tlbExcp.pageFault   := s2_except_tlb_pf(i)
628    toIFU(i).bits.tlbExcp.accessFault := s2_except_tlb_af(i) || s2_corrupt(i) || s2_except_pmp_af(i)
629    toIFU(i).bits.tlbExcp.mmio        := s2_mmio
630  }
631
632  /**
633    ******************************************************************************
634    * error resp: MSHR error
635    ******************************************************************************
636    */
637  // data/meta parity error
638  val s2_data_errors = Wire(Vec(PortNumber,Vec(nWays, Bool())))
639  (0 until PortNumber).map{ i =>
640    val read_datas = s2_data_cacheline(i).asTypeOf(Vec(nWays,Vec(dataCodeUnitNum, UInt(dataCodeUnit.W))))
641    val read_codes = s2_data_errorBits(i).asTypeOf(Vec(nWays,Vec(dataCodeUnitNum, UInt(dataCodeBits.W))))
642    val data_full_wayBits = VecInit((0 until nWays).map( w =>
643                                  VecInit((0 until dataCodeUnitNum).map( u =>
644                                        Cat(read_codes(w)(u), read_datas(w)(u))))))
645    val data_error_wayBits = VecInit((0 until nWays).map( w =>
646                                  VecInit((0 until dataCodeUnitNum).map( u =>
647                                       cacheParams.dataCode.decode(data_full_wayBits(w)(u)).error))))
648    // register for timing
649    if(i == 0){
650      (0 until nWays).map{ w =>
651        s2_data_errors(i)(w) := RegNext(RegNext(s1_fire)) && RegNext(data_error_wayBits(w)).reduce(_||_)
652      }
653    } else {
654      (0 until nWays).map{ w =>
655        s2_data_errors(i)(w) := RegNext(RegNext(s1_fire)) && RegNext(RegNext(s1_double_line)) && RegNext(data_error_wayBits(w)).reduce(_||_)
656      }
657    }
658  }
659
660  val s2_parity_meta_error  = VecInit((0 until PortNumber).map(i => s2_meta_errors(i).reduce(_||_) && io.csr_parity_enable))
661  val s2_parity_data_error  = VecInit((0 until PortNumber).map(i => s2_data_errors(i).reduce(_||_) && io.csr_parity_enable))
662  val s2_parity_error       = VecInit((0 until PortNumber).map(i => RegNext(s2_parity_meta_error(i)) || s2_parity_data_error(i)))
663
664  for(i <- 0 until PortNumber){
665    io.errors(i).valid            := RegNext(s2_parity_error(i) && RegNext(RegNext(s1_fire)))
666    io.errors(i).report_to_beu    := RegNext(s2_parity_error(i) && RegNext(RegNext(s1_fire)))
667    io.errors(i).paddr            := RegNext(RegNext(s2_req_paddr(i)))
668    io.errors(i).source           := DontCare
669    io.errors(i).source.tag       := RegNext(RegNext(s2_parity_meta_error(i)))
670    io.errors(i).source.data      := RegNext(s2_parity_data_error(i))
671    io.errors(i).source.l2        := false.B
672    io.errors(i).opType           := DontCare
673    io.errors(i).opType.fetch     := true.B
674  }
675
676  // MSHR error
677  (0 until PortNumber).map{ i =>
678    when(RegNext(s2_fire && s2_corrupt(i))){
679      io.errors(i).valid            := true.B
680      io.errors(i).report_to_beu    := false.B // l2 should have report that to bus error unit, no need to do it again
681      io.errors(i).paddr            := RegNext(s2_req_paddr(i))
682      io.errors(i).source.tag       := false.B
683      io.errors(i).source.data      := false.B
684      io.errors(i).source.l2        := true.B
685    }
686  }
687
688  /**
689    ******************************************************************************
690    * s2 prefetch port
691    ******************************************************************************
692    */
693  (0 until PortNumber).foreach{ i =>
694    // TODO: consider corrupt of missSlot
695    toIPrefetch.missSlot(i).valid   := missSlot(i).valid
696    toIPrefetch.missSlot(i).vSetIdx := missSlot(i).vSetIdx
697    toIPrefetch.missSlot(i).ptag    := missSlot(i).pTag
698  }
699
700  /**
701    ******************************************************************************
702    * update replacement status register
703    ******************************************************************************
704    */
705  /** replacement status register */
706  val port_touch_sets = Seq.fill(PortNumber)(Wire(Vec(2, UInt(log2Ceil(nSets/2).W))))
707  val port_touch_ways = Seq.fill(PortNumber)(Wire(Vec(2, Valid(UInt(log2Ceil(nWays).W)))))
708  (port_touch_ways zip port_touch_sets).zipWithIndex.map{ case((t_w,t_s), i) =>
709    /** update replacement status register: 0 is hit access/ 1 is miss access */
710    t_s(0)         := s2_req_vsetIdx(i)(highestIdxBit, 1)
711    // hit in slot will be ignored, which generate a repeated access
712    t_w(0).valid   := s2_valid && s2_port_hit(i)
713    t_w(0).bits    := OHToUInt(s2_tag_match_vec(i))
714
715    t_s(1)         := s2_req_vsetIdx(i)(highestIdxBit, 1)
716    t_w(1).valid   := s2_valid && s2_port_miss(i)
717    t_w(1).bits    := OHToUInt(s2_waymask(i))
718  }
719
720  val touch_ways = VecInit((0 until PortNumber).map( i => Mux(s2_req_vsetIdx(i)(0), port_touch_ways(1), port_touch_ways(0))))
721  val touch_sets = VecInit((0 until PortNumber).map( i => Mux(s2_req_vsetIdx(i)(0), port_touch_sets(1), port_touch_sets(0))))
722  ((replacers zip touch_sets) zip touch_ways).map{case ((r, s),w) => r.access(s,w)}
723  // TODO: need choose one replacer according to the bankid
724  IPFReplacer.waymask := UIntToOH(replacers(0).way(IPFReplacer.vsetIdx))
725
726  /**
727    ******************************************************************************
728    * performance info. TODO: need to simplify the logic
729    ***********************************************************s*******************
730    */
731  io.fetch.topdownIcacheMiss := s2_port_miss(0) || s2_port_miss(1)
732  io.fetch.topdownItlbMiss := itlbMissStage(0)
733
734  io.perfInfo.only_0_hit      :=  s2_fixed_port_hit(0) && !s2_double_line
735  io.perfInfo.only_0_miss     := !s2_fixed_port_hit(0) && !s2_double_line
736  io.perfInfo.hit_0_hit_1     :=  s2_fixed_port_hit(0) &&  s2_fixed_port_hit(1) && s2_double_line
737  io.perfInfo.hit_0_miss_1    :=  s2_fixed_port_hit(0) && !s2_fixed_port_hit(1) && s2_double_line
738  io.perfInfo.miss_0_hit_1    := !s2_fixed_port_hit(0) &&  s2_fixed_port_hit(1) && s2_double_line
739  io.perfInfo.miss_0_miss_1   := !s2_fixed_port_hit(0) && !s2_fixed_port_hit(1) && s2_double_line
740  io.perfInfo.hit_0_except_1  :=  s2_fixed_port_hit(0) && (s2_except_tlb(1) || s2_except_pmp_af(1)) && s2_double_line
741  io.perfInfo.miss_0_except_1 := !s2_fixed_port_hit(0) && (s2_except_tlb(1) || s2_except_pmp_af(1)) && s2_double_line
742  io.perfInfo.bank_hit(0)     :=  s2_fixed_port_hit(0)
743  io.perfInfo.bank_hit(1)     :=  s2_fixed_port_hit(1) && s2_double_line
744  io.perfInfo.except_0        := s2_except_tlb(0) || s2_except_pmp_af(0)
745  io.perfInfo.hit             := !s2_port_miss(0) && !s2_port_miss(1)
746
747  /** <PERF> fetch bubble generated by icache miss*/
748  XSPerfAccumulate("icache_bubble_s2_miss", s2_valid && !s2_fetch_finish )
749  XSPerfAccumulate("icache_bubble_s0_tlb_miss", s1_valid && !tlbRespAllValid)
750
751  /**
752    ******************************************************************************
753    * difftest refill check
754    ******************************************************************************
755    */
756  if (env.EnableDifftest) {
757    val discards = (0 until PortNumber).map { i =>
758      val discard = toIFU(i).bits.tlbExcp.pageFault || toIFU(i).bits.tlbExcp.accessFault || toIFU(i).bits.tlbExcp.mmio
759      discard
760    }
761    (0 until PortNumber).map { i =>
762      val diffMainPipeOut = DifftestModule(new DiffRefillEvent, dontCare = true)
763      diffMainPipeOut.coreid := io.hartId
764      diffMainPipeOut.index := (4 + i).U
765      if (i == 0) {
766        diffMainPipeOut.valid := s2_fire && !discards(0)
767        diffMainPipeOut.addr  := s2_req_paddr(0)
768      } else {
769        diffMainPipeOut.valid := s2_fire && !discards(0) && (!s2_double_line || (s2_double_line && !discards(1)))
770        diffMainPipeOut.addr  := s2_req_paddr(0) + (blockBits/2).U
771      }
772      diffMainPipeOut.data := Cat(0.U((blockBits/2).W), toIFU(i).bits.data).asTypeOf(diffMainPipeOut.data)
773      // idtfr: 0 -> data from icache 1 -> reversedData 2 -> data from missUnit
774      diffMainPipeOut.idtfr := Mux(s2_port_hit(i), 0.U, Mux(s2_fixed_port_hit(i), 1.U, 2.U))
775      diffMainPipeOut
776    }
777  }
778}
779