xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/ICacheMissUnit.scala (revision 131aa97c36124d7dbbbbc940856cd61b4fdc9319)
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._
221d8f4dcbSJayimport freechips.rocketchip.diplomacy.IdRange
231d8f4dcbSJayimport freechips.rocketchip.tilelink.ClientStates._
241d8f4dcbSJayimport freechips.rocketchip.tilelink.TLPermissions._
251d8f4dcbSJayimport freechips.rocketchip.tilelink._
261d8f4dcbSJayimport xiangshan._
271d8f4dcbSJayimport xiangshan.cache._
281d8f4dcbSJayimport utils._
293c02ee8fSwakafaimport utility._
3041cb8b61SJeniusimport difftest._
311d8f4dcbSJay
321d8f4dcbSJay
331d8f4dcbSJayabstract class ICacheMissUnitModule(implicit p: Parameters) extends XSModule
341d8f4dcbSJay  with HasICacheParameters
351d8f4dcbSJay
361d8f4dcbSJayabstract class ICacheMissUnitBundle(implicit p: Parameters) extends XSBundle
371d8f4dcbSJay  with HasICacheParameters
381d8f4dcbSJay
391d8f4dcbSJayclass ICacheMissReq(implicit p: Parameters) extends ICacheBundle
401d8f4dcbSJay{
411d8f4dcbSJay    val paddr      = UInt(PAddrBits.W)
421d8f4dcbSJay    val vaddr      = UInt(VAddrBits.W)
431d8f4dcbSJay    val waymask   = UInt(nWays.W)
441d8f4dcbSJay
451d8f4dcbSJay    def getVirSetIdx = get_idx(vaddr)
461d8f4dcbSJay    def getPhyTag    = get_phy_tag(paddr)
471d8f4dcbSJay}
481d8f4dcbSJay
491d8f4dcbSJay
501d8f4dcbSJayclass ICacheMissResp(implicit p: Parameters) extends ICacheBundle
511d8f4dcbSJay{
521d8f4dcbSJay    val data     = UInt(blockBits.W)
5358dbdfc2SJay    val corrupt  = Bool()
541d8f4dcbSJay}
551d8f4dcbSJay
561d8f4dcbSJayclass ICacheMissBundle(implicit p: Parameters) extends ICacheBundle{
571d8f4dcbSJay    val req       =   Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
581d8f4dcbSJay    val resp      =   Vec(2,ValidIO(new ICacheMissResp))
591d8f4dcbSJay    val flush     =   Input(Bool())
601d8f4dcbSJay}
611d8f4dcbSJay
621d8f4dcbSJay
631d8f4dcbSJayclass ICacheMissEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule
641d8f4dcbSJay  with MemoryOpConstants
651d8f4dcbSJay{
661d8f4dcbSJay  val io = IO(new Bundle {
677052722fSJay    val id = Input(UInt(log2Ceil(PortNumber).W))
681d8f4dcbSJay
691d8f4dcbSJay    val req = Flipped(DecoupledIO(new ICacheMissReq))
701d8f4dcbSJay    val resp = ValidIO(new ICacheMissResp)
711d8f4dcbSJay
721d8f4dcbSJay    //tilelink channel
731d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
741d8f4dcbSJay    val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
751d8f4dcbSJay
761d8f4dcbSJay    val meta_write = DecoupledIO(new ICacheMetaWriteBundle)
771d8f4dcbSJay    val data_write = DecoupledIO(new ICacheDataWriteBundle)
781d8f4dcbSJay
7958c354d0Sssszwic    val ongoing_req    = Output(new FilterInfo)
802a6078bfSguohongyu    val fencei = Input(Bool())
811d8f4dcbSJay  })
821d8f4dcbSJay
831d8f4dcbSJay  /** default value for control signals */
841d8f4dcbSJay  io.resp := DontCare
851d8f4dcbSJay  io.mem_acquire.bits := DontCare
861d8f4dcbSJay  io.mem_grant.ready := true.B
871d8f4dcbSJay  io.meta_write.bits := DontCare
881d8f4dcbSJay  io.data_write.bits := DontCare
891d8f4dcbSJay
90*131aa97cSssszwic  val s_idle  :: s_send_mem_aquire :: s_wait_mem_grant :: s_write_back_wait_resp :: s_write_back :: s_wait_resp :: Nil = Enum(6)
911d8f4dcbSJay  val state = RegInit(s_idle)
921d8f4dcbSJay  /** control logic transformation */
931d8f4dcbSJay  //request register
941d8f4dcbSJay  val req = Reg(new ICacheMissReq)
951d8f4dcbSJay  val req_idx = req.getVirSetIdx //virtual index
961d8f4dcbSJay  val req_tag = req.getPhyTag //physical tag
971d8f4dcbSJay  val req_waymask = req.waymask
9858dbdfc2SJay  val req_corrupt = RegInit(false.B)
991d8f4dcbSJay
1001d8f4dcbSJay  val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant)
1011d8f4dcbSJay
1022a6078bfSguohongyu  val needflush_r = RegInit(false.B)
1032a6078bfSguohongyu  when (state === s_idle) { needflush_r := false.B }
1042a6078bfSguohongyu  when (state =/= s_idle && io.fencei) { needflush_r := true.B }
1052a6078bfSguohongyu  val needflush = needflush_r | io.fencei
1062a6078bfSguohongyu
1071d8f4dcbSJay  //cacheline register
1081d8f4dcbSJay  val readBeatCnt = Reg(UInt(log2Up(refillCycles).W))
1091d8f4dcbSJay  val respDataReg = Reg(Vec(refillCycles, UInt(beatBits.W)))
1101d8f4dcbSJay
1111d8f4dcbSJay  //initial
1121d8f4dcbSJay  io.resp.bits := DontCare
1131d8f4dcbSJay  io.mem_acquire.bits := DontCare
1141d8f4dcbSJay  io.mem_grant.ready := true.B
1151d8f4dcbSJay  io.meta_write.bits := DontCare
1161d8f4dcbSJay  io.data_write.bits := DontCare
1171d8f4dcbSJay
1181d8f4dcbSJay  io.req.ready := (state === s_idle)
1192a25dbb4SJay  io.mem_acquire.valid := (state === s_send_mem_aquire)
1201d8f4dcbSJay
121974a902cSguohongyu  io.ongoing_req.valid := (state =/= s_idle)
12258c354d0Sssszwic  io.ongoing_req.paddr :=  addrAlign(req.paddr, blockBytes, PAddrBits)
12300240ba6SJay
1241d8f4dcbSJay  //state change
1251d8f4dcbSJay  switch(state) {
1261d8f4dcbSJay    is(s_idle) {
127935edac4STang Haojin      when(io.req.fire) {
1281d8f4dcbSJay        readBeatCnt := 0.U
1291d8f4dcbSJay        state := s_send_mem_aquire
1301d8f4dcbSJay        req := io.req.bits
1311d8f4dcbSJay      }
1321d8f4dcbSJay    }
1331d8f4dcbSJay
1341d8f4dcbSJay    // memory request
1351d8f4dcbSJay    is(s_send_mem_aquire) {
136935edac4STang Haojin      when(io.mem_acquire.fire) {
1371d8f4dcbSJay        state := s_wait_mem_grant
1381d8f4dcbSJay      }
1391d8f4dcbSJay    }
1401d8f4dcbSJay
1411d8f4dcbSJay    is(s_wait_mem_grant) {
1421d8f4dcbSJay      when(edge.hasData(io.mem_grant.bits)) {
143935edac4STang Haojin        when(io.mem_grant.fire) {
1441d8f4dcbSJay          readBeatCnt := readBeatCnt + 1.U
1451d8f4dcbSJay          respDataReg(readBeatCnt) := io.mem_grant.bits.data
14638160951Sguohongyu          req_corrupt := io.mem_grant.bits.corrupt // TODO: seems has bug
1471d8f4dcbSJay          when(readBeatCnt === (refillCycles - 1).U) {
1481d8f4dcbSJay            assert(refill_done, "refill not done!")
149*131aa97cSssszwic            state := s_write_back_wait_resp
150*131aa97cSssszwic          }
151*131aa97cSssszwic        }
152*131aa97cSssszwic      }
153*131aa97cSssszwic    }
154*131aa97cSssszwic
155*131aa97cSssszwic    is(s_write_back_wait_resp) {
156*131aa97cSssszwic      when((io.meta_write.fire && io.data_write.fire || needflush) && io.resp.fire) {
157*131aa97cSssszwic        state := s_idle
158*131aa97cSssszwic      }.elsewhen(io.meta_write.fire && io.data_write.fire || needflush) {
159*131aa97cSssszwic        state := s_wait_resp
160*131aa97cSssszwic      }.elsewhen(io.resp.fire) {
1614da04e5bSguohongyu        state := s_write_back
1621d8f4dcbSJay      }
1631d8f4dcbSJay    }
1641d8f4dcbSJay
1652a25dbb4SJay    is(s_write_back) {
166*131aa97cSssszwic      when(io.meta_write.fire && io.data_write.fire || needflush) {
167*131aa97cSssszwic        state := s_idle
168*131aa97cSssszwic      }
1692a25dbb4SJay    }
1702a25dbb4SJay
1711d8f4dcbSJay    is(s_wait_resp) {
172935edac4STang Haojin      when(io.resp.fire) {
1731d8f4dcbSJay        state := s_idle
1741d8f4dcbSJay      }
1751d8f4dcbSJay    }
1761d8f4dcbSJay  }
1771d8f4dcbSJay
1781d8f4dcbSJay  /** refill write and meta write */
17938160951Sguohongyu
18038160951Sguohongyu  val getBlock = edge.Get(
18138160951Sguohongyu    fromSource = io.id,
18238160951Sguohongyu    toAddress = addrAlign(req.paddr, blockBytes, PAddrBits),
18338160951Sguohongyu    lgSize = (log2Up(cacheParams.blockBytes)).U
18438160951Sguohongyu  )._2
18538160951Sguohongyu
1864da04e5bSguohongyu  io.mem_acquire.bits := getBlock // getBlock
187d2b20d1aSTang Haojin  // req source
188d2b20d1aSTang Haojin  io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.CPUInst.id.U)
1891d8f4dcbSJay  require(nSets <= 256) // icache size should not be more than 128KB
1901d8f4dcbSJay
1911d8f4dcbSJay  //resp to ifu
192*131aa97cSssszwic  io.resp.valid := (state === s_wait_resp) || (state === s_write_back_wait_resp)
1932a25dbb4SJay
194*131aa97cSssszwic  io.resp.bits.data := respDataReg.asUInt
195*131aa97cSssszwic  io.resp.bits.corrupt := req_corrupt
196*131aa97cSssszwic
197*131aa97cSssszwic  io.meta_write.valid := (((state === s_write_back) || (state === s_write_back_wait_resp)) && !needflush)
1984da04e5bSguohongyu  io.meta_write.bits.generate(tag = req_tag, idx = req_idx, waymask = req_waymask, bankIdx = req_idx(0))
1992a25dbb4SJay
200*131aa97cSssszwic  io.data_write.valid := (((state === s_write_back) || (state === s_write_back_wait_resp)) && !needflush)
20141cb8b61SJenius  io.data_write.bits.generate(data = respDataReg.asUInt,
20241cb8b61SJenius                              idx  = req_idx,
20341cb8b61SJenius                              waymask = req_waymask,
20441cb8b61SJenius                              bankIdx = req_idx(0),
20541cb8b61SJenius                              paddr = req.paddr)
2061d8f4dcbSJay
2071d8f4dcbSJay  XSPerfAccumulate(
2081d8f4dcbSJay    "entryPenalty" + Integer.toString(id, 10),
2091d8f4dcbSJay    BoolStopWatch(
210935edac4STang Haojin      start = io.req.fire,
2111d8f4dcbSJay      stop = io.resp.valid,
2121d8f4dcbSJay      startHighPriority = true)
2131d8f4dcbSJay  )
214935edac4STang Haojin  XSPerfAccumulate("entryReq" + Integer.toString(id, 10), io.req.fire)
21558c354d0Sssszwic
21658c354d0Sssszwic  // Statistics on the latency distribution of MSHR
21758c354d0Sssszwic  val cntLatency = RegInit(0.U(32.W))
21858c354d0Sssszwic  cntLatency := Mux(io.mem_acquire.fire, 1.U, cntLatency + 1.U)
21958c354d0Sssszwic  // the condition is same as the transition from s_wait_mem_grant to s_write_back
22058c354d0Sssszwic  val cntEnable = (state === s_wait_mem_grant) && edge.hasData(io.mem_grant.bits) &&
22158c354d0Sssszwic                  io.mem_grant.fire && (readBeatCnt === (refillCycles - 1).U)
22258c354d0Sssszwic  XSPerfHistogram("icache_mshr_latency_" + id.toString(), cntLatency, cntEnable, 0, 300, 10, right_strict = true)
2231d8f4dcbSJay}
2241d8f4dcbSJay
2251d8f4dcbSJay
2261d8f4dcbSJayclass ICacheMissUnit(edge: TLEdgeOut)(implicit p: Parameters) extends ICacheMissUnitModule
2271d8f4dcbSJay{
2281d8f4dcbSJay  val io = IO(new Bundle{
22941cb8b61SJenius    val hartId      = Input(UInt(8.W))
2301d8f4dcbSJay    val req         = Vec(2, Flipped(DecoupledIO(new ICacheMissReq)))
2311d8f4dcbSJay    val resp        = Vec(2, ValidIO(new ICacheMissResp))
2321d8f4dcbSJay
2331d8f4dcbSJay    val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle))
2341d8f4dcbSJay    val mem_grant   = Flipped(DecoupledIO(new TLBundleD(edge.bundle)))
2351d8f4dcbSJay
236cb6e5d3cSssszwic    val fdip_acquire = Flipped(DecoupledIO(new TLBundleA(edge.bundle)))
237cb6e5d3cSssszwic    val fdip_grant   = DecoupledIO(new TLBundleD(edge.bundle))
238cb6e5d3cSssszwic
2391d8f4dcbSJay    val meta_write  = DecoupledIO(new ICacheMetaWriteBundle)
2401d8f4dcbSJay    val data_write  = DecoupledIO(new ICacheDataWriteBundle)
2411d8f4dcbSJay
24258c354d0Sssszwic    val ICacheMissUnitInfo = new ICacheMissUnitInfo
243b1ded4e8Sguohongyu    val fencei = Input(Bool())
2441d8f4dcbSJay  })
2451d8f4dcbSJay  // assign default values to output signals
2461d8f4dcbSJay  io.mem_grant.ready := false.B
2471d8f4dcbSJay
2481d8f4dcbSJay  val meta_write_arb = Module(new Arbiter(new ICacheMetaWriteBundle,  PortNumber))
2491d8f4dcbSJay  val refill_arb     = Module(new Arbiter(new ICacheDataWriteBundle,  PortNumber))
2501d8f4dcbSJay
2511d8f4dcbSJay  io.mem_grant.ready := true.B
2521d8f4dcbSJay
2532a25dbb4SJay  val entries = (0 until PortNumber) map { i =>
2541d8f4dcbSJay    val entry = Module(new ICacheMissEntry(edge, i))
2551d8f4dcbSJay
2561d8f4dcbSJay    entry.io.id := i.U
2571d8f4dcbSJay
2581d8f4dcbSJay    // entry req
2591d8f4dcbSJay    entry.io.req.valid := io.req(i).valid
2601d8f4dcbSJay    entry.io.req.bits  := io.req(i).bits
2611d8f4dcbSJay    io.req(i).ready    := entry.io.req.ready
2621d8f4dcbSJay
2631d8f4dcbSJay    // entry resp
2641d8f4dcbSJay    meta_write_arb.io.in(i)     <>  entry.io.meta_write
2651d8f4dcbSJay    refill_arb.io.in(i)         <>  entry.io.data_write
2661d8f4dcbSJay
2671d8f4dcbSJay    entry.io.mem_grant.valid := false.B
2681d8f4dcbSJay    entry.io.mem_grant.bits  := DontCare
2691d8f4dcbSJay    when (io.mem_grant.bits.source === i.U) {
2701d8f4dcbSJay      entry.io.mem_grant <> io.mem_grant
2711d8f4dcbSJay    }
2721d8f4dcbSJay
2731d8f4dcbSJay    io.resp(i) <> entry.io.resp
27458c354d0Sssszwic    io.ICacheMissUnitInfo.mshr(i) <> entry.io.ongoing_req
2752a6078bfSguohongyu    entry.io.fencei := io.fencei
276d4112e88Sguohongyu//    XSPerfAccumulate(
277d4112e88Sguohongyu//      "entryPenalty" + Integer.toString(i, 10),
278d4112e88Sguohongyu//      BoolStopWatch(
279935edac4STang Haojin//        start = entry.io.req.fire,
280935edac4STang Haojin//        stop = entry.io.resp.fire,
281d4112e88Sguohongyu//        startHighPriority = true)
282d4112e88Sguohongyu//    )
283935edac4STang Haojin//    XSPerfAccumulate("entryReq" + Integer.toString(i, 10), entry.io.req.fire)
2841d8f4dcbSJay
2851d8f4dcbSJay    entry
2861d8f4dcbSJay  }
2871d8f4dcbSJay
288cb6e5d3cSssszwic  io.fdip_grant.valid := false.B
289cb6e5d3cSssszwic  io.fdip_grant.bits  := DontCare
290cb6e5d3cSssszwic  when (io.mem_grant.bits.source === PortNumber.U) {
291cb6e5d3cSssszwic    io.fdip_grant <> io.mem_grant
2927052722fSJay  }
2937052722fSJay
29458c354d0Sssszwic  /**
29558c354d0Sssszwic    ******************************************************************************
29658c354d0Sssszwic    * Register 2 cycle meta write info for IPrefetchPipe filter
29758c354d0Sssszwic    ******************************************************************************
29858c354d0Sssszwic    */
29958c354d0Sssszwic  val meta_write_buffer = InitQueue(new FilterInfo, size = 2)
30058c354d0Sssszwic  meta_write_buffer(0).valid := io.meta_write.fire
30158c354d0Sssszwic  meta_write_buffer(0).paddr := io.data_write.bits.paddr
30258c354d0Sssszwic  meta_write_buffer(1)       := meta_write_buffer(0)
30358c354d0Sssszwic  (0 until 2).foreach (i => {
30458c354d0Sssszwic    io.ICacheMissUnitInfo.recentWrite(i) := meta_write_buffer(i)
30558c354d0Sssszwic  })
30658c354d0Sssszwic
307cb6e5d3cSssszwic  val tl_a_chanel = entries.map(_.io.mem_acquire) :+ io.fdip_acquire
3087052722fSJay  TLArbiter.lowest(edge, io.mem_acquire, tl_a_chanel:_*)
3097052722fSJay
3101d8f4dcbSJay  io.meta_write     <> meta_write_arb.io.out
3111d8f4dcbSJay  io.data_write     <> refill_arb.io.out
3121d8f4dcbSJay
313afa866b1Sguohongyu  if (env.EnableDifftest) {
314a0c65233SYinan Xu    val difftest = DifftestModule(new DiffRefillEvent, dontCare = true)
3157d45a146SYinan Xu    difftest.coreid := io.hartId
3167d45a146SYinan Xu    difftest.index := 0.U
3177d45a146SYinan Xu    difftest.valid := refill_arb.io.out.valid
3187d45a146SYinan Xu    difftest.addr := refill_arb.io.out.bits.paddr
3197d45a146SYinan Xu    difftest.data := refill_arb.io.out.bits.data.asTypeOf(difftest.data)
320935edac4STang Haojin    difftest.idtfr := DontCare
32141cb8b61SJenius  }
32241cb8b61SJenius
3231d8f4dcbSJay  (0 until nWays).map{ w =>
3241d8f4dcbSJay    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)
3251d8f4dcbSJay    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)
3261d8f4dcbSJay  }
3271d8f4dcbSJay
3281d8f4dcbSJay}
329