1*7052722fSJay/*************************************************************************************** 2*7052722fSJay * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3*7052722fSJay * Copyright (c) 2020-2021 Peng Cheng Laboratory 4*7052722fSJay * 5*7052722fSJay * XiangShan is licensed under Mulan PSL v2. 6*7052722fSJay * You can use this software according to the terms and conditions of the Mulan PSL v2. 7*7052722fSJay * You may obtain a copy of Mulan PSL v2 at: 8*7052722fSJay * http://license.coscl.org.cn/MulanPSL2 9*7052722fSJay * 10*7052722fSJay * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11*7052722fSJay * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12*7052722fSJay * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13*7052722fSJay * 14*7052722fSJay * See the Mulan PSL v2 for more details. 15*7052722fSJay ***************************************************************************************/ 16*7052722fSJay 17*7052722fSJaypackage xiangshan.frontend.icache 18*7052722fSJay 19*7052722fSJayimport chipsalliance.rocketchip.config.Parameters 20*7052722fSJayimport chisel3._ 21*7052722fSJayimport chisel3.util._ 22*7052722fSJayimport freechips.rocketchip.tilelink._ 23*7052722fSJayimport utils._ 24*7052722fSJayimport xiangshan.cache.mmu._ 25*7052722fSJayimport xiangshan.frontend._ 26*7052722fSJayimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle} 27*7052722fSJay 28*7052722fSJay 29*7052722fSJay 30*7052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle 31*7052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule 32*7052722fSJay 33*7052722fSJayclass PIQReq(implicit p: Parameters) extends IPrefetchBundle { 34*7052722fSJay val paddr = UInt(PAddrBits.W) 35*7052722fSJay} 36*7052722fSJay 37*7052722fSJayclass IPrefetchPMPBundle(implicit p: Parameters) extends ICacheBundle{ 38*7052722fSJay val req = DecoupledIO(new PMPReqBundle()) 39*7052722fSJay val resp = Input(new PMPRespBundle()) 40*7052722fSJay} 41*7052722fSJay 42*7052722fSJay 43*7052722fSJayclass IPrefetchToMissUnit(implicit p: Parameters) extends IPrefetchBundle{ 44*7052722fSJay val enqReq = DecoupledIO(new PIQReq) 45*7052722fSJay} 46*7052722fSJay 47*7052722fSJayclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle { 48*7052722fSJay val fromFtq = Flipped(new FtqPrefechBundle) 49*7052722fSJay val iTLBInter = new BlockTlbRequestIO 50*7052722fSJay val pmp = new IPrefetchPMPBundle 51*7052722fSJay val toIMeta = Decoupled(new ICacheReadBundle) 52*7052722fSJay val fromIMeta = Input(new ICacheMetaRespBundle) 53*7052722fSJay val toMissUnit = new IPrefetchToMissUnit 54*7052722fSJay} 55*7052722fSJay 56*7052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule 57*7052722fSJay{ 58*7052722fSJay val io = IO(new IPredfetchIO) 59*7052722fSJay 60*7052722fSJay val fromFtq = io.fromFtq 61*7052722fSJay val (toITLB, fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp) 62*7052722fSJay val (toIMeta, fromIMeta) = (io.toIMeta, io.fromIMeta.metaData(0)) 63*7052722fSJay val (toPMP, fromPMP) = (io.pmp.req, io.pmp.resp) 64*7052722fSJay val toMissUnit = io.toMissUnit 65*7052722fSJay 66*7052722fSJay val p0_fire, p1_fire, p2_fire, p3_fire = WireInit(false.B) 67*7052722fSJay val p1_discard, p2_discard, p3_discard = WireInit(false.B) 68*7052722fSJay val p0_ready, p1_ready, p2_ready, p3_ready = WireInit(false.B) 69*7052722fSJay 70*7052722fSJay /** Prefetch Stage 0: req from Ftq */ 71*7052722fSJay val p0_valid = fromFtq.req.valid 72*7052722fSJay val p0_vaddr = addrAlign(fromFtq.req.bits.target, blockBytes, PAddrBits) 73*7052722fSJay p0_fire := p0_valid && p1_ready && toITLB.fire() && !fromITLB.bits.miss && toIMeta.ready 74*7052722fSJay 75*7052722fSJay toIMeta.valid := p0_valid 76*7052722fSJay toIMeta.bits.vSetIdx(0) := get_idx(p0_vaddr) 77*7052722fSJay 78*7052722fSJay toIMeta.bits.vSetIdx(1) := DontCare 79*7052722fSJay toIMeta.bits.isDoubleLine := false.B 80*7052722fSJay 81*7052722fSJay toITLB.valid := p0_valid 82*7052722fSJay toITLB.bits.size := 3.U // TODO: fix the size 83*7052722fSJay toITLB.bits.vaddr := p0_vaddr 84*7052722fSJay toITLB.bits.debug.pc := p0_vaddr 85*7052722fSJay 86*7052722fSJay toITLB.bits.cmd := TlbCmd.exec 87*7052722fSJay toITLB.bits.robIdx := DontCare 88*7052722fSJay toITLB.bits.debug.isFirstIssue := DontCare 89*7052722fSJay 90*7052722fSJay 91*7052722fSJay fromITLB.ready := true.B 92*7052722fSJay 93*7052722fSJay fromFtq.req.ready := p1_ready && GTimer() > 500.U 94*7052722fSJay 95*7052722fSJay /** Prefetch Stage 1: cache probe filter */ 96*7052722fSJay val p1_valid = generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B) 97*7052722fSJay 98*7052722fSJay val p1_vaddr = RegEnable(next = p0_vaddr, enable=p0_fire) 99*7052722fSJay 100*7052722fSJay //tlb resp 101*7052722fSJay val tlb_resp_valid = RegNext(p0_fire) 102*7052722fSJay 103*7052722fSJay val tlb_resp_paddr = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.paddr) 104*7052722fSJay val tlb_resp_pf = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.excp.pf.instr && tlb_resp_valid) 105*7052722fSJay val tlb_resp_af = ResultHoldBypass(valid = tlb_resp_valid, data = fromITLB.bits.excp.af.instr && tlb_resp_valid) 106*7052722fSJay 107*7052722fSJay val p1_exception = VecInit(Seq(tlb_resp_pf, tlb_resp_af)) 108*7052722fSJay val p1_has_except = p1_exception.reduce(_ || _) 109*7052722fSJay 110*7052722fSJay val p1_ptag = get_phy_tag(tlb_resp_paddr) 111*7052722fSJay 112*7052722fSJay val p1_meta_ptags = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.tag)),valid = RegNext(p0_fire)) 113*7052722fSJay val p1_meta_cohs = ResultHoldBypass(data = VecInit(fromIMeta.map(way => way.coh)),valid = RegNext(p0_fire)) 114*7052722fSJay 115*7052722fSJay val p1_tag_eq_vec = VecInit(p1_meta_ptags.map(_ === p1_ptag )) 116*7052722fSJay 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()}) 117*7052722fSJay val p1_tag_match = ParallelOR(p1_tag_match_vec) 118*7052722fSJay val (p1_hit, p1_miss) = (p1_valid && p1_tag_match && !p1_has_except, p1_valid && !p1_tag_match && !p1_has_except) 119*7052722fSJay 120*7052722fSJay //overriding the invalid req 121*7052722fSJay val p1_req_cancle = (p1_hit || (tlb_resp_valid && p1_exception.reduce(_ || _))) && p1_valid 122*7052722fSJay val p1_req_accept = p1_valid && tlb_resp_valid && p1_miss 123*7052722fSJay 124*7052722fSJay p1_ready := p1_fire || p1_req_cancle || !p1_valid 125*7052722fSJay p1_fire := p1_valid && p1_req_accept && p2_ready 126*7052722fSJay p1_discard := p1_valid && p1_req_cancle 127*7052722fSJay 128*7052722fSJay /** Prefetch Stage 2: filtered req PIQ enqueue */ 129*7052722fSJay val p2_valid = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B) 130*7052722fSJay val p2_pmp_fire = p2_valid && io.pmp.req.ready 131*7052722fSJay val pmpExcpAF = fromPMP.instr 132*7052722fSJay 133*7052722fSJay val p2_paddr = RegEnable(next = tlb_resp_paddr, enable = p1_fire) 134*7052722fSJay val p2_except_pf = RegEnable(next =tlb_resp_pf, enable = p1_fire) 135*7052722fSJay val p2_except_af = DataHoldBypass(pmpExcpAF, p2_pmp_fire) || RegEnable(next = tlb_resp_af, enable = p1_fire) 136*7052722fSJay val p2_mmio = DataHoldBypass(io.pmp.resp.mmio && !p2_except_af && !p2_except_pf, p2_pmp_fire) 137*7052722fSJay 138*7052722fSJay //TODO wait PMP logic 139*7052722fSJay val p2_exception = VecInit(Seq(pmpExcpAF, p2_mmio)).reduce(_||_) 140*7052722fSJay 141*7052722fSJay io.pmp.req.valid := p2_pmp_fire 142*7052722fSJay io.pmp.req.bits.addr := p2_paddr 143*7052722fSJay io.pmp.req.bits.size := 3.U 144*7052722fSJay io.pmp.req.bits.cmd := TlbCmd.exec 145*7052722fSJay 146*7052722fSJay p2_ready := p2_fire || p2_discard || !p2_valid 147*7052722fSJay p2_fire := p2_valid && !p2_exception && p3_ready && p2_pmp_fire 148*7052722fSJay p2_discard := p2_valid && ((p2_exception && p2_pmp_fire) || !io.pmp.req.ready) 149*7052722fSJay 150*7052722fSJay /** Prefetch Stage 2: filtered req PIQ enqueue */ 151*7052722fSJay val p3_valid = generatePipeControl(lastFire = p2_fire, thisFire = p3_fire, thisFlush = false.B, lastFlush = false.B) 152*7052722fSJay 153*7052722fSJay val p3_paddr = RegEnable(next = tlb_resp_paddr, enable = p1_fire) 154*7052722fSJay 155*7052722fSJay toMissUnit.enqReq.valid := p3_valid 156*7052722fSJay toMissUnit.enqReq.bits.paddr := p3_paddr 157*7052722fSJay 158*7052722fSJay p3_ready := toMissUnit.enqReq.ready 159*7052722fSJay p3_fire := toMissUnit.enqReq.fire() 160*7052722fSJay 161*7052722fSJay} 162*7052722fSJay 163*7052722fSJayclass IPrefetchEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends ICacheMissUnitModule 164*7052722fSJay{ 165*7052722fSJay val io = IO(new Bundle { 166*7052722fSJay val id = Input(UInt(log2Ceil(nPrefetchEntries).W)) 167*7052722fSJay 168*7052722fSJay val req = Flipped(DecoupledIO(new PIQReq)) 169*7052722fSJay 170*7052722fSJay //tilelink channel 171*7052722fSJay val mem_hint = DecoupledIO(new TLBundleA(edge.bundle)) 172*7052722fSJay val mem_hint_ack = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 173*7052722fSJay 174*7052722fSJay }) 175*7052722fSJay 176*7052722fSJay /** default value for control signals */ 177*7052722fSJay io.mem_hint.bits := DontCare 178*7052722fSJay io.mem_hint_ack.ready := true.B 179*7052722fSJay 180*7052722fSJay 181*7052722fSJay val s_idle :: s_send_hint :: s_wait_hint_ack :: Nil = Enum(3) 182*7052722fSJay val state = RegInit(s_idle) 183*7052722fSJay /** control logic transformation */ 184*7052722fSJay //request register 185*7052722fSJay val req = Reg(new PIQReq) 186*7052722fSJay //initial 187*7052722fSJay io.mem_hint.bits := DontCare 188*7052722fSJay io.mem_hint_ack.ready := true.B 189*7052722fSJay 190*7052722fSJay io.req.ready := (state === s_idle) 191*7052722fSJay io.mem_hint.valid := (state === s_send_hint) 192*7052722fSJay 193*7052722fSJay //state change 194*7052722fSJay switch(state) { 195*7052722fSJay is(s_idle) { 196*7052722fSJay when(io.req.fire()) { 197*7052722fSJay state := s_send_hint 198*7052722fSJay req := io.req.bits 199*7052722fSJay } 200*7052722fSJay } 201*7052722fSJay 202*7052722fSJay // memory request 203*7052722fSJay is(s_send_hint) { 204*7052722fSJay when(io.mem_hint.fire()) { 205*7052722fSJay state := s_idle 206*7052722fSJay } 207*7052722fSJay } 208*7052722fSJay } 209*7052722fSJay 210*7052722fSJay /** refill write and meta write */ 211*7052722fSJay val hint = edge.Hint( 212*7052722fSJay fromSource = io.id, 213*7052722fSJay toAddress = addrAlign(req.paddr, blockBytes, PAddrBits) + blockBytes.U, 214*7052722fSJay lgSize = (log2Up(cacheParams.blockBytes)).U, 215*7052722fSJay param = TLHints.PREFETCH_READ 216*7052722fSJay )._2 217*7052722fSJay io.mem_hint.bits := hint 218*7052722fSJay 219*7052722fSJay 220*7052722fSJay XSPerfAccumulate( 221*7052722fSJay "PrefetchEntryPenalty" + Integer.toString(id, 10), 222*7052722fSJay BoolStopWatch( 223*7052722fSJay start = io.req.fire(), 224*7052722fSJay stop = io.mem_hint_ack.fire(), 225*7052722fSJay startHighPriority = true) 226*7052722fSJay ) 227*7052722fSJay XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire()) 228*7052722fSJay 229*7052722fSJay}