xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala (revision 2a6078bf8d0c980824a4d361e4382e06eafff95b)
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
191d8f4dcbSJayimport chipsalliance.rocketchip.config.Parameters
201d8f4dcbSJayimport chisel3._
211d8f4dcbSJayimport chisel3.util._
221d8f4dcbSJayimport freechips.rocketchip.diplomacy.IdRange
231d8f4dcbSJayimport freechips.rocketchip.tilelink.ClientStates._
241d8f4dcbSJayimport freechips.rocketchip.tilelink.TLPermissions._
251d8f4dcbSJayimport freechips.rocketchip.tilelink._
261d8f4dcbSJayimport xiangshan._
271d8f4dcbSJayimport huancun.{AliasKey, DirtyKey}
281d8f4dcbSJayimport xiangshan.cache._
291d8f4dcbSJayimport utils._
303c02ee8fSwakafaimport utility._
3141cb8b61SJeniusimport difftest._
321d8f4dcbSJay
331d8f4dcbSJay
341d8f4dcbSJayabstract class ICacheMissUnitModule(implicit p: Parameters) extends XSModule
351d8f4dcbSJay  with HasICacheParameters
361d8f4dcbSJay
371d8f4dcbSJayabstract class ICacheMissUnitBundle(implicit p: Parameters) extends XSBundle
381d8f4dcbSJay  with HasICacheParameters
391d8f4dcbSJay
401d8f4dcbSJayclass ICacheMissReq(implicit p: Parameters) extends ICacheBundle
411d8f4dcbSJay{
421d8f4dcbSJay    val paddr      = UInt(PAddrBits.W)
431d8f4dcbSJay    val vaddr      = UInt(VAddrBits.W)
441d8f4dcbSJay    val waymask   = UInt(nWays.W)
451d8f4dcbSJay
461d8f4dcbSJay    def getVirSetIdx = get_idx(vaddr)
471d8f4dcbSJay    def getPhyTag    = get_phy_tag(paddr)
481d8f4dcbSJay}
491d8f4dcbSJay
501d8f4dcbSJay
511d8f4dcbSJayclass ICacheMissResp(implicit p: Parameters) extends ICacheBundle
521d8f4dcbSJay{
531d8f4dcbSJay    val data     = UInt(blockBits.W)
5458dbdfc2SJay    val corrupt  = Bool()
551d8f4dcbSJay}
561d8f4dcbSJay
571d8f4dcbSJayclass ICacheMissBundle(implicit p: Parameters) extends ICacheBundle{
581d8f4dcbSJay    val req       =   Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
591d8f4dcbSJay    val resp      =   Vec(2,ValidIO(new ICacheMissResp))
601d8f4dcbSJay    val flush     =   Input(Bool())
611d8f4dcbSJay}
621d8f4dcbSJay
631d8f4dcbSJay
641d8f4dcbSJayclass ICacheMissEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule
651d8f4dcbSJay  with MemoryOpConstants
661d8f4dcbSJay{
671d8f4dcbSJay  val io = IO(new Bundle {
687052722fSJay    val id = Input(UInt(log2Ceil(PortNumber).W))
691d8f4dcbSJay
701d8f4dcbSJay    val req = Flipped(DecoupledIO(new ICacheMissReq))
711d8f4dcbSJay    val resp = ValidIO(new ICacheMissResp)
721d8f4dcbSJay
731d8f4dcbSJay    //tilelink channel
741d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
751d8f4dcbSJay    val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
761d8f4dcbSJay
771d8f4dcbSJay    val meta_write = DecoupledIO(new ICacheMetaWriteBundle)
781d8f4dcbSJay    val data_write = DecoupledIO(new ICacheDataWriteBundle)
791d8f4dcbSJay
80974a902cSguohongyu    val ongoing_req    = ValidIO(UInt(PAddrBits.W))
81*2a6078bfSguohongyu    val fencei = Input(Bool())
821d8f4dcbSJay  })
831d8f4dcbSJay
841d8f4dcbSJay  /** default value for control signals */
851d8f4dcbSJay  io.resp := DontCare
861d8f4dcbSJay  io.mem_acquire.bits := DontCare
871d8f4dcbSJay  io.mem_grant.ready := true.B
881d8f4dcbSJay  io.meta_write.bits := DontCare
891d8f4dcbSJay  io.data_write.bits := DontCare
901d8f4dcbSJay
9138160951Sguohongyu  val s_idle  :: s_send_mem_aquire :: s_wait_mem_grant :: s_write_back :: s_wait_resp :: Nil = Enum(5)
921d8f4dcbSJay  val state = RegInit(s_idle)
931d8f4dcbSJay  /** control logic transformation */
941d8f4dcbSJay  //request register
951d8f4dcbSJay  val req = Reg(new ICacheMissReq)
961d8f4dcbSJay  val req_idx = req.getVirSetIdx //virtual index
971d8f4dcbSJay  val req_tag = req.getPhyTag //physical tag
981d8f4dcbSJay  val req_waymask = req.waymask
9958dbdfc2SJay  val req_corrupt = RegInit(false.B)
1001d8f4dcbSJay
1011d8f4dcbSJay  val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
1021d8f4dcbSJay
103*2a6078bfSguohongyu  val needflush_r = RegInit(false.B)
104*2a6078bfSguohongyu  when (state === s_idle) { needflush_r := false.B }
105*2a6078bfSguohongyu  when (state =/= s_idle && io.fencei) { needflush_r := true.B }
106*2a6078bfSguohongyu  val needflush = needflush_r | io.fencei
107*2a6078bfSguohongyu
1081d8f4dcbSJay  //cacheline register
1091d8f4dcbSJay  val readBeatCnt = Reg(UInt(log2Up(refillCycles).W))
1101d8f4dcbSJay  val respDataReg = Reg(Vec(refillCycles, UInt(beatBits.W)))
1111d8f4dcbSJay
1121d8f4dcbSJay  //initial
1131d8f4dcbSJay  io.resp.bits := DontCare
1141d8f4dcbSJay  io.mem_acquire.bits := DontCare
1151d8f4dcbSJay  io.mem_grant.ready := true.B
1161d8f4dcbSJay  io.meta_write.bits := DontCare
1171d8f4dcbSJay  io.data_write.bits := DontCare
1181d8f4dcbSJay
1191d8f4dcbSJay  io.req.ready := (state === s_idle)
1202a25dbb4SJay  io.mem_acquire.valid := (state === s_send_mem_aquire)
1211d8f4dcbSJay
122974a902cSguohongyu  io.ongoing_req.valid := (state =/= s_idle)
123974a902cSguohongyu  io.ongoing_req.bits  :=  addrAlign(req.paddr, blockBytes, PAddrBits)
12400240ba6SJay
1251d8f4dcbSJay  //state change
1261d8f4dcbSJay  switch(state) {
1271d8f4dcbSJay    is(s_idle) {
1281d8f4dcbSJay      when(io.req.fire()) {
1291d8f4dcbSJay        readBeatCnt := 0.U
1301d8f4dcbSJay        state := s_send_mem_aquire
1311d8f4dcbSJay        req := io.req.bits
1321d8f4dcbSJay      }
1331d8f4dcbSJay    }
1341d8f4dcbSJay
1351d8f4dcbSJay    // memory request
1361d8f4dcbSJay    is(s_send_mem_aquire) {
1371d8f4dcbSJay      when(io.mem_acquire.fire()) {
1381d8f4dcbSJay        state := s_wait_mem_grant
1391d8f4dcbSJay      }
1401d8f4dcbSJay    }
1411d8f4dcbSJay
1421d8f4dcbSJay    is(s_wait_mem_grant) {
1431d8f4dcbSJay      when(edge.hasData(io.mem_grant.bits)) {
1441d8f4dcbSJay        when(io.mem_grant.fire()) {
1451d8f4dcbSJay          readBeatCnt := readBeatCnt + 1.U
1461d8f4dcbSJay          respDataReg(readBeatCnt) := io.mem_grant.bits.data
14738160951Sguohongyu          req_corrupt := io.mem_grant.bits.corrupt // TODO: seems has bug
1481d8f4dcbSJay          when(readBeatCnt === (refillCycles - 1).U) {
1491d8f4dcbSJay            assert(refill_done, "refill not done!")
1504da04e5bSguohongyu            state := s_write_back
1511d8f4dcbSJay          }
1521d8f4dcbSJay        }
1531d8f4dcbSJay      }
1541d8f4dcbSJay    }
1551d8f4dcbSJay
1562a25dbb4SJay    is(s_write_back) {
157*2a6078bfSguohongyu      state := Mux(io.meta_write.fire() && io.data_write.fire() || needflush, s_wait_resp, s_write_back)
1582a25dbb4SJay    }
1592a25dbb4SJay
1601d8f4dcbSJay    is(s_wait_resp) {
1611d8f4dcbSJay      io.resp.bits.data := respDataReg.asUInt
16258dbdfc2SJay      io.resp.bits.corrupt := req_corrupt
1631d8f4dcbSJay      when(io.resp.fire()) {
1641d8f4dcbSJay        state := s_idle
1651d8f4dcbSJay      }
1661d8f4dcbSJay    }
1671d8f4dcbSJay  }
1681d8f4dcbSJay
1691d8f4dcbSJay  /** refill write and meta write */
17038160951Sguohongyu
17138160951Sguohongyu  val getBlock = edge.Get(
17238160951Sguohongyu    fromSource = io.id,
17338160951Sguohongyu    toAddress = addrAlign(req.paddr, blockBytes, PAddrBits),
17438160951Sguohongyu    lgSize = (log2Up(cacheParams.blockBytes)).U
17538160951Sguohongyu  )._2
17638160951Sguohongyu
1774da04e5bSguohongyu  io.mem_acquire.bits := getBlock // getBlock
1781d8f4dcbSJay  require(nSets <= 256) // icache size should not be more than 128KB
1791d8f4dcbSJay
1801d8f4dcbSJay  //resp to ifu
1811d8f4dcbSJay  io.resp.valid := state === s_wait_resp
1822a25dbb4SJay
183*2a6078bfSguohongyu  io.meta_write.valid := (state === s_write_back && !needflush)
1844da04e5bSguohongyu  io.meta_write.bits.generate(tag = req_tag, idx = req_idx, waymask = req_waymask, bankIdx = req_idx(0))
1852a25dbb4SJay
186*2a6078bfSguohongyu  io.data_write.valid := (state === s_write_back && !needflush)
18741cb8b61SJenius  io.data_write.bits.generate(data = respDataReg.asUInt,
18841cb8b61SJenius                              idx  = req_idx,
18941cb8b61SJenius                              waymask = req_waymask,
19041cb8b61SJenius                              bankIdx = req_idx(0),
19141cb8b61SJenius                              paddr = req.paddr)
1921d8f4dcbSJay
1931d8f4dcbSJay  XSPerfAccumulate(
1941d8f4dcbSJay    "entryPenalty" + Integer.toString(id, 10),
1951d8f4dcbSJay    BoolStopWatch(
1961d8f4dcbSJay      start = io.req.fire(),
1971d8f4dcbSJay      stop = io.resp.valid,
1981d8f4dcbSJay      startHighPriority = true)
1991d8f4dcbSJay  )
2001d8f4dcbSJay  XSPerfAccumulate("entryReq" + Integer.toString(id, 10), io.req.fire())
2015470b21eSguohongyu  XSError(blockCounter(io.req.fire, io.resp.fire, 5000), "missEntry"+ io.id +"_block_5000_cycle,may_has_error\n")
2021d8f4dcbSJay}
2031d8f4dcbSJay
2041d8f4dcbSJay
2051d8f4dcbSJayclass ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMissUnitModule
2061d8f4dcbSJay{
2071d8f4dcbSJay  val io = IO(new Bundle{
20841cb8b61SJenius    val hartId      = Input(UInt(8.W))
2091d8f4dcbSJay    val req         = Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
2101d8f4dcbSJay    val resp        = Vec(2, ValidIO(new ICacheMissResp))
2111d8f4dcbSJay
2121d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
2131d8f4dcbSJay    val mem_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
2141d8f4dcbSJay
2151d8f4dcbSJay    val meta_write  = DecoupledIO(new ICacheMetaWriteBundle)
2161d8f4dcbSJay    val data_write  = DecoupledIO(new ICacheDataWriteBundle)
2171d8f4dcbSJay
2187052722fSJay    val prefetch_req          =  Flipped(DecoupledIO(new PIQReq))
219974a902cSguohongyu    val mshr_info             =  Vec(totalMSHRNum,ValidIO(UInt(PAddrBits.W)))
220b1ded4e8Sguohongyu    val freePIQEntry          =  Output(UInt(log2Ceil(nPrefetchEntries).W))
22100240ba6SJay
222b1ded4e8Sguohongyu    val fencei = Input(Bool())
2237052722fSJay
224b1ded4e8Sguohongyu    val piq_write_ipbuffer = ValidIO(new IPFBufferWrite)
225b1ded4e8Sguohongyu
226b1ded4e8Sguohongyu    val to_main_pipe = Vec(nPrefetchEntries, new PIQToMainPipe)
2271d8f4dcbSJay  })
2281d8f4dcbSJay  // assign default values to output signals
2291d8f4dcbSJay  io.mem_grant.ready := false.B
2301d8f4dcbSJay
2311d8f4dcbSJay  val meta_write_arb = Module(new Arbiter(new ICacheMetaWriteBundle,  PortNumber))
2321d8f4dcbSJay  val refill_arb     = Module(new Arbiter(new ICacheDataWriteBundle,  PortNumber))
233b1ded4e8Sguohongyu  val ipf_write_arb  = Module(new Arbiter(new IPFBufferWrite,  nPrefetchEntries))
2341d8f4dcbSJay
2351d8f4dcbSJay  io.mem_grant.ready := true.B
2361d8f4dcbSJay
2372a25dbb4SJay  val entries = (0 until PortNumber) map { i =>
2381d8f4dcbSJay    val entry = Module(new ICacheMissEntry(edge, i))
2391d8f4dcbSJay
2401d8f4dcbSJay    entry.io.id := i.U
2411d8f4dcbSJay
2421d8f4dcbSJay    // entry req
2431d8f4dcbSJay    entry.io.req.valid := io.req(i).valid
2441d8f4dcbSJay    entry.io.req.bits  := io.req(i).bits
2451d8f4dcbSJay    io.req(i).ready    := entry.io.req.ready
2461d8f4dcbSJay
2471d8f4dcbSJay    // entry resp
2481d8f4dcbSJay    meta_write_arb.io.in(i)     <>  entry.io.meta_write
2491d8f4dcbSJay    refill_arb.io.in(i)         <>  entry.io.data_write
2501d8f4dcbSJay
2511d8f4dcbSJay    entry.io.mem_grant.valid := false.B
2521d8f4dcbSJay    entry.io.mem_grant.bits  := DontCare
2531d8f4dcbSJay    when (io.mem_grant.bits.source === i.U) {
2541d8f4dcbSJay      entry.io.mem_grant <> io.mem_grant
2551d8f4dcbSJay    }
2561d8f4dcbSJay
2571d8f4dcbSJay    io.resp(i) <> entry.io.resp
258974a902cSguohongyu    io.mshr_info(i) <> entry.io.ongoing_req
259*2a6078bfSguohongyu    entry.io.fencei := io.fencei
260d4112e88Sguohongyu//    XSPerfAccumulate(
261d4112e88Sguohongyu//      "entryPenalty" + Integer.toString(i, 10),
262d4112e88Sguohongyu//      BoolStopWatch(
263d4112e88Sguohongyu//        start = entry.io.req.fire(),
264d4112e88Sguohongyu//        stop = entry.io.resp.fire(),
265d4112e88Sguohongyu//        startHighPriority = true)
266d4112e88Sguohongyu//    )
267d4112e88Sguohongyu//    XSPerfAccumulate("entryReq" + Integer.toString(i, 10), entry.io.req.fire())
2681d8f4dcbSJay
2691d8f4dcbSJay    entry
2701d8f4dcbSJay  }
2711d8f4dcbSJay
2727052722fSJay  val alloc = Wire(UInt(log2Ceil(nPrefetchEntries).W))
273b1ded4e8Sguohongyu  val toMainPipe = io.to_main_pipe.map(_.info)
2747052722fSJay
275de7689fcSJay  val prefEntries = (PortNumber until PortNumber + nPrefetchEntries) map { i =>
276b1ded4e8Sguohongyu    val prefetchEntry = Module(new PIQEntry(edge, i))
2777052722fSJay
278b1ded4e8Sguohongyu    prefetchEntry.io.mem_grant.valid := false.B
279b1ded4e8Sguohongyu    prefetchEntry.io.mem_grant.bits := DontCare
280b1ded4e8Sguohongyu    prefetchEntry.io.fencei := io.fencei
2817052722fSJay
282b1ded4e8Sguohongyu    ipf_write_arb.io.in(i - PortNumber) <> prefetchEntry.io.piq_write_ipbuffer
283b1ded4e8Sguohongyu
284b1ded4e8Sguohongyu    when(io.mem_grant.bits.source === i.U) {
285b1ded4e8Sguohongyu      prefetchEntry.io.mem_grant <> io.mem_grant
2867052722fSJay    }
2877052722fSJay
288de7689fcSJay    prefetchEntry.io.req.valid := io.prefetch_req.valid && ((i-PortNumber).U === alloc)
2897052722fSJay    prefetchEntry.io.req.bits  := io.prefetch_req.bits
2907052722fSJay
2917052722fSJay    prefetchEntry.io.id := i.U
2927052722fSJay
293974a902cSguohongyu    io.mshr_info(i) := prefetchEntry.io.ongoing_req
294974a902cSguohongyu
2957052722fSJay    prefetchEntry
2967052722fSJay  }
2977052722fSJay
2987052722fSJay  alloc := PriorityEncoder(prefEntries.map(_.io.req.ready))
2997052722fSJay  io.prefetch_req.ready := ParallelOR(prefEntries.map(_.io.req.ready))
300b1ded4e8Sguohongyu  io.freePIQEntry := PriorityEncoder(prefEntries.map(_.io.req.ready))
301b1ded4e8Sguohongyu  (0 until nPrefetchEntries).foreach(i => toMainPipe(i) <> prefEntries(i).io.prefetch_entry_data)
302b1ded4e8Sguohongyu  val tl_a_chanel = entries.map(_.io.mem_acquire) ++ prefEntries.map(_.io.mem_acquire)
3037052722fSJay  TLArbiter.lowest(edge, io.mem_acquire, tl_a_chanel:_*)
3047052722fSJay
3051d8f4dcbSJay  io.meta_write     <> meta_write_arb.io.out
3061d8f4dcbSJay  io.data_write     <> refill_arb.io.out
3071d8f4dcbSJay
308b1ded4e8Sguohongyu  io.piq_write_ipbuffer.valid := ipf_write_arb.io.out.valid
309b1ded4e8Sguohongyu  io.piq_write_ipbuffer.bits  := ipf_write_arb.io.out.bits
310b1ded4e8Sguohongyu  ipf_write_arb.io.out.ready := true.B
311b1ded4e8Sguohongyu
312b1ded4e8Sguohongyu  XSPerfAccumulate("refill_ipf_num", io.piq_write_ipbuffer.fire)
313b1ded4e8Sguohongyu
31441cb8b61SJenius  if (env.EnableDifftest) {
315afa866b1Sguohongyu    val diffipfrefill = Module(new DifftestRefillEvent)
316afa866b1Sguohongyu    diffipfrefill.io.clock := clock
317afa866b1Sguohongyu    diffipfrefill.io.coreid := io.hartId
318afa866b1Sguohongyu    diffipfrefill.io.cacheid := 3.U
319afa866b1Sguohongyu    diffipfrefill.io.valid := ipf_write_arb.io.out.valid
320afa866b1Sguohongyu    diffipfrefill.io.addr := ipf_write_arb.io.out.bits.meta.paddr
321afa866b1Sguohongyu    diffipfrefill.io.data := ipf_write_arb.io.out.bits.data.asTypeOf(diffipfrefill.io.data)
322afa866b1Sguohongyu  }
323afa866b1Sguohongyu
324afa866b1Sguohongyu  if (env.EnableDifftest) {
32541cb8b61SJenius    val difftest = Module(new DifftestRefillEvent)
32641cb8b61SJenius    difftest.io.clock := clock
32741cb8b61SJenius    difftest.io.coreid := io.hartId
32841cb8b61SJenius    difftest.io.cacheid := 0.U
32941cb8b61SJenius    difftest.io.valid := refill_arb.io.out.valid
33041cb8b61SJenius    difftest.io.addr := refill_arb.io.out.bits.paddr
33141cb8b61SJenius    difftest.io.data := refill_arb.io.out.bits.data.asTypeOf(difftest.io.data)
33241cb8b61SJenius  }
33341cb8b61SJenius
3341d8f4dcbSJay  (0 until nWays).map{ w =>
3351d8f4dcbSJay    XSPerfAccumulate("line_0_refill_way_" + Integer.toString(w, 10),  entries(0).io.meta_write.valid && OHToUInt(entries(0).io.meta_write.bits.waymask)  === w.U)
3361d8f4dcbSJay    XSPerfAccumulate("line_1_refill_way_" + Integer.toString(w, 10),  entries(1).io.meta_write.valid && OHToUInt(entries(1).io.meta_write.bits.waymask)  === w.U)
3371d8f4dcbSJay  }
3381d8f4dcbSJay
3391d8f4dcbSJay}
3401d8f4dcbSJay
3411d8f4dcbSJay
3421d8f4dcbSJay
343