17052722fSJay/*************************************************************************************** 27052722fSJay * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 37052722fSJay * Copyright (c) 2020-2021 Peng Cheng Laboratory 47052722fSJay * 57052722fSJay * XiangShan is licensed under Mulan PSL v2. 67052722fSJay * You can use this software according to the terms and conditions of the Mulan PSL v2. 77052722fSJay * You may obtain a copy of Mulan PSL v2 at: 87052722fSJay * http://license.coscl.org.cn/MulanPSL2 97052722fSJay * 107052722fSJay * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 117052722fSJay * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 127052722fSJay * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 137052722fSJay * 147052722fSJay * See the Mulan PSL v2 for more details. 157052722fSJay ***************************************************************************************/ 167052722fSJay 177052722fSJaypackage xiangshan.frontend.icache 187052722fSJay 197052722fSJayimport chipsalliance.rocketchip.config.Parameters 207052722fSJayimport chisel3._ 217052722fSJayimport chisel3.util._ 227052722fSJayimport freechips.rocketchip.tilelink._ 237052722fSJayimport utils._ 247052722fSJayimport xiangshan.cache.mmu._ 257052722fSJayimport xiangshan.frontend._ 267052722fSJayimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle} 27de7689fcSJayimport huancun.{PreferCacheKey} 287052722fSJay 297052722fSJay 307052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle 317052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule 327052722fSJay 337052722fSJayclass PIQReq(implicit p: Parameters) extends IPrefetchBundle { 347052722fSJay val paddr = UInt(PAddrBits.W) 357052722fSJay} 367052722fSJay 377052722fSJay 387052722fSJayclass IPrefetchToMissUnit(implicit p: Parameters) extends IPrefetchBundle{ 397052722fSJay val enqReq = DecoupledIO(new PIQReq) 407052722fSJay} 417052722fSJay 427052722fSJayclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle { 437052722fSJay val fromFtq = Flipped(new FtqPrefechBundle) 44f1fe8698SLemover val iTLBInter = new TlbRequestIO 4561e1db30SJay val pmp = new ICachePMPBundle 467052722fSJay val toIMeta = Decoupled(new ICacheReadBundle) 477052722fSJay val fromIMeta = Input(new ICacheMetaRespBundle) 487052722fSJay val toMissUnit = new IPrefetchToMissUnit 4900240ba6SJay val fromMSHR = Flipped(Vec(PortNumber,ValidIO(UInt(PAddrBits.W)))) 50a108d429SJay 51a108d429SJay val prefetchEnable = Input(Bool()) 52a108d429SJay val prefetchDisable = Input(Bool()) 537052722fSJay} 547052722fSJay 557052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule 567052722fSJay{ 577052722fSJay val io = IO(new IPredfetchIO) 587052722fSJay 59a108d429SJay val enableBit = RegInit(false.B) 60a108d429SJay val maxPrefetchCoutner = RegInit(0.U(log2Ceil(nPrefetchEntries + 1).W)) 61a108d429SJay 62a108d429SJay val reachMaxSize = maxPrefetchCoutner === nPrefetchEntries.U 63a108d429SJay 64a108d429SJay when(io.prefetchEnable){ 65a108d429SJay enableBit := true.B 66a108d429SJay }.elsewhen((enableBit && io.prefetchDisable) || (enableBit && reachMaxSize)){ 67a108d429SJay enableBit := false.B 68a108d429SJay } 69a108d429SJay 70a108d429SJay class PrefetchDir(implicit p: Parameters) extends IPrefetchBundle 71a108d429SJay { 72a108d429SJay val valid = Bool() 73a108d429SJay val paddr = UInt(PAddrBits.W) 74a108d429SJay } 75a108d429SJay 76a108d429SJay val prefetch_dir = RegInit(VecInit(Seq.fill(nPrefetchEntries)(0.U.asTypeOf(new PrefetchDir)))) 77a108d429SJay 787052722fSJay val fromFtq = io.fromFtq 797052722fSJay val (toITLB, fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp) 80*c3b763d0SYinan Xu io.iTLBInter.req_kill := false.B 817052722fSJay val (toIMeta, fromIMeta) = (io.toIMeta, io.fromIMeta.metaData(0)) 827052722fSJay val (toPMP, fromPMP) = (io.pmp.req, io.pmp.resp) 837052722fSJay val toMissUnit = io.toMissUnit 847052722fSJay 857052722fSJay val p0_fire, p1_fire, p2_fire, p3_fire = WireInit(false.B) 867052722fSJay val p1_discard, p2_discard, p3_discard = WireInit(false.B) 877052722fSJay val p0_ready, p1_ready, p2_ready, p3_ready = WireInit(false.B) 887052722fSJay 897052722fSJay /** Prefetch Stage 0: req from Ftq */ 907052722fSJay val p0_valid = fromFtq.req.valid 91d6b06a99SJay val p0_vaddr = addrAlign(fromFtq.req.bits.target, blockBytes, VAddrBits) 92a108d429SJay p0_fire := p0_valid && p1_ready && toITLB.fire() && !fromITLB.bits.miss && toIMeta.ready && enableBit 93e8747464SJenius //discard req when source not ready 94e8747464SJenius // p0_discard := p0_valid && ((toITLB.fire() && fromITLB.bits.miss) || !toIMeta.ready || !enableBit) 957052722fSJay 967052722fSJay toIMeta.valid := p0_valid 977052722fSJay toIMeta.bits.vSetIdx(0) := get_idx(p0_vaddr) 987052722fSJay 997052722fSJay toIMeta.bits.vSetIdx(1) := DontCare 1007052722fSJay toIMeta.bits.isDoubleLine := false.B 1017052722fSJay 1027052722fSJay toITLB.valid := p0_valid 1037052722fSJay toITLB.bits.size := 3.U // TODO: fix the size 1047052722fSJay toITLB.bits.vaddr := p0_vaddr 1057052722fSJay toITLB.bits.debug.pc := p0_vaddr 1067052722fSJay 107f1fe8698SLemover toITLB.bits.kill := DontCare 1087052722fSJay toITLB.bits.cmd := TlbCmd.exec 109f1fe8698SLemover toITLB.bits.debug.robIdx := DontCare 1107052722fSJay toITLB.bits.debug.isFirstIssue := DontCare 1117052722fSJay 1127052722fSJay 1137052722fSJay fromITLB.ready := true.B 1147052722fSJay 115e8747464SJenius fromFtq.req.ready := true.B //(!enableBit || (enableBit && p3_ready)) && toIMeta.ready //&& GTimer() > 500.U 1167052722fSJay 1177052722fSJay /** Prefetch Stage 1: cache probe filter */ 1187052722fSJay val p1_valid = generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B) 1197052722fSJay 120005e809bSJiuyang Liu val p1_vaddr = RegEnable(p0_vaddr, p0_fire) 1217052722fSJay 1227052722fSJay //tlb resp 123de7689fcSJay val tlb_resp_valid = RegInit(false.B) 124de7689fcSJay when(p0_fire) {tlb_resp_valid := true.B} 125de7689fcSJay .elsewhen(tlb_resp_valid && (p1_fire || p1_discard)) {tlb_resp_valid := false.B} 1267052722fSJay 127de7689fcSJay val tlb_resp_paddr = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.paddr) 128de7689fcSJay val tlb_resp_pf = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp.pf.instr && tlb_resp_valid) 129de7689fcSJay val tlb_resp_af = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp.af.instr && tlb_resp_valid) 1307052722fSJay 1317052722fSJay val p1_exception = VecInit(Seq(tlb_resp_pf, tlb_resp_af)) 1327052722fSJay val p1_has_except = p1_exception.reduce(_ || _) 1337052722fSJay 1347052722fSJay val p1_ptag = get_phy_tag(tlb_resp_paddr) 1357052722fSJay 1367052722fSJay val p1_meta_ptags = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.tag)),valid = RegNext(p0_fire)) 1377052722fSJay val p1_meta_cohs = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.coh)),valid = RegNext(p0_fire)) 1387052722fSJay 1397052722fSJay val p1_tag_eq_vec = VecInit(p1_meta_ptags.map(_ === p1_ptag )) 1407052722fSJay val p1_tag_match_vec = VecInit(p1_tag_eq_vec.zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && p1_meta_cohs(w).isValid()}) 1417052722fSJay val p1_tag_match = ParallelOR(p1_tag_match_vec) 1427052722fSJay val (p1_hit, p1_miss) = (p1_valid && p1_tag_match && !p1_has_except, p1_valid && !p1_tag_match && !p1_has_except) 1437052722fSJay 1447052722fSJay //overriding the invalid req 1457052722fSJay val p1_req_cancle = (p1_hit || (tlb_resp_valid && p1_exception.reduce(_ || _))) && p1_valid 1467052722fSJay val p1_req_accept = p1_valid && tlb_resp_valid && p1_miss 1477052722fSJay 1487052722fSJay p1_ready := p1_fire || p1_req_cancle || !p1_valid 149a108d429SJay p1_fire := p1_valid && p1_req_accept && p2_ready && enableBit 1507052722fSJay p1_discard := p1_valid && p1_req_cancle 1517052722fSJay 1527052722fSJay /** Prefetch Stage 2: filtered req PIQ enqueue */ 1537052722fSJay val p2_valid = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B) 15461e1db30SJay val p2_pmp_fire = p2_valid 1557052722fSJay val pmpExcpAF = fromPMP.instr 1567052722fSJay 157005e809bSJiuyang Liu val p2_paddr = RegEnable(tlb_resp_paddr, p1_fire) 158005e809bSJiuyang Liu val p2_except_pf = RegEnable(tlb_resp_pf, p1_fire) 159005e809bSJiuyang Liu val p2_except_af = DataHoldBypass(pmpExcpAF, p2_pmp_fire) || RegEnable(tlb_resp_af, p1_fire) 1607052722fSJay val p2_mmio = DataHoldBypass(io.pmp.resp.mmio && !p2_except_af && !p2_except_pf, p2_pmp_fire) 1617052722fSJay 16200240ba6SJay /*when a prefetch req meet with a miss req in MSHR cancle the prefetch req */ 16300240ba6SJay val p2_check_in_mshr = VecInit(io.fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p2_paddr, blockBytes, PAddrBits))).reduce(_||_) 16400240ba6SJay 1657052722fSJay //TODO wait PMP logic 1667052722fSJay val p2_exception = VecInit(Seq(pmpExcpAF, p2_mmio)).reduce(_||_) 1677052722fSJay 1687052722fSJay io.pmp.req.valid := p2_pmp_fire 1697052722fSJay io.pmp.req.bits.addr := p2_paddr 1707052722fSJay io.pmp.req.bits.size := 3.U 1717052722fSJay io.pmp.req.bits.cmd := TlbCmd.exec 1727052722fSJay 1737052722fSJay p2_ready := p2_fire || p2_discard || !p2_valid 1747052722fSJay p2_fire := p2_valid && !p2_exception && p3_ready && p2_pmp_fire 17561e1db30SJay p2_discard := p2_valid && (p2_exception && p2_pmp_fire) 1767052722fSJay 1777052722fSJay /** Prefetch Stage 2: filtered req PIQ enqueue */ 178a108d429SJay val p3_valid = generatePipeControl(lastFire = p2_fire, thisFire = p3_fire || p3_discard, thisFlush = false.B, lastFlush = false.B) 1797052722fSJay 180005e809bSJiuyang Liu val p3_paddr = RegEnable(p2_paddr, p2_fire) 181005e809bSJiuyang Liu val p3_check_in_mshr = RegEnable(p2_check_in_mshr, p2_fire) 1827052722fSJay 183a108d429SJay val p3_hit_dir = VecInit((0 until nPrefetchEntries).map(i => prefetch_dir(i).valid && prefetch_dir(i).paddr === p3_paddr )).reduce(_||_) 184a108d429SJay 185e8747464SJenius p3_discard := p3_hit_dir || p3_check_in_mshr || (p3_valid && enableBit && !toMissUnit.enqReq.ready) 186a108d429SJay 187a108d429SJay toMissUnit.enqReq.valid := p3_valid && enableBit && !p3_discard 1887052722fSJay toMissUnit.enqReq.bits.paddr := p3_paddr 1897052722fSJay 190a108d429SJay when(reachMaxSize){ 191a108d429SJay maxPrefetchCoutner := 0.U 192a108d429SJay 193a108d429SJay prefetch_dir.foreach(_.valid := false.B) 194a108d429SJay }.elsewhen(toMissUnit.enqReq.fire()){ 195a108d429SJay maxPrefetchCoutner := maxPrefetchCoutner + 1.U 196a108d429SJay 197a108d429SJay prefetch_dir(maxPrefetchCoutner).valid := true.B 198a108d429SJay prefetch_dir(maxPrefetchCoutner).paddr := p3_paddr 199a108d429SJay } 200a108d429SJay 201a108d429SJay p3_ready := toMissUnit.enqReq.ready || !enableBit 2027052722fSJay p3_fire := toMissUnit.enqReq.fire() 2037052722fSJay 2047052722fSJay} 2057052722fSJay 2067052722fSJayclass IPrefetchEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule 2077052722fSJay{ 2087052722fSJay val io = IO(new Bundle { 2095e649ad5SJay val id = Input(UInt(log2Ceil(PortNumber + nPrefetchEntries).W)) 2107052722fSJay 2117052722fSJay val req = Flipped(DecoupledIO(new PIQReq)) 2127052722fSJay 2137052722fSJay //tilelink channel 2147052722fSJay val mem_hint = DecoupledIO(new TLBundleA(edge.bundle)) 2157052722fSJay val mem_hint_ack = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 2167052722fSJay 2177052722fSJay }) 2187052722fSJay 2197052722fSJay /** default value for control signals */ 2207052722fSJay io.mem_hint.bits := DontCare 2217052722fSJay io.mem_hint_ack.ready := true.B 2227052722fSJay 2237052722fSJay 2247052722fSJay val s_idle :: s_send_hint :: s_wait_hint_ack :: Nil = Enum(3) 2257052722fSJay val state = RegInit(s_idle) 2267052722fSJay /** control logic transformation */ 2277052722fSJay //request register 2287052722fSJay val req = Reg(new PIQReq) 2297052722fSJay //initial 2307052722fSJay io.mem_hint.bits := DontCare 2317052722fSJay io.mem_hint_ack.ready := true.B 2327052722fSJay 2337052722fSJay io.req.ready := (state === s_idle) 2347052722fSJay io.mem_hint.valid := (state === s_send_hint) 2357052722fSJay 2367052722fSJay //state change 2377052722fSJay switch(state) { 2387052722fSJay is(s_idle) { 2397052722fSJay when(io.req.fire()) { 2407052722fSJay state := s_send_hint 2417052722fSJay req := io.req.bits 2427052722fSJay } 2437052722fSJay } 2447052722fSJay 2457052722fSJay // memory request 2467052722fSJay is(s_send_hint) { 2477052722fSJay when(io.mem_hint.fire()) { 2487052722fSJay state := s_idle 2497052722fSJay } 2507052722fSJay } 2517052722fSJay } 2527052722fSJay 2537052722fSJay /** refill write and meta write */ 2547052722fSJay val hint = edge.Hint( 2557052722fSJay fromSource = io.id, 2567052722fSJay toAddress = addrAlign(req.paddr, blockBytes, PAddrBits) + blockBytes.U, 2577052722fSJay lgSize = (log2Up(cacheParams.blockBytes)).U, 2587052722fSJay param = TLHints.PREFETCH_READ 2597052722fSJay )._2 2607052722fSJay io.mem_hint.bits := hint 261de7689fcSJay io.mem_hint.bits.user.lift(PreferCacheKey).foreach(_ := true.B) 2627052722fSJay 2637052722fSJay 2647052722fSJay XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire()) 2657052722fSJay 2667052722fSJay} 267