xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMainPipe.scala (revision b436d3b66611ea0d1fbd4eb28e3b26c0830ce2ac)
11d8f4dcbSJay/***************************************************************************************
21d8f4dcbSJay* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
31d8f4dcbSJay* Copyright (c) 2020-2021 Peng Cheng Laboratory
41d8f4dcbSJay*
51d8f4dcbSJay* XiangShan is licensed under Mulan PSL v2.
61d8f4dcbSJay* You can use this software according to the terms and conditions of the Mulan PSL v2.
71d8f4dcbSJay* You may obtain a copy of Mulan PSL v2 at:
81d8f4dcbSJay*          http://license.coscl.org.cn/MulanPSL2
91d8f4dcbSJay*
101d8f4dcbSJay* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
111d8f4dcbSJay* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
121d8f4dcbSJay* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
131d8f4dcbSJay*
141d8f4dcbSJay* See the Mulan PSL v2 for more details.
151d8f4dcbSJay***************************************************************************************/
161d8f4dcbSJay
171d8f4dcbSJaypackage xiangshan.frontend.icache
181d8f4dcbSJay
198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
201d8f4dcbSJayimport chisel3._
211d8f4dcbSJayimport chisel3.util._
227d45a146SYinan Xuimport difftest._
231d8f4dcbSJayimport freechips.rocketchip.tilelink.ClientStates
241d8f4dcbSJayimport xiangshan._
251d8f4dcbSJayimport xiangshan.cache.mmu._
261d8f4dcbSJayimport utils._
273c02ee8fSwakafaimport utility._
281d8f4dcbSJayimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle}
29f22cf846SJeniusimport xiangshan.frontend.{FtqICacheInfo, FtqToICacheRequestBundle}
301d8f4dcbSJay
311d8f4dcbSJayclass ICacheMainPipeReq(implicit p: Parameters) extends ICacheBundle
321d8f4dcbSJay{
331d8f4dcbSJay  val vaddr  = UInt(VAddrBits.W)
341d8f4dcbSJay  def vsetIdx = get_idx(vaddr)
351d8f4dcbSJay}
361d8f4dcbSJay
371d8f4dcbSJayclass ICacheMainPipeResp(implicit p: Parameters) extends ICacheBundle
381d8f4dcbSJay{
391d8f4dcbSJay  val vaddr    = UInt(VAddrBits.W)
40a61a35e0Sssszwic  // val registerData = UInt(blockBits.W)
41a61a35e0Sssszwic  // val sramData = UInt(blockBits.W)
42a61a35e0Sssszwic  // val select   = Bool()
43a61a35e0Sssszwic  val data = UInt((blockBits/2).W)
441d8f4dcbSJay  val paddr    = UInt(PAddrBits.W)
45d0de7e4aSpeixiaokun  val gpaddr    = UInt(GPAddrBits.W)
461d8f4dcbSJay  val tlbExcp  = new Bundle{
471d8f4dcbSJay    val pageFault = Bool()
48d0de7e4aSpeixiaokun    val guestPageFault = Bool()
491d8f4dcbSJay    val accessFault = Bool()
501d8f4dcbSJay    val mmio = Bool()
511d8f4dcbSJay  }
521d8f4dcbSJay}
531d8f4dcbSJay
541d8f4dcbSJayclass ICacheMainPipeBundle(implicit p: Parameters) extends ICacheBundle
551d8f4dcbSJay{
56c5c5edaeSJenius  val req  = Flipped(Decoupled(new FtqToICacheRequestBundle))
57c5c5edaeSJenius  val resp = Vec(PortNumber, ValidIO(new ICacheMainPipeResp))
58d2b20d1aSTang Haojin  val topdownIcacheMiss = Output(Bool())
59d2b20d1aSTang Haojin  val topdownItlbMiss = Output(Bool())
601d8f4dcbSJay}
611d8f4dcbSJay
621d8f4dcbSJayclass ICacheMetaReqBundle(implicit p: Parameters) extends ICacheBundle{
63afed18b5SJenius  val toIMeta       = DecoupledIO(new ICacheReadBundle)
641d8f4dcbSJay  val fromIMeta     = Input(new ICacheMetaRespBundle)
651d8f4dcbSJay}
661d8f4dcbSJay
671d8f4dcbSJayclass ICacheDataReqBundle(implicit p: Parameters) extends ICacheBundle{
682da4ac8cSJenius  val toIData       = DecoupledIO(Vec(partWayNum, new ICacheReadBundle))
691d8f4dcbSJay  val fromIData     = Input(new ICacheDataRespBundle)
701d8f4dcbSJay}
711d8f4dcbSJay
721d8f4dcbSJayclass ICacheMSHRBundle(implicit p: Parameters) extends ICacheBundle{
731d8f4dcbSJay  val toMSHR        = Decoupled(new ICacheMissReq)
741d8f4dcbSJay  val fromMSHR      = Flipped(ValidIO(new ICacheMissResp))
751d8f4dcbSJay}
761d8f4dcbSJay
771d8f4dcbSJayclass ICachePMPBundle(implicit p: Parameters) extends ICacheBundle{
781d8f4dcbSJay  val req  = Valid(new PMPReqBundle())
791d8f4dcbSJay  val resp = Input(new PMPRespBundle())
801d8f4dcbSJay}
811d8f4dcbSJay
821d8f4dcbSJayclass ICachePerfInfo(implicit p: Parameters) extends ICacheBundle{
831d8f4dcbSJay  val only_0_hit     = Bool()
841d8f4dcbSJay  val only_0_miss    = Bool()
851d8f4dcbSJay  val hit_0_hit_1    = Bool()
861d8f4dcbSJay  val hit_0_miss_1   = Bool()
871d8f4dcbSJay  val miss_0_hit_1   = Bool()
881d8f4dcbSJay  val miss_0_miss_1  = Bool()
89a108d429SJay  val hit_0_except_1 = Bool()
90a108d429SJay  val miss_0_except_1 = Bool()
91a108d429SJay  val except_0       = Bool()
921d8f4dcbSJay  val bank_hit       = Vec(2,Bool())
931d8f4dcbSJay  val hit            = Bool()
941d8f4dcbSJay}
951d8f4dcbSJay
961d8f4dcbSJayclass ICacheMainPipeInterface(implicit p: Parameters) extends ICacheBundle {
97f57f7f2aSYangyu Chen  val hartId = Input(UInt(hartIdLen.W))
982a3050c2SJay  /*** internal interface ***/
991d8f4dcbSJay  val metaArray   = new ICacheMetaReqBundle
1001d8f4dcbSJay  val dataArray   = new ICacheDataReqBundle
101b1ded4e8Sguohongyu  /** prefetch io */
102cb6e5d3cSssszwic  val IPFBufferRead = Flipped(new IPFBufferRead)
103cb6e5d3cSssszwic  val PIQRead       = Flipped(new PIQRead)
104cb6e5d3cSssszwic
105cb6e5d3cSssszwic  val IPFReplacer         = Flipped(new IPFReplacer)
10658c354d0Sssszwic  val ICacheMainPipeInfo  = new ICacheMainPipeInfo
107b1ded4e8Sguohongyu
1081d8f4dcbSJay  val mshr        = Vec(PortNumber, new ICacheMSHRBundle)
10958dbdfc2SJay  val errors      = Output(Vec(PortNumber, new L1CacheErrorInfo))
1102a3050c2SJay  /*** outside interface ***/
111c5c5edaeSJenius  //val fetch       = Vec(PortNumber, new ICacheMainPipeBundle)
112c5c5edaeSJenius  /* when ftq.valid is high in T + 1 cycle
113c5c5edaeSJenius   * the ftq component must be valid in T cycle
114c5c5edaeSJenius   */
115c5c5edaeSJenius  val fetch       = new ICacheMainPipeBundle
1161d8f4dcbSJay  val pmp         = Vec(PortNumber, new ICachePMPBundle)
117f1fe8698SLemover  val itlb        = Vec(PortNumber, new TlbRequestIO)
1181d8f4dcbSJay  val respStall   = Input(Bool())
1191d8f4dcbSJay  val perfInfo = Output(new ICachePerfInfo)
12058dbdfc2SJay
121ecccf78fSJay  val csr_parity_enable = Input(Bool())
1221d8f4dcbSJay}
1231d8f4dcbSJay
124f9c51548Sssszwicclass ICacheDB(implicit p: Parameters) extends ICacheBundle {
125f9c51548Sssszwic  val blk_vaddr   = UInt((VAddrBits - blockOffBits).W)
126f9c51548Sssszwic  val blk_paddr   = UInt((PAddrBits - blockOffBits).W)
127f9c51548Sssszwic  val hit         = Bool()
128f9c51548Sssszwic}
129f9c51548Sssszwic
1301d8f4dcbSJayclass ICacheMainPipe(implicit p: Parameters) extends ICacheModule
1311d8f4dcbSJay{
1321d8f4dcbSJay  val io = IO(new ICacheMainPipeInterface)
1331d8f4dcbSJay
13458dbdfc2SJay  /** Input/Output port */
135c5c5edaeSJenius  val (fromFtq, toIFU)    = (io.fetch.req,          io.fetch.resp)
1362a3050c2SJay  val (toMeta, metaResp)  = (io.metaArray.toIMeta,  io.metaArray.fromIMeta)
1372a3050c2SJay  val (toData, dataResp)  = (io.dataArray.toIData,  io.dataArray.fromIData)
138cb6e5d3cSssszwic  val (toIPF,  fromIPF)   = (io.IPFBufferRead.req,  io.IPFBufferRead.resp)
139cb6e5d3cSssszwic  val (toPIQ,  fromPIQ)   = (io.PIQRead.req,        io.PIQRead.resp)
1401d8f4dcbSJay  val (toMSHR, fromMSHR)  = (io.mshr.map(_.toMSHR), io.mshr.map(_.fromMSHR))
1411d8f4dcbSJay  val (toITLB, fromITLB)  = (io.itlb.map(_.req),    io.itlb.map(_.resp))
1421d8f4dcbSJay  val (toPMP,  fromPMP)   = (io.pmp.map(_.req),     io.pmp.map(_.resp))
143cb6e5d3cSssszwic
144cb6e5d3cSssszwic  val IPFReplacer         = io.IPFReplacer
14558c354d0Sssszwic  val toIPrefetch         = io.ICacheMainPipeInfo
14658c354d0Sssszwic
14758c354d0Sssszwic
14858c354d0Sssszwic  // Statistics on the frequency distribution of FTQ fire interval
14958c354d0Sssszwic  val cntFtqFireInterval = RegInit(0.U(32.W))
15058c354d0Sssszwic  cntFtqFireInterval := Mux(fromFtq.fire, 1.U, cntFtqFireInterval + 1.U)
15158c354d0Sssszwic  XSPerfHistogram("ftq2icache_fire_" + p(XSCoreParamsKey).HartId.toString,
15258c354d0Sssszwic                  cntFtqFireInterval, fromFtq.fire,
15358c354d0Sssszwic                  1, 300, 1, right_strict = true)
154b1ded4e8Sguohongyu
155c5c5edaeSJenius  // Ftq RegNext Register
156b004fa13SJenius  val fromFtqReq = fromFtq.bits.pcMemRead
157c5c5edaeSJenius
15858dbdfc2SJay  /** pipeline control signal */
159f1fe8698SLemover  val s1_ready, s2_ready = Wire(Bool())
160f1fe8698SLemover  val s0_fire,  s1_fire , s2_fire  = Wire(Bool())
1611d8f4dcbSJay
1622a3050c2SJay  /**
1632a3050c2SJay    ******************************************************************************
16458dbdfc2SJay    * ICache Stage 0
16558dbdfc2SJay    * - send req to ITLB and wait for tlb miss fixing
16658dbdfc2SJay    * - send req to Meta/Data SRAM
1672a3050c2SJay    ******************************************************************************
1682a3050c2SJay    */
1692a3050c2SJay
17058dbdfc2SJay  /** s0 control */
171c5c5edaeSJenius  val s0_valid       = fromFtq.valid
172f56177cbSJenius  val s0_req_vaddr   = (0 until partWayNum + 1).map(i => VecInit(Seq(fromFtqReq(i).startAddr, fromFtqReq(i).nextlineStart)))
173f56177cbSJenius  val s0_req_vsetIdx = (0 until partWayNum + 1).map(i => VecInit(s0_req_vaddr(i).map(get_idx(_))))
174dc270d3bSJenius  val s0_only_first  = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && !fromFtqReq(i).crossCacheline)
175dc270d3bSJenius  val s0_double_line = (0 until partWayNum + 1).map(i => fromFtq.bits.readValid(i) && fromFtqReq(i).crossCacheline)
1761d8f4dcbSJay
177f1fe8698SLemover  val s0_final_valid        = s0_valid
178fd0ecf27SLingrui98  val s0_final_vaddr        = s0_req_vaddr.head
179fd0ecf27SLingrui98  val s0_final_vsetIdx      = s0_req_vsetIdx.head
180fd0ecf27SLingrui98  val s0_final_only_first   = s0_only_first.head
181fd0ecf27SLingrui98  val s0_final_double_line  = s0_double_line.head
18261e1db30SJay
18358dbdfc2SJay  /** SRAM request */
184a61a35e0Sssszwic  // 0,1,2,3 -> dataArray(data); 3 -> dataArray(code); 0 -> metaArray; 4 -> itlb
185f56177cbSJenius  val ftq_req_to_data_doubleline  = s0_double_line.init
186f56177cbSJenius  val ftq_req_to_data_vset_idx    = s0_req_vsetIdx.init
187dc270d3bSJenius  val ftq_req_to_data_valid       = fromFtq.bits.readValid.init
188f56177cbSJenius
189f56177cbSJenius  val ftq_req_to_meta_doubleline  = s0_double_line.head
190f56177cbSJenius  val ftq_req_to_meta_vset_idx    = s0_req_vsetIdx.head
191a61a35e0Sssszwic  val ftq_req_to_meta_valid       = fromFtq.bits.readValid.head
192f56177cbSJenius
193f56177cbSJenius  val ftq_req_to_itlb_only_first  = s0_only_first.last
194f56177cbSJenius  val ftq_req_to_itlb_doubleline  = s0_double_line.last
195f56177cbSJenius  val ftq_req_to_itlb_vaddr       = s0_req_vaddr.last
196f56177cbSJenius  val ftq_req_to_itlb_vset_idx    = s0_req_vsetIdx.last
197f56177cbSJenius
198cb6e5d3cSssszwic  /** Data request */
199fd0ecf27SLingrui98  for(i <- 0 until partWayNum) {
200a61a35e0Sssszwic    toData.valid                  := ftq_req_to_data_valid(i)
201f56177cbSJenius    toData.bits(i).isDoubleLine   := ftq_req_to_data_doubleline(i)
202f56177cbSJenius    toData.bits(i).vSetIdx        := ftq_req_to_data_vset_idx(i)
2031d8f4dcbSJay  }
204afed18b5SJenius
205cb6e5d3cSssszwic  /** Meta request */
206a61a35e0Sssszwic  toMeta.valid               := ftq_req_to_meta_valid
207f56177cbSJenius  toMeta.bits.isDoubleLine   := ftq_req_to_meta_doubleline
208f56177cbSJenius  toMeta.bits.vSetIdx        := ftq_req_to_meta_vset_idx
209afed18b5SJenius
210cb6e5d3cSssszwic  val toITLB_s0_valid    = VecInit(Seq(s0_valid, s0_valid && ftq_req_to_itlb_doubleline))
211cb6e5d3cSssszwic  val toITLB_s0_size     = VecInit(Seq(3.U, 3.U)) // TODO: fix the size
212cb6e5d3cSssszwic  val toITLB_s0_vaddr    = ftq_req_to_itlb_vaddr
213cb6e5d3cSssszwic  val toITLB_s0_debug_pc = ftq_req_to_itlb_vaddr
2142a3050c2SJay
215f1fe8698SLemover  val itlb_can_go    = toITLB(0).ready && toITLB(1).ready
216afed18b5SJenius  val icache_can_go  = toData.ready && toMeta.ready
217a61a35e0Sssszwic  val pipe_can_go    = s1_ready
218f1fe8698SLemover  val s0_can_go      = itlb_can_go && icache_can_go && pipe_can_go
219cb6e5d3cSssszwic  s0_fire  := s0_valid && s0_can_go
2207052722fSJay
2217052722fSJay  //TODO: fix GTimer() condition
222c5c5edaeSJenius  fromFtq.ready := s0_can_go
223f1fe8698SLemover
2242a3050c2SJay  /**
2252a3050c2SJay    ******************************************************************************
22658dbdfc2SJay    * ICache Stage 1
22758dbdfc2SJay    * - get tlb resp data (exceptiong info and physical addresses)
22858dbdfc2SJay    * - get Meta/Data SRAM read responses (latched for pipeline stop)
22958dbdfc2SJay    * - tag compare/hit check
230cb6e5d3cSssszwic    * - check ipf and piq
2312a3050c2SJay    ******************************************************************************
2322a3050c2SJay    */
2331d8f4dcbSJay
23458dbdfc2SJay  /** s1 control */
235f1fe8698SLemover  val s1_valid = generatePipeControl(lastFire = s0_fire, thisFire = s1_fire, thisFlush = false.B, lastFlush = false.B)
2361d8f4dcbSJay
237005e809bSJiuyang Liu  val s1_req_vaddr   = RegEnable(s0_final_vaddr, s0_fire)
238005e809bSJiuyang Liu  val s1_req_vsetIdx = RegEnable(s0_final_vsetIdx, s0_fire)
239005e809bSJiuyang Liu  val s1_double_line = RegEnable(s0_final_double_line, s0_fire)
240cb6e5d3cSssszwic
241cb6e5d3cSssszwic  /** tlb request and response */
242cb6e5d3cSssszwic  fromITLB.foreach(_.ready := true.B)
243cb6e5d3cSssszwic  val s1_wait_itlb  = RegInit(VecInit(Seq.fill(PortNumber)(false.B)))
244cb6e5d3cSssszwic
245cb6e5d3cSssszwic  (0 until PortNumber).foreach { i =>
246cb6e5d3cSssszwic    when(RegNext(s0_fire) && fromITLB(i).bits.miss) {
247cb6e5d3cSssszwic      s1_wait_itlb(i) := true.B
248cb6e5d3cSssszwic    }.elsewhen(s1_wait_itlb(i) && !fromITLB(i).bits.miss) {
249cb6e5d3cSssszwic      s1_wait_itlb(i) := false.B
250cb6e5d3cSssszwic    }
251cb6e5d3cSssszwic  }
252cb6e5d3cSssszwic
253cb6e5d3cSssszwic  val s1_need_itlb = Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && fromITLB(0).bits.miss,
254cb6e5d3cSssszwic                         (RegNext(s0_fire) || s1_wait_itlb(1)) && fromITLB(1).bits.miss && s1_double_line)
255cb6e5d3cSssszwic  val toITLB_s1_valid    = s1_need_itlb
256cb6e5d3cSssszwic  val toITLB_s1_size     = VecInit(Seq(3.U, 3.U)) // TODO: fix the size
257cb6e5d3cSssszwic  val toITLB_s1_vaddr    = s1_req_vaddr
258cb6e5d3cSssszwic  val toITLB_s1_debug_pc = s1_req_vaddr
259cb6e5d3cSssszwic
260cb6e5d3cSssszwic  // chose tlb req between s0 and s1
261cb6e5d3cSssszwic  for (i <- 0 until PortNumber) {
262cb6e5d3cSssszwic    toITLB(i).valid         := Mux(s1_need_itlb(i), toITLB_s1_valid(i), toITLB_s0_valid(i))
263cb6e5d3cSssszwic    toITLB(i).bits.size     := Mux(s1_need_itlb(i), toITLB_s1_size(i), toITLB_s0_size(i))
264cb6e5d3cSssszwic    toITLB(i).bits.vaddr    := Mux(s1_need_itlb(i), toITLB_s1_vaddr(i), toITLB_s0_vaddr(i))
265cb6e5d3cSssszwic    toITLB(i).bits.debug.pc := Mux(s1_need_itlb(i), toITLB_s1_debug_pc(i), toITLB_s0_debug_pc(i))
266cb6e5d3cSssszwic  }
267cb6e5d3cSssszwic  toITLB.map{port =>
268cb6e5d3cSssszwic    port.bits.cmd                 := TlbCmd.exec
269cb6e5d3cSssszwic    port.bits.memidx              := DontCare
270cb6e5d3cSssszwic    port.bits.debug.robIdx        := DontCare
271cb6e5d3cSssszwic    port.bits.no_translate        := false.B
272cb6e5d3cSssszwic    port.bits.debug.isFirstIssue  := DontCare
273cb6e5d3cSssszwic    port.bits.kill                := DontCare
274382a2ebdSpeixiaokun    port.bits.hlvx                := DontCare
275382a2ebdSpeixiaokun    port.bits.hyperinst           := DontCare
276cb6e5d3cSssszwic  }
277cb6e5d3cSssszwic  io.itlb.foreach(_.req_kill := false.B)
2781d8f4dcbSJay
27958dbdfc2SJay  /** tlb response latch for pipeline stop */
280cb6e5d3cSssszwic  // val tlb_valid_tmp = VecInit((0 until PortNumber).map(i =>
281cb6e5d3cSssszwic  //                       (RegNext(s0_fire) || s1_wait_itlb(i)) && !fromITLB(i).bits.miss))
282cb6e5d3cSssszwic  val tlb_valid_tmp = VecInit(Seq((RegNext(s0_fire) || s1_wait_itlb(0)) && !fromITLB(0).bits.miss,
283cb6e5d3cSssszwic                                  (RegNext(s0_fire) || s1_wait_itlb(1)) && !fromITLB(1).bits.miss && s1_double_line))
284cb6e5d3cSssszwic  val tlbRespPAddr  = VecInit((0 until PortNumber).map(i =>
285cb6e5d3cSssszwic                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.paddr(0))))
286*b436d3b6Speixiaokun  val tlbRespGPAddr = VecInit((0 until PortNumber).map(i =>
287*b436d3b6Speixiaokun                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.gpaddr(0))))
288*b436d3b6Speixiaokun  val tlbExcpGPF    = VecInit((0 until PortNumber).map(i =>
289*b436d3b6Speixiaokun                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.excp(0).gpf.instr)))
290cb6e5d3cSssszwic  val tlbExcpPF     = VecInit((0 until PortNumber).map(i =>
291cb6e5d3cSssszwic                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.excp(0).pf.instr)))
292cb6e5d3cSssszwic  val tlbExcpAF     = VecInit((0 until PortNumber).map(i =>
293cb6e5d3cSssszwic                        ResultHoldBypass(valid = tlb_valid_tmp(i), data = fromITLB(i).bits.excp(0).af.instr)))
294*b436d3b6Speixiaokun  val tlbExcp       = VecInit((0 until PortNumber).map(i => tlbExcpAF(i) || tlbExcpPF(i) || tlbExcpGPF(i)))
2951d8f4dcbSJay
296cb6e5d3cSssszwic  val s1_tlb_valid = VecInit((0 until PortNumber).map(i => ValidHoldBypass(tlb_valid_tmp(i), s1_fire)))
297cb6e5d3cSssszwic  val tlbRespAllValid = s1_tlb_valid(0) && (!s1_double_line || s1_double_line && s1_tlb_valid(1))
2982a3050c2SJay
2991d8f4dcbSJay
300d2b20d1aSTang Haojin  def numOfStage = 3
301d2b20d1aSTang Haojin  val itlbMissStage = RegInit(VecInit(Seq.fill(numOfStage - 1)(0.B)))
302d2b20d1aSTang Haojin  itlbMissStage(0) := !tlbRespAllValid
303d2b20d1aSTang Haojin  for (i <- 1 until numOfStage - 1) {
304d2b20d1aSTang Haojin    itlbMissStage(i) := itlbMissStage(i - 1)
305d2b20d1aSTang Haojin  }
306d2b20d1aSTang Haojin
30758dbdfc2SJay  /** s1 hit check/tag compare */
3081d8f4dcbSJay  val s1_req_paddr              = tlbRespPAddr
309d0de7e4aSpeixiaokun  val s1_req_gpaddr             = tlbRespGPAddr
3101d8f4dcbSJay  val s1_req_ptags              = VecInit(s1_req_paddr.map(get_phy_tag(_)))
3111d8f4dcbSJay
312ccfc2e22SJay  val s1_meta_ptags              = ResultHoldBypass(data = metaResp.tags, valid = RegNext(s0_fire))
31360672d5eSguohongyu  val s1_meta_valids             = ResultHoldBypass(data = metaResp.entryValid, valid = RegNext(s0_fire))
31458dbdfc2SJay  val s1_meta_errors             = ResultHoldBypass(data = metaResp.errors, valid = RegNext(s0_fire))
31558dbdfc2SJay
316ccfc2e22SJay  val s1_data_cacheline          = ResultHoldBypass(data = dataResp.datas, valid = RegNext(s0_fire))
31779b191f7SJay  val s1_data_errorBits          = ResultHoldBypass(data = dataResp.codes, valid = RegNext(s0_fire))
3181d8f4dcbSJay
3191d8f4dcbSJay  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)))))
320a61a35e0Sssszwic  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)})))
3211d8f4dcbSJay  val s1_tag_match         = VecInit(s1_tag_match_vec.map(vector => ParallelOR(vector)))
3221d8f4dcbSJay
323a61a35e0Sssszwic  val s1_port_hit          = VecInit(Seq(s1_tag_match(0) && s1_valid, s1_tag_match(1) && s1_valid && s1_double_line))
3241d8f4dcbSJay
3251d8f4dcbSJay  /** choose victim cacheline */
3262f4a98abSssszwic  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))))
3275b0cc873Sguohongyu  val replacers       = Seq.fill(PortNumber)(ReplacementPolicy.fromString(cacheParams.replacer,nWays,nSets/PortNumber))
3282f4a98abSssszwic  val bank_victim_oh  = ResultHoldBypass(data = VecInit(replacers.zipWithIndex.map{case (replacer, i) => UIntToOH(replacer.way(bank_vsetIdx(i)))}), valid = RegNext(s0_fire))
3292f4a98abSssszwic  val s1_victim_oh    = VecInit((0 until PortNumber).map( i => Mux(s1_req_vsetIdx(i)(0), bank_victim_oh(1), bank_victim_oh(0))))
3301d8f4dcbSJay
3312f4a98abSssszwic  when(s1_fire){
3322f4a98abSssszwic    assert(PopCount(s1_tag_match_vec(0)) <= 1.U && (PopCount(s1_tag_match_vec(1)) <= 1.U || !s1_double_line),
3332f4a98abSssszwic      "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 ",
3342f4a98abSssszwic      PopCount(s1_tag_match_vec(0)) > 1.U,s1_req_ptags(0), get_idx(s1_req_vaddr(0)), s1_req_vaddr(0),
3352f4a98abSssszwic      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))
3362f4a98abSssszwic  }
3371d8f4dcbSJay
338cb6e5d3cSssszwic  /** check ipf, get result at the same cycle */
339b1ded4e8Sguohongyu  (0 until PortNumber).foreach { i =>
340cb6e5d3cSssszwic    toIPF(i).valid      := tlb_valid_tmp(i)
341b1ded4e8Sguohongyu    toIPF(i).bits.paddr := s1_req_paddr(i)
342b1ded4e8Sguohongyu  }
343cb6e5d3cSssszwic  val s1_ipf_hit        = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromIPF(i).ipf_hit))
344cb6e5d3cSssszwic  val s1_ipf_hit_latch  = VecInit((0 until PortNumber).map(i => holdReleaseLatch(valid = s1_ipf_hit(i), release = s1_fire, flush = false.B)))
345cb6e5d3cSssszwic  val s1_ipf_data       = VecInit((0 until PortNumber).map(i => ResultHoldBypass(data = fromIPF(i).cacheline, valid = s1_ipf_hit(i))))
346b1ded4e8Sguohongyu
347b1ded4e8Sguohongyu  /** check in PIQ, if hit, wait until prefetch port hit */
348cb6e5d3cSssszwic  (0 until PortNumber).foreach { i =>
349cb6e5d3cSssszwic    toPIQ(i).valid      := tlb_valid_tmp(i)
350cb6e5d3cSssszwic    toPIQ(i).bits.paddr := s1_req_paddr(i)
351b1ded4e8Sguohongyu  }
352cb6e5d3cSssszwic  val s1_piq_hit        = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromPIQ(i).piq_hit))
353cb6e5d3cSssszwic  val s1_piq_hit_latch  = VecInit((0 until PortNumber).map(i => holdReleaseLatch(valid = s1_piq_hit(i), release = s1_fire, flush = false.B)))
354cb6e5d3cSssszwic  val wait_piq          = VecInit((0 until PortNumber).map(i => toIPF(i).valid && fromPIQ(i).piq_hit && !fromPIQ(i).data_valid))
355cb6e5d3cSssszwic  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)))
356cb6e5d3cSssszwic  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)))
357b1ded4e8Sguohongyu
358cb6e5d3cSssszwic  val s1_wait           = (0 until PortNumber).map(i => wait_piq_latch(i) && !fromPIQ(i).data_valid).reduce(_||_)
359b1ded4e8Sguohongyu
360cb6e5d3cSssszwic  val s1_prefetch_hit = VecInit((0 until PortNumber).map(i => s1_ipf_hit_latch(i) || s1_piq_hit_latch(i)))
361cb6e5d3cSssszwic  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))))
362cb6e5d3cSssszwic
363cb6e5d3cSssszwic  s1_ready := s2_ready && tlbRespAllValid && !s1_wait || !s1_valid
364cb6e5d3cSssszwic  s1_fire  := s1_valid && tlbRespAllValid && s2_ready && !s1_wait
365b1ded4e8Sguohongyu
366f9c51548Sssszwic  // record cacheline log
367f9c51548Sssszwic  val isWriteICacheTable = WireInit(Constantin.createRecord("isWriteICacheTable" + p(XSCoreParamsKey).HartId.toString))
368f9c51548Sssszwic  val ICacheTable = ChiselDB.createTable("ICacheTable" + p(XSCoreParamsKey).HartId.toString, new ICacheDB)
369f9c51548Sssszwic
370f9c51548Sssszwic  val ICacheDumpData_req0 = Wire(new ICacheDB)
371f9c51548Sssszwic  ICacheDumpData_req0.blk_paddr := getBlkAddr(s1_req_paddr(0))
372f9c51548Sssszwic  ICacheDumpData_req0.blk_vaddr := getBlkAddr(s1_req_vaddr(0))
373f9c51548Sssszwic  ICacheDumpData_req0.hit       := s1_port_hit(0) || s1_prefetch_hit(0)
374f9c51548Sssszwic  ICacheTable.log(
375f9c51548Sssszwic    data = ICacheDumpData_req0,
376f9c51548Sssszwic    en = isWriteICacheTable.orR && s1_fire,
377f9c51548Sssszwic    clock = clock,
378f9c51548Sssszwic    reset = reset
379f9c51548Sssszwic  )
380f9c51548Sssszwic
381f9c51548Sssszwic  val ICacheDumpData_req1 = Wire(new ICacheDB)
382f9c51548Sssszwic  ICacheDumpData_req1.blk_paddr := getBlkAddr(s1_req_paddr(1))
383f9c51548Sssszwic  ICacheDumpData_req1.blk_vaddr := getBlkAddr(s1_req_vaddr(1))
384f9c51548Sssszwic  ICacheDumpData_req1.hit       := s1_port_hit(1) || s1_prefetch_hit(1)
385f9c51548Sssszwic  ICacheTable.log(
386f9c51548Sssszwic    data = ICacheDumpData_req1,
387f9c51548Sssszwic    en = isWriteICacheTable.orR && s1_fire && s1_double_line,
388f9c51548Sssszwic    clock = clock,
389f9c51548Sssszwic    reset = reset
390f9c51548Sssszwic  )
391f9c51548Sssszwic
39258dbdfc2SJay  /** <PERF> replace victim way number */
39358dbdfc2SJay
3941d8f4dcbSJay  (0 until nWays).map{ w =>
3951d8f4dcbSJay    XSPerfAccumulate("line_0_hit_way_" + Integer.toString(w, 10),  s1_fire && s1_port_hit(0) && OHToUInt(s1_tag_match_vec(0))  === w.U)
3961d8f4dcbSJay  }
3971d8f4dcbSJay
3981d8f4dcbSJay  (0 until nWays).map{ w =>
3991d8f4dcbSJay    XSPerfAccumulate("line_0_victim_way_" + Integer.toString(w, 10),  s1_fire && !s1_port_hit(0) && OHToUInt(s1_victim_oh(0))  === w.U)
4001d8f4dcbSJay  }
4011d8f4dcbSJay
4021d8f4dcbSJay  (0 until nWays).map{ w =>
4031d8f4dcbSJay    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)
4041d8f4dcbSJay  }
4051d8f4dcbSJay
4061d8f4dcbSJay  (0 until nWays).map{ w =>
4071d8f4dcbSJay    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)
4081d8f4dcbSJay  }
4091d8f4dcbSJay
410b1ded4e8Sguohongyu  XSPerfAccumulate("mainPipe_stage1_block_by_piq_cycles", s1_valid && s1_wait)
411b1ded4e8Sguohongyu
4122a3050c2SJay  /**
4132a3050c2SJay    ******************************************************************************
41458dbdfc2SJay    * ICache Stage 2
41558dbdfc2SJay    * - send request to MSHR if ICache miss
41658dbdfc2SJay    * - generate secondary miss status/data registers
41758dbdfc2SJay    * - response to IFU
4182a3050c2SJay    ******************************************************************************
4192a3050c2SJay    */
42058dbdfc2SJay
42158dbdfc2SJay  /** s2 control */
4221d8f4dcbSJay  val s2_fetch_finish = Wire(Bool())
4231d8f4dcbSJay
424f1fe8698SLemover  val s2_valid          = generatePipeControl(lastFire = s1_fire, thisFire = s2_fire, thisFlush = false.B, lastFlush = false.B)
4251d8f4dcbSJay
426a61a35e0Sssszwic  s2_ready      := (s2_valid && s2_fetch_finish && !io.respStall) || !s2_valid
4271d8f4dcbSJay  s2_fire       := s2_valid && s2_fetch_finish && !io.respStall
4281d8f4dcbSJay
42958dbdfc2SJay  /** s2 data */
430cb6e5d3cSssszwic  // val mmio = fromPMP.map(port => port.mmio) // TODO: handle it
431005e809bSJiuyang Liu  val (s2_req_paddr , s2_req_vaddr) = (RegEnable(s1_req_paddr, s1_fire), RegEnable(s1_req_vaddr, s1_fire))
432d0de7e4aSpeixiaokun  val s2_req_gpaddr           = RegEnable(s1_req_gpaddr,        s1_fire)
433005e809bSJiuyang Liu  val s2_req_vsetIdx          = RegEnable(s1_req_vsetIdx,       s1_fire)
434005e809bSJiuyang Liu  val s2_req_ptags            = RegEnable(s1_req_ptags,         s1_fire)
435005e809bSJiuyang Liu  val s2_double_line          = RegEnable(s1_double_line,       s1_fire)
436005e809bSJiuyang Liu  val s2_port_hit             = RegEnable(s1_port_hit,          s1_fire)
437005e809bSJiuyang Liu  val s2_waymask              = RegEnable(s1_victim_oh,         s1_fire)
438005e809bSJiuyang Liu  val s2_tag_match_vec        = RegEnable(s1_tag_match_vec,     s1_fire)
4391d8f4dcbSJay
440a61a35e0Sssszwic  val s2_meta_errors          = RegEnable(s1_meta_errors,    s1_fire)
441a61a35e0Sssszwic  val s2_data_errorBits       = RegEnable(s1_data_errorBits, s1_fire)
442a61a35e0Sssszwic  val s2_data_cacheline       = RegEnable(s1_data_cacheline, s1_fire)
443d2b20d1aSTang Haojin
44458c354d0Sssszwic  /** send req info of s1 and s2 to IPrefetchPipe for filter request */
44558c354d0Sssszwic  toIPrefetch.s1Info(0).paddr  := s1_req_paddr(0)
44658c354d0Sssszwic  toIPrefetch.s1Info(0).valid  := s1_valid
44758c354d0Sssszwic  toIPrefetch.s1Info(1).paddr  := s1_req_paddr(1)
44858c354d0Sssszwic  toIPrefetch.s1Info(1).valid  := s1_valid && s1_double_line
44958c354d0Sssszwic  toIPrefetch.s2Info(0).paddr  := s2_req_paddr(0)
45058c354d0Sssszwic  toIPrefetch.s2Info(0).valid  := s2_valid
45158c354d0Sssszwic  toIPrefetch.s2Info(1).paddr  := s2_req_paddr(1)
45258c354d0Sssszwic  toIPrefetch.s2Info(1).valid  := s2_valid && s2_double_line
45358c354d0Sssszwic
454f1fe8698SLemover  assert(RegNext(!s2_valid || s2_req_paddr(0)(11,0) === s2_req_vaddr(0)(11,0), true.B))
455f1fe8698SLemover
456a61a35e0Sssszwic  /**
457a61a35e0Sssszwic    ******************************************************************************
458a61a35e0Sssszwic    * tlb exception and pmp logic
459a61a35e0Sssszwic    ******************************************************************************
460a61a35e0Sssszwic    */
461a61a35e0Sssszwic  // short delay exception signal
462a61a35e0Sssszwic  val s2_except_tlb_pf  = RegEnable(tlbExcpPF, s1_fire)
463*b436d3b6Speixiaokun  val s2_except_tlb_gpf = RegEnable(tlbExcpGPF, s1_fire)
464a61a35e0Sssszwic  val s2_except_tlb_af  = RegEnable(tlbExcpAF, s1_fire)
465*b436d3b6Speixiaokun  val s2_except_tlb     = VecInit(Seq(s2_except_tlb_pf(0) || s2_except_tlb_af(0) || s2_except_tlb_gpf(0), s2_double_line && (s2_except_tlb_pf(1) || s2_except_tlb_af(1) || s2_except_tlb_gpf(1))))
466a61a35e0Sssszwic  val s2_has_except_tlb = s2_valid && s2_except_tlb.reduce(_||_)
467a61a35e0Sssszwic  // long delay exception signal
468a61a35e0Sssszwic  // exception information and mmio
469a61a35e0Sssszwic  val pmpExcpAF = VecInit(Seq(fromPMP(0).instr, fromPMP(1).instr && s2_double_line))
470a61a35e0Sssszwic  val s2_except_pmp_af = DataHoldBypass(pmpExcpAF, RegNext(s1_fire))
471a61a35e0Sssszwic  val s2_mmio = s2_valid && DataHoldBypass(fromPMP(0).mmio && !s2_except_tlb(0) && !s2_except_pmp_af(0), RegNext(s1_fire)).asBool
472a61a35e0Sssszwic  // pmp port
473a61a35e0Sssszwic  toPMP.zipWithIndex.map { case (p, i) =>
474a61a35e0Sssszwic    p.valid     := s2_valid
475a61a35e0Sssszwic    p.bits.addr := s2_req_paddr(i)
476a61a35e0Sssszwic    p.bits.size := 3.U // TODO
477a61a35e0Sssszwic    p.bits.cmd  := TlbCmd.exec
478a61a35e0Sssszwic  }
4791d8f4dcbSJay
480a61a35e0Sssszwic  /**
481a61a35e0Sssszwic    ******************************************************************************
482a61a35e0Sssszwic    * look last miss data
483a61a35e0Sssszwic    ******************************************************************************
484a61a35e0Sssszwic    */
485a61a35e0Sssszwic  class MissSlot(implicit p: Parameters) extends ICacheBundle {
486a61a35e0Sssszwic    val paddr     = RegInit(0.U(PAddrBits.W))
487a61a35e0Sssszwic    val vSetIdx   = RegInit(0.U(idxBits.W))
488a61a35e0Sssszwic    val waymask   = RegInit(0.U(nWays.W))
489a61a35e0Sssszwic    val data      = RegInit(0.U(blockBits.W))
490a61a35e0Sssszwic    val corrupt   = RegInit(false.B)
491a61a35e0Sssszwic    val finish    = RegInit(true.B)
492a61a35e0Sssszwic    val valid     = RegInit(false.B)
493a61a35e0Sssszwic    def data_vec  = data.asTypeOf(Vec(2, UInt((blockBits/2).W)))
494a61a35e0Sssszwic    def pTag      = get_phy_tag(paddr)
495a61a35e0Sssszwic  }
496a61a35e0Sssszwic  val missSlot    = Seq.fill(2)(new MissSlot)
49779b191f7SJay
498a61a35e0Sssszwic  // whether hit in last miss req
499a61a35e0Sssszwic  def getMissSituat(missNum : Int, slotNum : Int ) :Bool =  {
500a61a35e0Sssszwic    (missSlot(slotNum).vSetIdx === s1_req_vsetIdx(missNum)) &&
501a61a35e0Sssszwic    (missSlot(slotNum).pTag === s1_req_ptags(missNum)) &&
502a61a35e0Sssszwic    !missSlot(slotNum).corrupt && missSlot(slotNum).finish &&
503a61a35e0Sssszwic    missSlot(slotNum).valid
504a61a35e0Sssszwic  }
505a61a35e0Sssszwic
506a61a35e0Sssszwic  // s2_hit_slot(0)(1): port 0 hit slot 1
507a61a35e0Sssszwic  // Use the signal of S1 to make a judgment for timing, the value of missSlot has benn set when s1 fire
508a61a35e0Sssszwic  val s1_hit_slot_vec = VecInit((0 until PortNumber).map(port => VecInit((0 until PortNumber).map(getMissSituat(port, _)))))
509a61a35e0Sssszwic  val s2_hit_slot_vec = RegEnable(s1_hit_slot_vec, s1_fire)
510a61a35e0Sssszwic
511a61a35e0Sssszwic  // select one from two missSlots to handle miss for every port
512a61a35e0Sssszwic  // slot(0) hit  && slot(1) hit : don't case
513a61a35e0Sssszwic  // slot(0) hit  && slot(1) miss: (a) missed port(0) -> slot(1); (b) missed port(1) -> slot(1)
514a61a35e0Sssszwic  // slot(0) miss && slot(1) hit : (a) missed port(0) -> slot(0); (b) missed port(1) -> slot(0)
515a61a35e0Sssszwic  // slot(0) miss && slot(1) miss: missed port(0) -> slot(0)  missed port(1) -> slot(1)
516a61a35e0Sssszwic  val s1_curr_slot_id = Wire(Vec(2, Bool()))
517a61a35e0Sssszwic  s1_curr_slot_id(0) := s1_hit_slot_vec(0)(0) || s1_hit_slot_vec(1)(0)
518a61a35e0Sssszwic  s1_curr_slot_id(1) := !(s1_hit_slot_vec(0)(1) || s1_hit_slot_vec(1)(1))
519a61a35e0Sssszwic  val s2_curr_slot_id = RegEnable(s1_curr_slot_id, s1_fire)
520a61a35e0Sssszwic
521a61a35e0Sssszwic  /**
522a61a35e0Sssszwic    ******************************************************************************
523a61a35e0Sssszwic    * miss handle
524a61a35e0Sssszwic    ******************************************************************************
525a61a35e0Sssszwic    */
526a61a35e0Sssszwic  val s2_hit_slot = VecInit(s2_hit_slot_vec.map(_.asUInt.orR))
527a61a35e0Sssszwic  val s2_fixed_port_hit = VecInit((0 until PortNumber).map(port => s2_port_hit(port) || s2_hit_slot(port)))
528a61a35e0Sssszwic
529a61a35e0Sssszwic  // only handle port0 miss when port1 have tlb except or pmp except
530a61a35e0Sssszwic  val s2_port_miss = Wire(Vec(PortNumber, Bool()))
531a61a35e0Sssszwic
532a61a35e0Sssszwic  s2_port_miss(0) := !s2_fixed_port_hit(0) && !s2_except_tlb(0) && !s2_except_pmp_af(0) && !s2_mmio
533a61a35e0Sssszwic  s2_port_miss(1) := !s2_fixed_port_hit(1) && s2_double_line && !s2_except_tlb(0) && !s2_except_tlb(1) &&
534a61a35e0Sssszwic                     !s2_except_pmp_af(0) && !s2_except_pmp_af(1) && !s2_mmio
535a61a35e0Sssszwic
536a61a35e0Sssszwic  (0 until PortNumber).map{ i =>
537a61a35e0Sssszwic    when(s2_port_miss(i) && RegNext(s1_fire)) {
538a61a35e0Sssszwic      when(s2_curr_slot_id(i)) {
539a61a35e0Sssszwic        missSlot(1).vSetIdx := s2_req_vsetIdx(i)
540a61a35e0Sssszwic        missSlot(1).paddr   := s2_req_paddr(i)
541a61a35e0Sssszwic        missSlot(1).waymask := s2_waymask(i)
542a61a35e0Sssszwic        missSlot(1).finish  := false.B
543a61a35e0Sssszwic        missSlot(1).valid   := true.B
544a61a35e0Sssszwic      }.otherwise {
545a61a35e0Sssszwic        missSlot(0).vSetIdx := s2_req_vsetIdx(i)
546a61a35e0Sssszwic        missSlot(0).paddr   := s2_req_paddr(i)
547a61a35e0Sssszwic        missSlot(0).waymask := s2_waymask(i)
548a61a35e0Sssszwic        missSlot(0).finish  := false.B
549a61a35e0Sssszwic        missSlot(0).valid   := true.B
550a61a35e0Sssszwic      }
551a61a35e0Sssszwic    }
552a61a35e0Sssszwic  }
553a61a35e0Sssszwic
554a61a35e0Sssszwic  // which missSlot need to be issued
555a61a35e0Sssszwic  val s2_missSlot_issue = Wire(Vec(2, Bool()))
556a61a35e0Sssszwic  s2_missSlot_issue(0) := (s2_port_miss(0) && !s2_curr_slot_id(0)) || (s2_port_miss(1) && !s2_curr_slot_id(1))
557a61a35e0Sssszwic  s2_missSlot_issue(1) := (s2_port_miss(0) && s2_curr_slot_id(0)) || (s2_port_miss(1) && s2_curr_slot_id(1))
558a61a35e0Sssszwic
559a61a35e0Sssszwic  // state machine
560a61a35e0Sssszwic  val m_idle ::m_send_req :: m_wait_resp :: Nil = Enum(3)
561a61a35e0Sssszwic  val missStateQueue = RegInit(VecInit(Seq.fill(2)(m_idle)))
562a61a35e0Sssszwic
563a61a35e0Sssszwic  (0 until PortNumber).map{ i =>
564a61a35e0Sssszwic    switch(missStateQueue(i)){
565a61a35e0Sssszwic      is(m_idle) {
566a61a35e0Sssszwic        missStateQueue(i) := Mux(RegNext(s1_fire) && s2_missSlot_issue(i), m_send_req, m_idle)
567a61a35e0Sssszwic      }
568a61a35e0Sssszwic      is(m_send_req) {
569a61a35e0Sssszwic        missStateQueue(i) := Mux(toMSHR(i).fire, m_wait_resp, m_send_req)
570a61a35e0Sssszwic      }
571a61a35e0Sssszwic      is(m_wait_resp) {
572a61a35e0Sssszwic        missStateQueue(i) := Mux(fromMSHR(i).fire, m_idle, m_wait_resp)
573a61a35e0Sssszwic      }
574a61a35e0Sssszwic    }
575a61a35e0Sssszwic  }
576a61a35e0Sssszwic
577a61a35e0Sssszwic  // send req to MSHR
578a61a35e0Sssszwic  (0 until PortNumber).map{i =>
579a61a35e0Sssszwic    toMSHR(i).valid         := missStateQueue(i) === m_send_req
580a61a35e0Sssszwic    toMSHR(i).bits.paddr    := missSlot(i).paddr
581a61a35e0Sssszwic    toMSHR(i).bits.vSetIdx  := missSlot(i).vSetIdx
582a61a35e0Sssszwic    toMSHR(i).bits.waymask  := missSlot(i).waymask
583a61a35e0Sssszwic  }
584a61a35e0Sssszwic
585a61a35e0Sssszwic  // recrive resp from MSHR to update missSlot
586a61a35e0Sssszwic  (0 until PortNumber).map{ i =>
587a61a35e0Sssszwic    when((missStateQueue(i) === m_wait_resp) && fromMSHR(i).fire) {
588a61a35e0Sssszwic      missSlot(i).finish  := true.B
589a61a35e0Sssszwic      missSlot(i).data    := fromMSHR(i).bits.data
590a61a35e0Sssszwic      missSlot(i).corrupt := fromMSHR(i).bits.corrupt
591a61a35e0Sssszwic    }
592a61a35e0Sssszwic  }
593a61a35e0Sssszwic
594a61a35e0Sssszwic  // handle miss finish
595a61a35e0Sssszwic  s2_fetch_finish := (!s2_port_miss(0) && !s2_port_miss(1)) || (missSlot(0).finish && missSlot(1).finish && !RegNext(s1_fire))
596a61a35e0Sssszwic
597a61a35e0Sssszwic  /**
598a61a35e0Sssszwic    ******************************************************************************
599a61a35e0Sssszwic    * select data from hitted sram data, last missSlot and current missSlot
600a61a35e0Sssszwic    ******************************************************************************
601a61a35e0Sssszwic    */
602a61a35e0Sssszwic  val s2_hit_datas = Wire(Vec(2, UInt((blockBits/2).W)))
603a61a35e0Sssszwic  s2_hit_datas(0) := Mux1H(s2_tag_match_vec(0).asUInt, s2_data_cacheline(0))
604a61a35e0Sssszwic  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))
605a61a35e0Sssszwic
606a61a35e0Sssszwic  // get cacheline from last slot
607a61a35e0Sssszwic  val s2_last_slot_cacheline = (0 until PortNumber).map(port => Mux1H(s2_hit_slot_vec(port).asUInt, missSlot.map(_.data_vec)))
608a61a35e0Sssszwic  // get cacheline from curr slot
609a61a35e0Sssszwic  val s2_curr_slot_cacheline = (0 until PortNumber).map(port => Mux(s2_curr_slot_id(port), missSlot(1).data_vec, missSlot(0).data_vec))
610a61a35e0Sssszwic  val s2_slot_cacheline = (0 until PortNumber).map(port => Mux(s2_hit_slot(port), s2_last_slot_cacheline(port), s2_curr_slot_cacheline(port)))
611a61a35e0Sssszwic  val s2_slot_data = Wire(Vec(PortNumber, UInt((blockBits/2).W)))
612a61a35e0Sssszwic  s2_slot_data(0) := Mux(s2_double_line, s2_slot_cacheline(0)(1), s2_slot_cacheline(0)(0))
613a61a35e0Sssszwic  s2_slot_data(1) := Mux(s2_double_line, s2_slot_cacheline(1)(0), s2_slot_cacheline(0)(1))
614a61a35e0Sssszwic
615a61a35e0Sssszwic  val s2_fetch_data = Wire(Vec(2, UInt((blockBits/2).W)))
616a61a35e0Sssszwic  s2_fetch_data(0) := Mux(s2_port_hit(0), s2_hit_datas(0), s2_slot_data(0))
617a61a35e0Sssszwic  s2_fetch_data(1) := Mux(s2_port_hit(1) || (s2_port_hit(0) && !s2_double_line), s2_hit_datas(1), s2_slot_data(1))
618a61a35e0Sssszwic
619a61a35e0Sssszwic  val s2_corrupt = (0 until PortNumber).map(port => s2_port_miss(port) && Mux(s2_curr_slot_id(port), missSlot(1).corrupt, missSlot(0).corrupt))
620a61a35e0Sssszwic
621a61a35e0Sssszwic  /**
622a61a35e0Sssszwic    ******************************************************************************
623a61a35e0Sssszwic    * IFU data resp
624a61a35e0Sssszwic    ******************************************************************************
625a61a35e0Sssszwic    */
626a61a35e0Sssszwic  (0 until PortNumber).map{ i =>
627a61a35e0Sssszwic    if(i ==0) toIFU(i).valid          := s2_fire
628a61a35e0Sssszwic      else   toIFU(i).valid           := s2_fire && s2_double_line
629a61a35e0Sssszwic    toIFU(i).bits.paddr               := s2_req_paddr(i)
630*b436d3b6Speixiaokun    toIFU(i).bits.gpaddr              := s2_req_gpaddr(i)
631a61a35e0Sssszwic    toIFU(i).bits.vaddr               := s2_req_vaddr(i)
632a61a35e0Sssszwic    toIFU(i).bits.data                := s2_fetch_data(i)
633a61a35e0Sssszwic    toIFU(i).bits.tlbExcp.pageFault   := s2_except_tlb_pf(i)
634*b436d3b6Speixiaokun    toIFU(i).bits.tlbExcp.guestPageFault:= s2_except_tlb_gpf(i)
635a61a35e0Sssszwic    toIFU(i).bits.tlbExcp.accessFault := s2_except_tlb_af(i) || s2_corrupt(i) || s2_except_pmp_af(i)
636a61a35e0Sssszwic    toIFU(i).bits.tlbExcp.mmio        := s2_mmio
637a61a35e0Sssszwic  }
638a61a35e0Sssszwic
639a61a35e0Sssszwic  /**
640a61a35e0Sssszwic    ******************************************************************************
641a61a35e0Sssszwic    * error resp: MSHR error
642a61a35e0Sssszwic    ******************************************************************************
643a61a35e0Sssszwic    */
644a61a35e0Sssszwic  // data/meta parity error
64579b191f7SJay  val s2_data_errors = Wire(Vec(PortNumber,Vec(nWays, Bool())))
64679b191f7SJay  (0 until PortNumber).map{ i =>
64779b191f7SJay    val read_datas = s2_data_cacheline(i).asTypeOf(Vec(nWays,Vec(dataCodeUnitNum, UInt(dataCodeUnit.W))))
64879b191f7SJay    val read_codes = s2_data_errorBits(i).asTypeOf(Vec(nWays,Vec(dataCodeUnitNum, UInt(dataCodeBits.W))))
64979b191f7SJay    val data_full_wayBits = VecInit((0 until nWays).map( w =>
65079b191f7SJay                                  VecInit((0 until dataCodeUnitNum).map( u =>
65179b191f7SJay                                        Cat(read_codes(w)(u), read_datas(w)(u))))))
65279b191f7SJay    val data_error_wayBits = VecInit((0 until nWays).map( w =>
65379b191f7SJay                                  VecInit((0 until dataCodeUnitNum).map( u =>
65479b191f7SJay                                       cacheParams.dataCode.decode(data_full_wayBits(w)(u)).error))))
655a61a35e0Sssszwic    // register for timing
65679b191f7SJay    if(i == 0){
65779b191f7SJay      (0 until nWays).map{ w =>
65879b191f7SJay        s2_data_errors(i)(w) := RegNext(RegNext(s1_fire)) && RegNext(data_error_wayBits(w)).reduce(_||_)
65979b191f7SJay      }
66079b191f7SJay    } else {
66179b191f7SJay      (0 until nWays).map{ w =>
66279b191f7SJay        s2_data_errors(i)(w) := RegNext(RegNext(s1_fire)) && RegNext(RegNext(s1_double_line)) && RegNext(data_error_wayBits(w)).reduce(_||_)
66379b191f7SJay      }
66479b191f7SJay    }
66579b191f7SJay  }
66679b191f7SJay
66779b191f7SJay  val s2_parity_meta_error  = VecInit((0 until PortNumber).map(i => s2_meta_errors(i).reduce(_||_) && io.csr_parity_enable))
66879b191f7SJay  val s2_parity_data_error  = VecInit((0 until PortNumber).map(i => s2_data_errors(i).reduce(_||_) && io.csr_parity_enable))
66979b191f7SJay  val s2_parity_error       = VecInit((0 until PortNumber).map(i => RegNext(s2_parity_meta_error(i)) || s2_parity_data_error(i)))
67079b191f7SJay
67179b191f7SJay  for(i <- 0 until PortNumber){
672e8e4462cSJay    io.errors(i).valid            := RegNext(s2_parity_error(i) && RegNext(RegNext(s1_fire)))
673e8e4462cSJay    io.errors(i).report_to_beu    := RegNext(s2_parity_error(i) && RegNext(RegNext(s1_fire)))
67479b191f7SJay    io.errors(i).paddr            := RegNext(RegNext(s2_req_paddr(i)))
67579b191f7SJay    io.errors(i).source           := DontCare
67679b191f7SJay    io.errors(i).source.tag       := RegNext(RegNext(s2_parity_meta_error(i)))
67779b191f7SJay    io.errors(i).source.data      := RegNext(s2_parity_data_error(i))
67879b191f7SJay    io.errors(i).source.l2        := false.B
67979b191f7SJay    io.errors(i).opType           := DontCare
68079b191f7SJay    io.errors(i).opType.fetch     := true.B
68179b191f7SJay  }
68279b191f7SJay
683a61a35e0Sssszwic  // MSHR error
684a61a35e0Sssszwic  (0 until PortNumber).map{ i =>
685a61a35e0Sssszwic    when(RegNext(s2_fire && s2_corrupt(i))){
686a61a35e0Sssszwic      io.errors(i).valid            := true.B
687a61a35e0Sssszwic      io.errors(i).report_to_beu    := false.B // l2 should have report that to bus error unit, no need to do it again
688a61a35e0Sssszwic      io.errors(i).paddr            := RegNext(s2_req_paddr(i))
689a61a35e0Sssszwic      io.errors(i).source.tag       := false.B
690a61a35e0Sssszwic      io.errors(i).source.data      := false.B
691a61a35e0Sssszwic      io.errors(i).source.l2        := true.B
6921d8f4dcbSJay    }
6931d8f4dcbSJay  }
6941d8f4dcbSJay
695a61a35e0Sssszwic  /**
696a61a35e0Sssszwic    ******************************************************************************
697a61a35e0Sssszwic    * s2 prefetch port
698a61a35e0Sssszwic    ******************************************************************************
699a61a35e0Sssszwic    */
700a61a35e0Sssszwic  (0 until PortNumber).foreach{ i =>
701a61a35e0Sssszwic    // TODO: consider corrupt of missSlot
702a61a35e0Sssszwic    toIPrefetch.missSlot(i).valid   := missSlot(i).valid
703a61a35e0Sssszwic    toIPrefetch.missSlot(i).vSetIdx := missSlot(i).vSetIdx
704a61a35e0Sssszwic    toIPrefetch.missSlot(i).ptag    := missSlot(i).pTag
7051d8f4dcbSJay  }
7061d8f4dcbSJay
707a61a35e0Sssszwic  /**
708a61a35e0Sssszwic    ******************************************************************************
709a61a35e0Sssszwic    * update replacement status register
710a61a35e0Sssszwic    ******************************************************************************
711a61a35e0Sssszwic    */
712a61a35e0Sssszwic  /** replacement status register */
7132f4a98abSssszwic  val port_touch_sets = Seq.fill(PortNumber)(Wire(Vec(2, UInt(log2Ceil(nSets/2).W))))
7142f4a98abSssszwic  val port_touch_ways = Seq.fill(PortNumber)(Wire(Vec(2, Valid(UInt(log2Ceil(nWays).W)))))
7152f4a98abSssszwic  (port_touch_ways zip port_touch_sets).zipWithIndex.map{ case((t_w,t_s), i) =>
7162f4a98abSssszwic    /** update replacement status register: 0 is hit access/ 1 is miss access */
7175b0cc873Sguohongyu    t_s(0)         := s2_req_vsetIdx(i)(highestIdxBit, 1)
7182f4a98abSssszwic    // hit in slot will be ignored, which generate a repeated access
71961e1db30SJay    t_w(0).valid   := s2_valid && s2_port_hit(i)
72061e1db30SJay    t_w(0).bits    := OHToUInt(s2_tag_match_vec(i))
7211d8f4dcbSJay
7225b0cc873Sguohongyu    t_s(1)         := s2_req_vsetIdx(i)(highestIdxBit, 1)
723a61a35e0Sssszwic    t_w(1).valid   := s2_valid && s2_port_miss(i)
7241d8f4dcbSJay    t_w(1).bits    := OHToUInt(s2_waymask(i))
7251d8f4dcbSJay  }
7261d8f4dcbSJay
7272f4a98abSssszwic  val touch_ways = VecInit((0 until PortNumber).map( i => Mux(s2_req_vsetIdx(i)(0), port_touch_ways(1), port_touch_ways(0))))
7282f4a98abSssszwic  val touch_sets = VecInit((0 until PortNumber).map( i => Mux(s2_req_vsetIdx(i)(0), port_touch_sets(1), port_touch_sets(0))))
7292f4a98abSssszwic  ((replacers zip touch_sets) zip touch_ways).map{case ((r, s),w) => r.access(s,w)}
730a61a35e0Sssszwic  // TODO: need choose one replacer according to the bankid
7312f4a98abSssszwic  IPFReplacer.waymask := UIntToOH(replacers(0).way(IPFReplacer.vsetIdx))
7322f4a98abSssszwic
733a61a35e0Sssszwic  /**
734a61a35e0Sssszwic    ******************************************************************************
735a61a35e0Sssszwic    * performance info. TODO: need to simplify the logic
736a61a35e0Sssszwic    ***********************************************************s*******************
737a61a35e0Sssszwic    */
738a61a35e0Sssszwic  io.fetch.topdownIcacheMiss := s2_port_miss(0) || s2_port_miss(1)
739d2b20d1aSTang Haojin  io.fetch.topdownItlbMiss := itlbMissStage(0)
740d2b20d1aSTang Haojin
741a61a35e0Sssszwic  io.perfInfo.only_0_hit      :=  s2_fixed_port_hit(0) && !s2_double_line
742a61a35e0Sssszwic  io.perfInfo.only_0_miss     := !s2_fixed_port_hit(0) && !s2_double_line
743a61a35e0Sssszwic  io.perfInfo.hit_0_hit_1     :=  s2_fixed_port_hit(0) &&  s2_fixed_port_hit(1) && s2_double_line
744a61a35e0Sssszwic  io.perfInfo.hit_0_miss_1    :=  s2_fixed_port_hit(0) && !s2_fixed_port_hit(1) && s2_double_line
745a61a35e0Sssszwic  io.perfInfo.miss_0_hit_1    := !s2_fixed_port_hit(0) &&  s2_fixed_port_hit(1) && s2_double_line
746a61a35e0Sssszwic  io.perfInfo.miss_0_miss_1   := !s2_fixed_port_hit(0) && !s2_fixed_port_hit(1) && s2_double_line
747a61a35e0Sssszwic  io.perfInfo.hit_0_except_1  :=  s2_fixed_port_hit(0) && (s2_except_tlb(1) || s2_except_pmp_af(1)) && s2_double_line
748a61a35e0Sssszwic  io.perfInfo.miss_0_except_1 := !s2_fixed_port_hit(0) && (s2_except_tlb(1) || s2_except_pmp_af(1)) && s2_double_line
749a61a35e0Sssszwic  io.perfInfo.bank_hit(0)     :=  s2_fixed_port_hit(0)
750a61a35e0Sssszwic  io.perfInfo.bank_hit(1)     :=  s2_fixed_port_hit(1) && s2_double_line
751a61a35e0Sssszwic  io.perfInfo.except_0        := s2_except_tlb(0) || s2_except_pmp_af(0)
752a61a35e0Sssszwic  io.perfInfo.hit             := !s2_port_miss(0) && !s2_port_miss(1)
75358dbdfc2SJay
75458dbdfc2SJay  /** <PERF> fetch bubble generated by icache miss*/
75500240ba6SJay  XSPerfAccumulate("icache_bubble_s2_miss", s2_valid && !s2_fetch_finish )
756a61a35e0Sssszwic  XSPerfAccumulate("icache_bubble_s0_tlb_miss", s1_valid && !tlbRespAllValid)
75758dbdfc2SJay
758a61a35e0Sssszwic  /**
759a61a35e0Sssszwic    ******************************************************************************
760a61a35e0Sssszwic    * difftest refill check
761a61a35e0Sssszwic    ******************************************************************************
762a61a35e0Sssszwic    */
763afa866b1Sguohongyu  if (env.EnableDifftest) {
764afa866b1Sguohongyu    val discards = (0 until PortNumber).map { i =>
765*b436d3b6Speixiaokun      val discard = toIFU(i).bits.tlbExcp.pageFault || toIFU(i).bits.tlbExcp.guestPageFault || toIFU(i).bits.tlbExcp.accessFault || toIFU(i).bits.tlbExcp.mmio
766afa866b1Sguohongyu      discard
767afa866b1Sguohongyu    }
768afa866b1Sguohongyu    (0 until PortNumber).map { i =>
769a0c65233SYinan Xu      val diffMainPipeOut = DifftestModule(new DiffRefillEvent, dontCare = true)
7707d45a146SYinan Xu      diffMainPipeOut.coreid := io.hartId
7717d45a146SYinan Xu      diffMainPipeOut.index := (4 + i).U
772a61a35e0Sssszwic      if (i == 0) {
773a61a35e0Sssszwic        diffMainPipeOut.valid := s2_fire && !discards(0)
774a61a35e0Sssszwic        diffMainPipeOut.addr  := s2_req_paddr(0)
775a61a35e0Sssszwic      } else {
776a61a35e0Sssszwic        diffMainPipeOut.valid := s2_fire && !discards(0) && (!s2_double_line || (s2_double_line && !discards(1)))
777a61a35e0Sssszwic        diffMainPipeOut.addr  := s2_req_paddr(0) + (blockBits/2).U
778afa866b1Sguohongyu      }
779a61a35e0Sssszwic      diffMainPipeOut.data := Cat(0.U((blockBits/2).W), toIFU(i).bits.data).asTypeOf(diffMainPipeOut.data)
780a61a35e0Sssszwic      // idtfr: 0 -> data from icache 1 -> reversedData 2 -> data from missUnit
781a61a35e0Sssszwic      diffMainPipeOut.idtfr := Mux(s2_port_hit(i), 0.U, Mux(s2_fixed_port_hit(i), 1.U, 2.U))
782afa866b1Sguohongyu      diffMainPipeOut
783afa866b1Sguohongyu    }
784afa866b1Sguohongyu  }
7851d8f4dcbSJay}
786