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 19*8891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters 207052722fSJayimport chisel3._ 217052722fSJayimport chisel3.util._ 227d45a146SYinan Xuimport difftest._ 237052722fSJayimport freechips.rocketchip.tilelink._ 247052722fSJayimport utils._ 257052722fSJayimport xiangshan.cache.mmu._ 267052722fSJayimport xiangshan.frontend._ 27d2b20d1aSTang Haojinimport xiangshan.backend.fu.{PMPReqBundle, PMPRespBundle} 28d2b20d1aSTang Haojinimport huancun.PreferCacheKey 29b92c5693STang Haojinimport xiangshan.XSCoreParamsKey 30b1ded4e8Sguohongyuimport utility._ 317052722fSJay 327052722fSJay 337052722fSJayabstract class IPrefetchBundle(implicit p: Parameters) extends ICacheBundle 347052722fSJayabstract class IPrefetchModule(implicit p: Parameters) extends ICacheModule 357052722fSJay 36b1ded4e8Sguohongyu//TODO: remove this 37b1ded4e8Sguohongyuobject DebugFlags { 38b1ded4e8Sguohongyu val fdip = false 397052722fSJay} 407052722fSJay 41b1ded4e8Sguohongyuclass PIQData(implicit p: Parameters) extends IPrefetchBundle { 42b1ded4e8Sguohongyu val ptage = UInt(tagBits.W) 43b1ded4e8Sguohongyu val vSetIdx = UInt(idxBits.W) 44b1ded4e8Sguohongyu val cacheline = UInt(blockBits.W) 45b1ded4e8Sguohongyu val writeBack = Bool() 46b1ded4e8Sguohongyu} 47b1ded4e8Sguohongyu 48b1ded4e8Sguohongyuclass PIQToMainPipe(implicit p: Parameters) extends IPrefetchBundle{ 49b1ded4e8Sguohongyu val info = DecoupledIO(new PIQData) 50b1ded4e8Sguohongyu} 51b1ded4e8Sguohongyu/* need change name */ 52cb6e5d3cSssszwicclass MainPipeMissInfo(implicit p: Parameters) extends IPrefetchBundle { 53b1ded4e8Sguohongyu val ptage = UInt(tagBits.W) 54b1ded4e8Sguohongyu val vSetIdx = UInt(idxBits.W) 55b1ded4e8Sguohongyu} 56b1ded4e8Sguohongyu 57cb6e5d3cSssszwicclass PrefetchReq(implicit p: Parameters) extends IPrefetchBundle{ 58cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 59cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 60b1ded4e8Sguohongyu} 617052722fSJay 62cb6e5d3cSssszwicclass PrefetchBufferIO(implicit p: Parameters) extends IPrefetchBundle { 63cb6e5d3cSssszwic val hartId = Input(UInt(8.W)) 64b1ded4e8Sguohongyu val fencei = Input(Bool()) 65cb6e5d3cSssszwic val IPFFilterRead = new IPFBufferFilterRead 66cb6e5d3cSssszwic val IPFBufferRead = new IPFBufferRead 67cb6e5d3cSssszwic val IPFBufferWrite = Flipped(DecoupledIO(new IPFBufferWrite)) 68cb6e5d3cSssszwic val metaWrite = DecoupledIO(new ICacheMetaWriteBundle) 69cb6e5d3cSssszwic val dataWrite = DecoupledIO(new ICacheDataWriteBundle) 70cb6e5d3cSssszwic val IPFReplacer = new IPFReplacer 71b1ded4e8Sguohongyu} 72b1ded4e8Sguohongyu 73b1ded4e8Sguohongyuclass PrefetchBuffer(implicit p: Parameters) extends IPrefetchModule 74b1ded4e8Sguohongyu{ 75cb6e5d3cSssszwic val io = IO(new PrefetchBufferIO) 76cb6e5d3cSssszwic 77cb6e5d3cSssszwic val fromIPrefetch = io.IPFFilterRead.req 78cb6e5d3cSssszwic val toIPrefetch = io.IPFFilterRead.resp 79cb6e5d3cSssszwic val fromMainPipe = io.IPFBufferRead.req 80cb6e5d3cSssszwic val toMainPipe = io.IPFBufferRead.resp 81cb6e5d3cSssszwic val fromPIQ = io.IPFBufferWrite 82cb6e5d3cSssszwic val toICacheMeta = io.metaWrite 83cb6e5d3cSssszwic val toICacheData = io.dataWrite 84cb6e5d3cSssszwic val fromReplacer = io.IPFReplacer 85b1ded4e8Sguohongyu 86b1ded4e8Sguohongyu class IPFBufferEntryMeta(implicit p: Parameters) extends IPrefetchBundle 87b1ded4e8Sguohongyu { 88b1ded4e8Sguohongyu val valid = Bool() 89cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 90cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 91b1ded4e8Sguohongyu val confidence = UInt(log2Ceil(maxIPFMoveConf + 1).W) 92b1ded4e8Sguohongyu } 93b1ded4e8Sguohongyu 94b1ded4e8Sguohongyu class IPFBufferEntryData(implicit p: Parameters) extends IPrefetchBundle 95b1ded4e8Sguohongyu { 96cb6e5d3cSssszwic val cacheline = UInt(blockBits.W) 97b1ded4e8Sguohongyu } 98b1ded4e8Sguohongyu 99b1ded4e8Sguohongyu def InitQueue[T <: Data](entry: T, size: Int): Vec[T] ={ 100b1ded4e8Sguohongyu return RegInit(VecInit(Seq.fill(size)(0.U.asTypeOf(entry.cloneType)))) 101b1ded4e8Sguohongyu } 102b1ded4e8Sguohongyu 103b1ded4e8Sguohongyu val meta_buffer = InitQueue(new IPFBufferEntryMeta, size = nIPFBufferSize) 104b1ded4e8Sguohongyu val data_buffer = InitQueue(new IPFBufferEntryData, size = nIPFBufferSize) 105b1ded4e8Sguohongyu 106cb6e5d3cSssszwic /** 107cb6e5d3cSssszwic ****************************************************************************** 108cb6e5d3cSssszwic * handle look-up request from IPrefetchPipe 109cb6e5d3cSssszwic * - 1. Receive request from IPrefetch 110cb6e5d3cSssszwic * - 2. Look up whether hit in meta_buffer 111cb6e5d3cSssszwic * - 3. Send response to IPrefetch at the same cycle 112cb6e5d3cSssszwic ****************************************************************************** 113cb6e5d3cSssszwic */ 114cb6e5d3cSssszwic val fr_block = get_block(fromIPrefetch.paddr) 115cb6e5d3cSssszwic val fr_hit_oh = meta_buffer.map(e => e.valid && (get_block(e.paddr) === fr_block)) 116cb6e5d3cSssszwic toIPrefetch.ipf_hit := ParallelOR(fr_hit_oh) 117cb6e5d3cSssszwic // only hit one entry in meta_buffer at the same time 118cb6e5d3cSssszwic assert(PopCount(fr_hit_oh) <= 1.U, "More than 1 hit in L1 prefetch buffer for filter") 11964d7d412Sguohongyu 120cb6e5d3cSssszwic /** 121cb6e5d3cSssszwic ****************************************************************************** 122cb6e5d3cSssszwic * handle read request from ICacheMainPipe 123cb6e5d3cSssszwic * - 1. Receive request from ICacheMainPipe 124cb6e5d3cSssszwic * - 2. Look up whether hit in meta_buffer and get hitted data 125cb6e5d3cSssszwic * - 3. Send response to ICacheMainPipe at the same cycle 126cb6e5d3cSssszwic ****************************************************************************** 127cb6e5d3cSssszwic */ 128cb6e5d3cSssszwic fromMainPipe.foreach(_.ready := DontCare) 129cb6e5d3cSssszwic val r_blocks = fromMainPipe.map (e => get_block(e.bits.paddr)) 130cb6e5d3cSssszwic val r_hit_oh = r_blocks.map (ptag => meta_buffer.map(e => e.valid && (get_block(e.paddr) === ptag))) 131cb6e5d3cSssszwic val curr_hit_ptr = r_hit_oh.map (OHToUInt(_)) 132cb6e5d3cSssszwic val r_hit_data = r_hit_oh.map (oh => Mux1H(oh, data_buffer.map(_.cacheline))) 133cb6e5d3cSssszwic val r_hit = (0 until PortNumber).map (i => ParallelOR(r_hit_oh(i)) && fromMainPipe(i).valid) 134cb6e5d3cSssszwic (0 until PortNumber).foreach (i => { 135cb6e5d3cSssszwic toMainPipe(i).ipf_hit := r_hit(i) 136cb6e5d3cSssszwic toMainPipe(i).cacheline := r_hit_data(i) 137cb6e5d3cSssszwic // only hit one entry in meta_buffer 138cb6e5d3cSssszwic assert(PopCount(r_hit_oh(i)) <= 1.U, "More than 1 hit in L1 prefetch buffer") 139cb6e5d3cSssszwic XSPerfAccumulate("fdip_mainpipe_hit_in_ipf_" + i, r_hit(i)) 140cb6e5d3cSssszwic }) 141d4112e88Sguohongyu 142d4112e88Sguohongyu 143cb6e5d3cSssszwic /** 144cb6e5d3cSssszwic ****************************************************************************** 145cb6e5d3cSssszwic * move the entry arriving max confidence to icache 146cb6e5d3cSssszwic * - 1. Chose a moved entry from the entries that reach max confidence (LSB first) 147cb6e5d3cSssszwic * - 2. Get victim way of array from replacer of ICacheMainPipe 148cb6e5d3cSssszwic * - 3. Send write req to metaArray and dataArray and ensure fire together 149cb6e5d3cSssszwic ****************************************************************************** 150cb6e5d3cSssszwic */ 151cb6e5d3cSssszwic val move_oh = meta_buffer.map (e => e.confidence === maxIPFMoveConf.U && e.valid) 152cb6e5d3cSssszwic val move_need = ParallelOR(move_oh) 153cb6e5d3cSssszwic val curr_move_ptr = PriorityEncoder(move_oh) 154b1ded4e8Sguohongyu 155cb6e5d3cSssszwic fromReplacer.vsetIdx := meta_buffer(curr_move_ptr).vSetIdx 156b1ded4e8Sguohongyu 157cb6e5d3cSssszwic toICacheMeta.valid := move_need 158cb6e5d3cSssszwic toICacheMeta.bits.generate( 159cb6e5d3cSssszwic tag = get_phy_tag(meta_buffer(curr_move_ptr).paddr), 160cb6e5d3cSssszwic idx = meta_buffer(curr_move_ptr).vSetIdx, 161cb6e5d3cSssszwic waymask = fromReplacer.waymask, 162cb6e5d3cSssszwic bankIdx = meta_buffer(curr_move_ptr).vSetIdx(0)) 163b1ded4e8Sguohongyu 164cb6e5d3cSssszwic toICacheData.valid := move_need 165cb6e5d3cSssszwic toICacheData.bits.generate( 166cb6e5d3cSssszwic data = data_buffer(curr_move_ptr).cacheline, 167cb6e5d3cSssszwic idx = meta_buffer(curr_move_ptr).vSetIdx, 168cb6e5d3cSssszwic waymask = fromReplacer.waymask, 169cb6e5d3cSssszwic bankIdx = meta_buffer(curr_move_ptr).vSetIdx(0), 170cb6e5d3cSssszwic paddr = meta_buffer(curr_move_ptr).paddr) 171b1ded4e8Sguohongyu 172cb6e5d3cSssszwic // TODO: how to ensure 173cb6e5d3cSssszwic assert((toICacheMeta.fire && toICacheData.fire) || (!toICacheMeta.fire && !toICacheData.fire), 174b1ded4e8Sguohongyu "meta and data array need fire at same time") 175b1ded4e8Sguohongyu 176cb6e5d3cSssszwic XSPerfAccumulate("fdip_move_to_icache", toICacheMeta.fire && toICacheData.fire) 177cb6e5d3cSssszwic 178cb6e5d3cSssszwic when(toICacheMeta.fire) { 179cb6e5d3cSssszwic XSDebug(p"PrefetchBuffer: write prefetch data to icache . vSetIdx:${meta_buffer(curr_move_ptr).vSetIdx} " + 180cb6e5d3cSssszwic p"paddr:${meta_buffer(curr_move_ptr).paddr}") 181cb6e5d3cSssszwic } 182cb6e5d3cSssszwic 183cb6e5d3cSssszwic /** 184cb6e5d3cSssszwic ****************************************************************************** 185cb6e5d3cSssszwic * Prefetch buffer write logic 186cb6e5d3cSssszwic * Read old data when read and write occur in the same cycle 187cb6e5d3cSssszwic * There are 4 situations that can cause meta_buffer and data_buffer to be written 188cb6e5d3cSssszwic * - 1. ICacheMainPipe read hit that need to change some status 189cb6e5d3cSssszwic * - 2. Move prefetch cacheline to icache 190cb6e5d3cSssszwic * - 3. Receive write request from ICacheMissUnit 191cb6e5d3cSssszwic * - 4. Receive fencei req that need to flush all buffer 192cb6e5d3cSssszwic * Priority: 4 > 3 > 2 > 1 193cb6e5d3cSssszwic * The order of the code determines the priority, with the following priority being higher 194cb6e5d3cSssszwic ****************************************************************************** 195cb6e5d3cSssszwic */ 196cb6e5d3cSssszwic 197cb6e5d3cSssszwic /** 1. confidence++ for every ICacheMainPipe hit */ 198cb6e5d3cSssszwic (0 until PortNumber) .map (i => 199cb6e5d3cSssszwic when(r_hit(i)) { 200cb6e5d3cSssszwic // handle overflow 201cb6e5d3cSssszwic when(meta_buffer(curr_hit_ptr(i)).confidence =/= maxIPFMoveConf.U) { 202cb6e5d3cSssszwic meta_buffer(curr_hit_ptr(i)).confidence := meta_buffer(curr_hit_ptr(i)).confidence + 1.U 203cb6e5d3cSssszwic } 204cb6e5d3cSssszwic } 205cb6e5d3cSssszwic ) 206cb6e5d3cSssszwic 207cb6e5d3cSssszwic /** 2. set entry invalid after move to icache */ 208cb6e5d3cSssszwic when(toICacheMeta.fire) { 209cb6e5d3cSssszwic meta_buffer(curr_move_ptr).valid := false.B 210cb6e5d3cSssszwic } 211cb6e5d3cSssszwic 212cb6e5d3cSssszwic /** 3. write prefetch data to entry */ 213cb6e5d3cSssszwic // try to get a free entry ptr 214cb6e5d3cSssszwic val free_oh = meta_buffer.map (_.valid === false.B) 215cb6e5d3cSssszwic val has_free = ParallelOR(free_oh) 216cb6e5d3cSssszwic val ptr_from_free = PriorityEncoder(free_oh) 217cb6e5d3cSssszwic // get a ptr from random replacement policy 218cb6e5d3cSssszwic val replacer = ReplacementPolicy.fromString(Some("random"), nIPFBufferSize) 219cb6e5d3cSssszwic // write to free entry if has, otherwise random entry 220cb6e5d3cSssszwic val curr_write_ptr = Mux(has_free, ptr_from_free, replacer.way) 221cb6e5d3cSssszwic fromPIQ.ready := DontCare 222cb6e5d3cSssszwic when(fromPIQ.valid) { 223cb6e5d3cSssszwic meta_buffer(curr_write_ptr).valid := true.B 224cb6e5d3cSssszwic meta_buffer(curr_write_ptr).confidence := fromPIQ.bits.has_hit.asUInt 225cb6e5d3cSssszwic meta_buffer(curr_write_ptr).paddr := fromPIQ.bits.paddr 226cb6e5d3cSssszwic meta_buffer(curr_write_ptr).vSetIdx := fromPIQ.bits.vSetIdx 227cb6e5d3cSssszwic data_buffer(curr_write_ptr).cacheline := fromPIQ.bits.cacheline 228cb6e5d3cSssszwic } 229b1ded4e8Sguohongyu 230b1ded4e8Sguohongyu if(DebugFlags.fdip) { 231cb6e5d3cSssszwic when(fromPIQ.valid) { 232cb6e5d3cSssszwic printf(p"PrefetchBuffer: receive prefetch data. vSetIdx:${fromPIQ.bits.vSetIdx} paddr:${fromPIQ.bits.paddr}") 233b1ded4e8Sguohongyu } 234b1ded4e8Sguohongyu } 235b1ded4e8Sguohongyu 236cb6e5d3cSssszwic XSPerfAccumulate("fdip_vitcm_used", !has_free && fromPIQ.valid && (meta_buffer(curr_write_ptr).confidence =/= 0.U)) 237cb6e5d3cSssszwic XSPerfAccumulate("fdip_vitcm_no_used", !has_free && fromPIQ.valid && (meta_buffer(curr_write_ptr).confidence === 0.U)) 238cb6e5d3cSssszwic 239cb6e5d3cSssszwic /** 4. flush all prefetch buffer when fencei */ 240cb6e5d3cSssszwic when(io.fencei) { 241cb6e5d3cSssszwic meta_buffer.foreach { b => 242cb6e5d3cSssszwic b.valid := false.B 243cb6e5d3cSssszwic b.confidence := 0.U 244cb6e5d3cSssszwic } 245cb6e5d3cSssszwic } 246cb6e5d3cSssszwic 247cb6e5d3cSssszwic XSPerfAccumulate("fdip_fencei_cycle", io.fencei) 248cb6e5d3cSssszwic 249afa866b1Sguohongyu if (env.EnableDifftest) { 250a0c65233SYinan Xu val difftest = DifftestModule(new DiffRefillEvent, dontCare = true) 2517d45a146SYinan Xu difftest.coreid := io.hartId 2527d45a146SYinan Xu difftest.index := 6.U 2537d45a146SYinan Xu difftest.valid := toICacheData.fire 2547d45a146SYinan Xu difftest.addr := toICacheData.bits.paddr 2557d45a146SYinan Xu difftest.data := toICacheData.bits.data.asTypeOf(difftest.data) 256935edac4STang Haojin difftest.idtfr := DontCare 25764d7d412Sguohongyu } 25864d7d412Sguohongyu} 259b1ded4e8Sguohongyu 260cb6e5d3cSssszwicclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle { 261cb6e5d3cSssszwic val ftqReq = Flipped(new FtqPrefechBundle) 262cb6e5d3cSssszwic val iTLBInter = new TlbRequestIO 263cb6e5d3cSssszwic val pmp = new ICachePMPBundle 264cb6e5d3cSssszwic val metaReadReq = Decoupled(new ICacheMetaReadReqBundle) 265cb6e5d3cSssszwic val metaReadResp = Input(new ICacheMetaReadRespBundle) 266cb6e5d3cSssszwic val prefetchReq = DecoupledIO(new PrefetchReq) 267cb6e5d3cSssszwic val mshrInfo = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W)))) 268cb6e5d3cSssszwic val IPFFilterRead = Flipped(new IPFBufferFilterRead) 269cb6e5d3cSssszwic val PIQFilterRead = Flipped(new PIQFilterRead) 270cb6e5d3cSssszwic /** icache main pipe to prefetch pipe */ 271cb6e5d3cSssszwic val mainPipeMissInfo = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo))) 272cb6e5d3cSssszwic val fencei = Input(Bool()) 2737052722fSJay} 2747052722fSJay 2757052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule 2767052722fSJay{ 2777052722fSJay val io = IO(new IPredfetchIO) 2787052722fSJay 279a108d429SJay val enableBit = RegInit(false.B) 280cb6e5d3cSssszwic enableBit := false.B 281a108d429SJay 282cb6e5d3cSssszwic val fromFtq = io.ftqReq 283cb6e5d3cSssszwic val mainPipeMissInfo = io.mainPipeMissInfo 2847052722fSJay val (toITLB, fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp) 285cb6e5d3cSssszwic val (toIMeta, fromIMeta, fromIMetaValid) = (io.metaReadReq, io.metaReadResp.metaData, io.metaReadResp.entryValid) 286cb6e5d3cSssszwic val (toIPFBuffer, fromIPFBuffer) = (io.IPFFilterRead.req, io.IPFFilterRead.resp) 287cb6e5d3cSssszwic val (toPIQ, fromPIQ) = (io.PIQFilterRead.req, io.PIQFilterRead.resp) 2887052722fSJay val (toPMP, fromPMP) = (io.pmp.req, io.pmp.resp) 289cb6e5d3cSssszwic val fromMSHR = io.mshrInfo 290cb6e5d3cSssszwic val toPIQEnqReq = io.prefetchReq 2917052722fSJay 292cb6e5d3cSssszwic val p0_fire, p1_fire, p2_fire = WireInit(false.B) 293cb6e5d3cSssszwic val p0_discard, p1_discard, p2_discard = WireInit(false.B) 294cb6e5d3cSssszwic val p0_ready, p1_ready, p2_ready = WireInit(false.B) 2957052722fSJay 296cb6e5d3cSssszwic /** 297cb6e5d3cSssszwic ****************************************************************************** 298cb6e5d3cSssszwic * IPrefetch Stage 0 299cb6e5d3cSssszwic * - 1. send req to IMeta 300cb6e5d3cSssszwic * - 2. send req to ITLB (no blocked) 301cb6e5d3cSssszwic * - 3. check last req 302cb6e5d3cSssszwic ****************************************************************************** 303cb6e5d3cSssszwic */ 3047052722fSJay val p0_valid = fromFtq.req.valid 305cb6e5d3cSssszwic 306d6b06a99SJay val p0_vaddr = addrAlign(fromFtq.req.bits.target, blockBytes, VAddrBits) 307cb6e5d3cSssszwic val p0_vaddr_reg = RegEnable(p0_vaddr, p0_fire) 308cb6e5d3cSssszwic val p0_req_cancel = Wire(Bool()) 3097052722fSJay 310cb6e5d3cSssszwic /** 1. send req to IMeta */ 3119bba777eSssszwic toIMeta.valid := p0_valid && !p0_req_cancel 3120c26d810Sguohongyu toIMeta.bits.idx := get_idx(p0_vaddr) 3137052722fSJay 314cb6e5d3cSssszwic /** 2. send req to ITLB (no blocked) */ 3159bba777eSssszwic toITLB.valid := p0_valid && !p0_req_cancel 3167052722fSJay toITLB.bits.size := 3.U // TODO: fix the size 3177052722fSJay toITLB.bits.vaddr := p0_vaddr 3187052722fSJay toITLB.bits.debug.pc := p0_vaddr 319f1fe8698SLemover toITLB.bits.kill := DontCare 3207052722fSJay toITLB.bits.cmd := TlbCmd.exec 321f1fe8698SLemover toITLB.bits.debug.robIdx := DontCare 3227052722fSJay toITLB.bits.debug.isFirstIssue := DontCare 323b1ded4e8Sguohongyu toITLB.bits.memidx := DontCare 324b1ded4e8Sguohongyu toITLB.bits.no_translate := false.B 3257052722fSJay fromITLB.ready := true.B 326cb6e5d3cSssszwic // TODO: whether to handle tlb miss for prefetch 327cb6e5d3cSssszwic io.iTLBInter.req_kill := false.B 3287052722fSJay 329cb6e5d3cSssszwic /** FTQ request port */ 330cb6e5d3cSssszwic fromFtq.req.ready := p0_ready 3317052722fSJay 332cb6e5d3cSssszwic /** 3. Check last req: request from FTQ is same as last time or behind */ 333cb6e5d3cSssszwic val p0_hit_behind = Wire(Bool()) 334cb6e5d3cSssszwic 335cb6e5d3cSssszwic /** stage 0 control */ 336cb6e5d3cSssszwic // Cancel request when prefetch not enable or the request from FTQ is same as last time 337cb6e5d3cSssszwic p0_req_cancel := !enableBit || p0_hit_behind || io.fencei 338cb6e5d3cSssszwic p0_ready := p0_req_cancel || p1_ready && toITLB.ready && toIMeta.ready 339cb6e5d3cSssszwic p0_fire := p0_valid && p1_ready && toITLB.ready && toIMeta.ready && enableBit && !p0_req_cancel 340cb6e5d3cSssszwic p0_discard := p0_valid && p0_req_cancel 341cb6e5d3cSssszwic 342cb6e5d3cSssszwic if(DebugFlags.fdip) { 343cb6e5d3cSssszwic when(p0_discard) { 344cb6e5d3cSssszwic printf(p"IPrefetchPipe: discard req in s0.") 345cb6e5d3cSssszwic } 346cb6e5d3cSssszwic } 347cb6e5d3cSssszwic 348cb6e5d3cSssszwic /** 349cb6e5d3cSssszwic ****************************************************************************** 350cb6e5d3cSssszwic * IPrefetch Stage 1 351cb6e5d3cSssszwic * - 1. Receive resp from ITLB (no blocked) 352cb6e5d3cSssszwic * - 2. Receive resp from IMeta 353cb6e5d3cSssszwic * - 3. Check MSHR 354cb6e5d3cSssszwic ****************************************************************************** 355cb6e5d3cSssszwic */ 3567052722fSJay val p1_valid = generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B) 357cb6e5d3cSssszwic 358005e809bSJiuyang Liu val p1_vaddr = RegEnable(p0_vaddr, p0_fire) 359cb6e5d3cSssszwic val p1_req_cancel = Wire(Bool()) 3607052722fSJay 361cb6e5d3cSssszwic /** 1. Receive resp from ITLB (no blocked) */ 362cb6e5d3cSssszwic val p1_tlb_resp_miss = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.miss) 363cb6e5d3cSssszwic val p1_tlb_resp_paddr = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.paddr(0)) 364cb6e5d3cSssszwic val p1_tlb_resp_pf = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).pf.instr) 365cb6e5d3cSssszwic val p1_tlb_resp_af = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).af.instr) 366cb6e5d3cSssszwic val p1_exception = VecInit(Seq(p1_tlb_resp_pf, p1_tlb_resp_af)) 3677052722fSJay val p1_has_except = p1_exception.reduce(_ || _) 368cb6e5d3cSssszwic val p1_paddr = p1_tlb_resp_paddr 3697052722fSJay 370cb6e5d3cSssszwic /** 2. Receive resp from IMeta. Register the data first because of strict timing. */ 3719bba777eSssszwic val p1_meta_ptags_reg = RegEnable(VecInit(fromIMeta.map(way => way.tag)), RegNext(p0_fire)) 3729bba777eSssszwic val p1_meta_valids_reg = RegEnable(fromIMetaValid, RegNext(p0_fire)) 3737052722fSJay 374cb6e5d3cSssszwic /** 3. Check MSHR */ 375cb6e5d3cSssszwic val p1_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p1_paddr, blockBytes, PAddrBits))).reduce(_||_) 376b1ded4e8Sguohongyu 377cb6e5d3cSssszwic /** Stage 1 control */ 378cb6e5d3cSssszwic p1_req_cancel := p1_check_in_mshr || p1_tlb_resp_miss || p1_has_except || io.fencei 3799bba777eSssszwic p1_ready := p1_valid && p2_ready || !p1_valid 3809bba777eSssszwic p1_fire := p1_valid && !p1_req_cancel && p2_ready && enableBit 3819bba777eSssszwic p1_discard := p1_valid && p1_req_cancel 3827052722fSJay 383cb6e5d3cSssszwic when(p1_discard) { 384cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: discard req in s1. vaddr:${p1_vaddr}") 385cb6e5d3cSssszwic } 386cb6e5d3cSssszwic 387cb6e5d3cSssszwic /** 388cb6e5d3cSssszwic ****************************************************************************** 389cb6e5d3cSssszwic * IPrefetch Stage 2 390cb6e5d3cSssszwic * - 1. IMeta Check: check whether req hit in icache 391cb6e5d3cSssszwic * - 2. PMP Check: send req and receive resq in the same cycle 392cb6e5d3cSssszwic * - 3. Check miss handling by main pipe 393cb6e5d3cSssszwic * - 4. Prefetch buffer Check 394cb6e5d3cSssszwic * - 5. Prefetch Queue Check 395cb6e5d3cSssszwic * - 6. MSHR check 396cb6e5d3cSssszwic * - 7. send req to piq 397cb6e5d3cSssszwic ****************************************************************************** 398cb6e5d3cSssszwic */ 3997052722fSJay val p2_valid = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B) 400cb6e5d3cSssszwic 4019bba777eSssszwic val p2_paddr = RegEnable(p1_paddr, p1_fire) 4029bba777eSssszwic val p2_vaddr = RegEnable(p1_vaddr, p1_fire) 403cb6e5d3cSssszwic val p2_req_cancel = Wire(Bool()) 404cb6e5d3cSssszwic val p2_vidx = get_idx(p2_vaddr) 4059bba777eSssszwic 406cb6e5d3cSssszwic p0_hit_behind := (p0_vaddr === p1_vaddr) || (p0_vaddr === p2_vaddr) 407cb6e5d3cSssszwic 408cb6e5d3cSssszwic /** 1. IMeta Check */ 4099bba777eSssszwic val p2_ptag = get_phy_tag(p2_paddr) 4109bba777eSssszwic val p2_tag_eq_vec = VecInit(p1_meta_ptags_reg.map(_ === p2_ptag )) 4119bba777eSssszwic val p2_tag_match_vec = VecInit(p2_tag_eq_vec.zipWithIndex.map{ case(way_tag_eq, w) => way_tag_eq && p1_meta_valids_reg(w)}) 4129bba777eSssszwic val p2_tag_match = DataHoldBypass(ParallelOR(p2_tag_match_vec), RegNext(p1_fire)) 4139bba777eSssszwic 414cb6e5d3cSssszwic /** 2. PMP Check */ 415cb6e5d3cSssszwic // TODO: When fromPMP.mmio is low but fromPMP.instr is high, which is a except? 416cb6e5d3cSssszwic val p2_exception = DataHoldBypass((fromPMP.mmio && !fromPMP.instr) || fromPMP.instr, RegNext(p1_fire)) 417cb6e5d3cSssszwic // PMP request 418cb6e5d3cSssszwic toPMP.valid := p2_valid 4199bba777eSssszwic toPMP.bits.addr := p2_paddr 4209bba777eSssszwic toPMP.bits.size := 3.U 4219bba777eSssszwic toPMP.bits.cmd := TlbCmd.exec 422b1ded4e8Sguohongyu 423cb6e5d3cSssszwic /** 3. Check miss handling by main pipe */ 424cb6e5d3cSssszwic val p2_hit_mp_miss = VecInit((0 until PortNumber).map(i => 425cb6e5d3cSssszwic mainPipeMissInfo(i).valid && (mainPipeMissInfo(i).bits.ptage === p2_ptag && 426cb6e5d3cSssszwic (mainPipeMissInfo(i).bits.vSetIdx === p2_vidx)))).reduce(_||_) 42700240ba6SJay 428cb6e5d3cSssszwic /** 4. Prefetch buffer Check */ 429cb6e5d3cSssszwic toIPFBuffer.paddr := p2_paddr 430cb6e5d3cSssszwic val p2_hit_buffer = fromIPFBuffer.ipf_hit 431cb6e5d3cSssszwic 432cb6e5d3cSssszwic /** 5. Prefetch Queue Check */ 433cb6e5d3cSssszwic toPIQ.paddr := p2_paddr 434cb6e5d3cSssszwic val p2_hit_piq = fromPIQ.piq_hit 435cb6e5d3cSssszwic 436cb6e5d3cSssszwic /** 6. MSHR check */ 437cb6e5d3cSssszwic val p2_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p2_paddr, blockBytes, PAddrBits))).reduce(_||_) 438cb6e5d3cSssszwic 439cb6e5d3cSssszwic /** 7. send req to piq */ 440cb6e5d3cSssszwic toPIQEnqReq.valid := p2_valid && !p2_req_cancel 441cb6e5d3cSssszwic toPIQEnqReq.bits.paddr := p2_paddr 442cb6e5d3cSssszwic toPIQEnqReq.bits.vSetIdx := p2_vidx 443cb6e5d3cSssszwic 444cb6e5d3cSssszwic /** Stage 2 control */ 445cb6e5d3cSssszwic p2_req_cancel := p2_tag_match || p2_exception || p2_hit_mp_miss || p2_hit_buffer || p2_hit_piq || p2_check_in_mshr || io.fencei 446cb6e5d3cSssszwic p2_ready := p2_valid && toPIQEnqReq.ready || !p2_valid 447935edac4STang Haojin p2_fire := toPIQEnqReq.fire 4489bba777eSssszwic p2_discard := p2_valid && p2_req_cancel 449b1ded4e8Sguohongyu 450cb6e5d3cSssszwic when(p2_discard) { 451cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: discard req in s2. vaddr:${p2_vaddr}") 452cb6e5d3cSssszwic } 4539bba777eSssszwic 454cb6e5d3cSssszwic when(p2_fire) { 455cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: send req to PIQ. vaddr:${p2_vaddr} paddr:${p2_paddr}") 456cb6e5d3cSssszwic } 4579bba777eSssszwic 458cb6e5d3cSssszwic /** PerfAccumulate */ 459cb6e5d3cSssszwic // the number of prefetch request received from ftq 460935edac4STang Haojin XSPerfAccumulate("prefetch_req_receive", fromFtq.req.fire) 461cb6e5d3cSssszwic // the number of prefetch request sent to PIQ 462935edac4STang Haojin XSPerfAccumulate("prefetch_req_send", toPIQEnqReq.fire) 463cb6e5d3cSssszwic /** 464cb6e5d3cSssszwic * Count the number of requests that are filtered for various reasons. 465cb6e5d3cSssszwic * The number of prefetch discard in Performance Accumulator may be 466cb6e5d3cSssszwic * a littel larger the number of really discarded. Because there can 467cb6e5d3cSssszwic * be multiple reasons for a canceled request at the same time. 468cb6e5d3cSssszwic */ 469cb6e5d3cSssszwic // discard prefetch request by fencei instruction 470cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_fencei", (p0_discard || p1_discard || p2_discard) && io.fencei) 471cb6e5d3cSssszwic // discard prefetch request by hit hit MSHR 472cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_mshr", (p1_discard && p1_check_in_mshr) || (p2_discard && p2_check_in_mshr)) 473cb6e5d3cSssszwic // discard prefetch request by the request is same as pipeline behind 474cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_behind", p0_discard && p0_hit_behind) 475cb6e5d3cSssszwic // discard prefetch request by tlb miss 476cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_tlb_miss", p1_discard && p1_tlb_resp_miss) 477cb6e5d3cSssszwic // discard prefetch request by tlb except 478cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_tlb_except", p1_discard && p1_has_except) 479cb6e5d3cSssszwic // discard prefetch request by hit icache 480cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_cache", p2_discard && p2_tag_match) 481cb6e5d3cSssszwic // discard prefetch request by pmp except or mmio 482cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_pmp", p2_discard && p2_exception) 483cb6e5d3cSssszwic // discard prefetch request by req is handling by icache mainpipe 484cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_mp", p2_discard && p2_hit_mp_miss) 485cb6e5d3cSssszwic // discard prefetch request by hit in prefetch buffer 486cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_pf", p2_discard && p2_hit_buffer) 487cb6e5d3cSssszwic // discard prefetch request by hit in prefetch queue 488cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_piq", p2_discard && p2_hit_piq) 489cb6e5d3cSssszwic} 4907052722fSJay 491cb6e5d3cSssszwic// class PIQEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends IPrefetchModule 492cb6e5d3cSssszwic// { 493cb6e5d3cSssszwic// val io = IO(new Bundle{ 494cb6e5d3cSssszwic// val id = Input(UInt((log2Ceil(nPrefetchEntries + PortNumber)).W)) 4959bba777eSssszwic 496cb6e5d3cSssszwic// val req = Flipped(DecoupledIO(new PIQReq)) 497a108d429SJay 498cb6e5d3cSssszwic// val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 499cb6e5d3cSssszwic// val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 5007052722fSJay 501cb6e5d3cSssszwic// // write back to Prefetch Buffer 502cb6e5d3cSssszwic// val piq_write_ipbuffer = DecoupledIO(new IPFBufferWrite) 5039bba777eSssszwic 504cb6e5d3cSssszwic// val fencei = Input(Bool()) 505cb6e5d3cSssszwic 506cb6e5d3cSssszwic// val prefetch_entry_data = DecoupledIO(new PIQData) 507cb6e5d3cSssszwic 508cb6e5d3cSssszwic// val ongoing_req = ValidIO(UInt(PAddrBits.W)) 509cb6e5d3cSssszwic// }) 510cb6e5d3cSssszwic 511cb6e5d3cSssszwic// val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: s_finish:: Nil = Enum(5) 512cb6e5d3cSssszwic// val state = RegInit(s_idle) 513cb6e5d3cSssszwic 514cb6e5d3cSssszwic// //req register 515cb6e5d3cSssszwic// val req = Reg(new PIQReq) 516cb6e5d3cSssszwic// val req_idx = req.vSetIdx //virtual index 517cb6e5d3cSssszwic// val req_tag = get_phy_tag(req.paddr) //physical tag 518cb6e5d3cSssszwic 519cb6e5d3cSssszwic// val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant) 520cb6e5d3cSssszwic 521cb6e5d3cSssszwic// //8 for 64 bits bus and 2 for 256 bits 522cb6e5d3cSssszwic// val readBeatCnt = Reg(UInt(log2Up(refillCycles).W)) 523cb6e5d3cSssszwic// val respDataReg = Reg(Vec(refillCycles,UInt(beatBits.W))) 524cb6e5d3cSssszwic 525cb6e5d3cSssszwic// //to main pipe s1 526cb6e5d3cSssszwic// io.prefetch_entry_data.valid := state =/= s_idle 527cb6e5d3cSssszwic// io.prefetch_entry_data.bits.vSetIdx := req_idx 528cb6e5d3cSssszwic// io.prefetch_entry_data.bits.ptage := req_tag 529cb6e5d3cSssszwic// io.prefetch_entry_data.bits.cacheline := respDataReg.asUInt 530cb6e5d3cSssszwic// io.prefetch_entry_data.bits.writeBack := state === s_write_back 531cb6e5d3cSssszwic 532cb6e5d3cSssszwic// //initial 533cb6e5d3cSssszwic// io.mem_acquire.bits := DontCare 534cb6e5d3cSssszwic// io.mem_grant.ready := true.B 535cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits:= DontCare 536cb6e5d3cSssszwic 537cb6e5d3cSssszwic// io.req.ready := state === s_idle 538cb6e5d3cSssszwic// io.mem_acquire.valid := state === s_memReadReq 539cb6e5d3cSssszwic 540cb6e5d3cSssszwic// val needflush_r = RegInit(false.B) 541cb6e5d3cSssszwic// when (state === s_idle) { needflush_r := false.B } 542cb6e5d3cSssszwic// when (state =/= s_idle && io.fencei) { needflush_r := true.B } 543cb6e5d3cSssszwic// val needflush = needflush_r | io.fencei 544cb6e5d3cSssszwic 545cb6e5d3cSssszwic// //state change 546cb6e5d3cSssszwic// switch(state){ 547cb6e5d3cSssszwic// is(s_idle){ 548cb6e5d3cSssszwic// when(io.req.fire()){ 549cb6e5d3cSssszwic// readBeatCnt := 0.U 550cb6e5d3cSssszwic// state := s_memReadReq 551cb6e5d3cSssszwic// req := io.req.bits 552974a902cSguohongyu// } 553cb6e5d3cSssszwic// } 5547052722fSJay 555cb6e5d3cSssszwic// // memory request 556cb6e5d3cSssszwic// is(s_memReadReq){ 557cb6e5d3cSssszwic// when(io.mem_acquire.fire()){ 558cb6e5d3cSssszwic// state := s_memReadResp 559cb6e5d3cSssszwic// } 560cb6e5d3cSssszwic// } 5617052722fSJay 562cb6e5d3cSssszwic// is(s_memReadResp){ 563cb6e5d3cSssszwic// when (edge.hasData(io.mem_grant.bits)) { 564cb6e5d3cSssszwic// when (io.mem_grant.fire()) { 565cb6e5d3cSssszwic// readBeatCnt := readBeatCnt + 1.U 566cb6e5d3cSssszwic// respDataReg(readBeatCnt) := io.mem_grant.bits.data 567cb6e5d3cSssszwic// when (readBeatCnt === (refillCycles - 1).U) { 568cb6e5d3cSssszwic// assert(refill_done, "refill not done!") 569cb6e5d3cSssszwic// state := s_write_back 570cb6e5d3cSssszwic// } 571cb6e5d3cSssszwic// } 572cb6e5d3cSssszwic// } 573cb6e5d3cSssszwic// } 5747052722fSJay 575cb6e5d3cSssszwic// is(s_write_back){ 576cb6e5d3cSssszwic// state := Mux(io.piq_write_ipbuffer.fire() || needflush, s_finish, s_write_back) 577cb6e5d3cSssszwic// } 578cb6e5d3cSssszwic 579cb6e5d3cSssszwic// is(s_finish){ 580cb6e5d3cSssszwic// state := s_idle 581cb6e5d3cSssszwic// } 582cb6e5d3cSssszwic// } 583cb6e5d3cSssszwic 584cb6e5d3cSssszwic// //refill write and meta write 585cb6e5d3cSssszwic// //WARNING: Maybe could not finish refill in 1 cycle 586cb6e5d3cSssszwic// io.piq_write_ipbuffer.valid := (state === s_write_back) && !needflush 587cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.tag := req_tag 588cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.index := req_idx 589cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.paddr := req.paddr 590cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.data := respDataReg.asUInt 591cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.buffIdx := io.id - PortNumber.U 592cb6e5d3cSssszwic 593cb6e5d3cSssszwic// io.ongoing_req.valid := state =/= s_idle 594cb6e5d3cSssszwic// io.ongoing_req.bits := addrAlign(req.paddr, blockBytes, PAddrBits) 595cb6e5d3cSssszwic 596cb6e5d3cSssszwic// XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire()) 597cb6e5d3cSssszwic 598cb6e5d3cSssszwic// //mem request 599cb6e5d3cSssszwic// io.mem_acquire.bits := edge.Get( 600cb6e5d3cSssszwic// fromSource = io.id, 601cb6e5d3cSssszwic// toAddress = Cat(req.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)), 602cb6e5d3cSssszwic// lgSize = (log2Up(cacheParams.blockBytes)).U)._2 603cb6e5d3cSssszwic// io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B) 604cb6e5d3cSssszwic// io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U) 605cb6e5d3cSssszwic// } 606cb6e5d3cSssszwic 607cb6e5d3cSssszwicclass PrefetchQueueIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle { 608cb6e5d3cSssszwic val hartId = Input(UInt(8.W)) 609cb6e5d3cSssszwic val prefetchReq = Flipped(DecoupledIO(new PrefetchReq)) 610cb6e5d3cSssszwic val PIQFilterRead = new PIQFilterRead 611cb6e5d3cSssszwic val PIQRead = new PIQRead 612cb6e5d3cSssszwic val IPFBufferWrite = DecoupledIO(new IPFBufferWrite) 613cb6e5d3cSssszwic /** TileLink Port */ 614b1ded4e8Sguohongyu val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 615b1ded4e8Sguohongyu val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 616b1ded4e8Sguohongyu val fencei = Input(Bool()) 617cb6e5d3cSssszwic} 618b1ded4e8Sguohongyu 619cb6e5d3cSssszwicclass PrefetchQueue(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule { 620cb6e5d3cSssszwic val io = IO(new PrefetchQueueIO(edge)) 621974a902cSguohongyu 622cb6e5d3cSssszwic val enqueReq = io.prefetchReq 623cb6e5d3cSssszwic val fromIPrefetch = io.PIQFilterRead.req 624cb6e5d3cSssszwic val toIPrefetch = io.PIQFilterRead.resp 625cb6e5d3cSssszwic val fromMainPipe = io.PIQRead.req 626cb6e5d3cSssszwic val toMainPipe = io.PIQRead.resp 627cb6e5d3cSssszwic val toIPF = io.IPFBufferWrite 628cb6e5d3cSssszwic 629cb6e5d3cSssszwic /** Define entryt content and initial FIFO queue */ 630cb6e5d3cSssszwic class PrefetchEntry(implicit p: Parameters) extends IPrefetchBundle { 631cb6e5d3cSssszwic val valid = Bool() 632cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 633cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 634cb6e5d3cSssszwic } 635cb6e5d3cSssszwic val PIQ = RegInit(VecInit(Seq.fill(nPrefetchEntries)(0.U.asTypeOf((new PrefetchEntry).cloneType)))) 636cb6e5d3cSssszwic 637cb6e5d3cSssszwic class HandleEntry(implicit p: Parameters) extends IPrefetchBundle { 638cb6e5d3cSssszwic val valid = Bool() 639cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 640cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 641cb6e5d3cSssszwic val issue = Bool() 642cb6e5d3cSssszwic val finish = Bool() 643cb6e5d3cSssszwic val flash = Bool() 644cb6e5d3cSssszwic val readBeatCnt = UInt(log2Up(refillCycles).W) 645cb6e5d3cSssszwic val respData = Vec(refillCycles, UInt(beatBits.W)) 646cb6e5d3cSssszwic 647cb6e5d3cSssszwic def cacheline = respData.asUInt 648cb6e5d3cSssszwic } 649cb6e5d3cSssszwic val handleEntry = RegInit(0.U.asTypeOf((new HandleEntry).cloneType)) 650cb6e5d3cSssszwic 651cb6e5d3cSssszwic /** 652cb6e5d3cSssszwic ****************************************************************************** 653cb6e5d3cSssszwic * handle look-up request from IPrefetchPipe 654cb6e5d3cSssszwic * - 1. Receive request from IPrefetch 655cb6e5d3cSssszwic * - 2. Look up whether hit in PIQ and handleEntry 656cb6e5d3cSssszwic * - 3. Send response to IPrefetch at the same cycle 657cb6e5d3cSssszwic ****************************************************************************** 658cb6e5d3cSssszwic */ 659cb6e5d3cSssszwic val fr_block = get_block(fromIPrefetch.paddr) 660cb6e5d3cSssszwic val fr_hit_oh = PIQ.map(e => e.valid && (get_block(e.paddr) === fr_block)) :+ 661cb6e5d3cSssszwic (handleEntry.valid && (get_block(handleEntry.paddr) === fr_block)) 662cb6e5d3cSssszwic val fr_hit = ParallelOR(fr_hit_oh) 663cb6e5d3cSssszwic toIPrefetch.piq_hit := fr_hit 664cb6e5d3cSssszwic // only hit one entry in PIQ 665cb6e5d3cSssszwic assert(PopCount(fr_hit_oh) <= 1.U, "More than 1 hit in L1 PIQ for filter") 666cb6e5d3cSssszwic 667cb6e5d3cSssszwic 668cb6e5d3cSssszwic /** 669cb6e5d3cSssszwic ****************************************************************************** 670cb6e5d3cSssszwic * handle read request from ICacheMainPipe 671cb6e5d3cSssszwic * - 1. Receive request from ICacheMainPipe 672cb6e5d3cSssszwic * - 2. Look up PIQ and handleEntry 673cb6e5d3cSssszwic * - 3. Send response to ICacheMainPipe at the same cycle 674cb6e5d3cSssszwic ****************************************************************************** 675cb6e5d3cSssszwic */ 676cb6e5d3cSssszwic fromMainPipe.foreach(_.ready := DontCare) 677cb6e5d3cSssszwic val r_blocks = fromMainPipe.map (e => get_block(e.bits.paddr)) 678cb6e5d3cSssszwic /** When hit in PIQ, invalid hitted entry */ 679cb6e5d3cSssszwic val r_hit_oh = r_blocks.map (block => PIQ.map(e => e.valid && (get_block(e.paddr) === block))) 680cb6e5d3cSssszwic val curr_hit_ptr = r_hit_oh.map (OHToUInt(_)) 681cb6e5d3cSssszwic val r_hit_PIQ = (0 until PortNumber).map (i => ParallelOR(r_hit_oh(i)) && fromMainPipe(i).valid) 682cb6e5d3cSssszwic // only hit one entry in PIQ 683cb6e5d3cSssszwic (0 until PortNumber).map (i => 684cb6e5d3cSssszwic assert(PopCount(r_hit_oh(i)) <= 1.U, "More than 1 hit in L1 PIQ") 685cb6e5d3cSssszwic ) 686cb6e5d3cSssszwic 687cb6e5d3cSssszwic /** When hit in handleEntry has't been issued, cancel it and return not hit at the same cycle. 688cb6e5d3cSssszwic * When hit in handleEntry has been issued return hit at the same cycle, then return data when transiton finish. 689cb6e5d3cSssszwic * ICacheMainPipe should be blocked during handle handleEntry. 690cb6e5d3cSssszwic */ 691cb6e5d3cSssszwic val r_hit_handle = r_blocks.map(block => handleEntry.valid && (block === get_block(handleEntry.paddr))) 692cb6e5d3cSssszwic val cancelHandleEntry = (((0 until PortNumber).map(i=> fromMainPipe(i).valid && r_hit_handle(i))).reduce(_||_) || io.fencei) && !handleEntry.issue 693cb6e5d3cSssszwic val piq_hit = (0 until PortNumber).map(i => r_hit_handle(i) && handleEntry.issue && !handleEntry.flash && !io.fencei) 694cb6e5d3cSssszwic (0 until PortNumber).foreach (i => { 695cb6e5d3cSssszwic toMainPipe(i).piq_hit := piq_hit(i) 696cb6e5d3cSssszwic toMainPipe(i).cacheline := handleEntry.cacheline 697cb6e5d3cSssszwic toMainPipe(i).data_valid := handleEntry.valid && handleEntry.finish 6987052722fSJay }) 699cb6e5d3cSssszwic val piq_hit_req = RegEnable(piq_hit.reduce(_||_), fromMainPipe.map(_.valid).reduce(_||_)) 7007052722fSJay 701cb6e5d3cSssszwic /** 702cb6e5d3cSssszwic ****************************************************************************** 703cb6e5d3cSssszwic * Manage prefetch requests by queue 704cb6e5d3cSssszwic * - 1. Shift: entry shift when there are free entries behind 705cb6e5d3cSssszwic * - 2. Enqueue: receive prefetch request when first entry free 706cb6e5d3cSssszwic * - 3. Free: invalid the entry hitted mainpipe look up 707cb6e5d3cSssszwic * - 4. Fencei PIQ: invalid all PIQ entry when fencei 708cb6e5d3cSssszwic * - 5. Dequeue: move prefetch request from last entry to handle entry 709cb6e5d3cSssszwic * - 6. Cancel handleEntry hitted mainpipe if hasn't been issued 710cb6e5d3cSssszwic * - 7. Valid flash of handleEntry when fencei if has been issued 711cb6e5d3cSssszwic ****************************************************************************** 712cb6e5d3cSssszwic */ 713cb6e5d3cSssszwic /** 1. Shift: entry shift when there are free entries behind */ 714cb6e5d3cSssszwic val move = Wire(Vec(nPrefetchEntries, Bool())) 715cb6e5d3cSssszwic (0 until nPrefetchEntries).map (i => 716cb6e5d3cSssszwic // shift when there are invalid (free) entry behind 717cb6e5d3cSssszwic move(i) := ParallelOR((i+1 until nPrefetchEntries).map(!PIQ(_).valid) :+ !handleEntry.valid) 718cb6e5d3cSssszwic ) 719cb6e5d3cSssszwic (1 until nPrefetchEntries).map (i => 720cb6e5d3cSssszwic when(move(i-1)) { 721cb6e5d3cSssszwic PIQ(i) := PIQ(i-1) 722cb6e5d3cSssszwic } 723cb6e5d3cSssszwic ) 7247052722fSJay 725cb6e5d3cSssszwic /** 2. Enqueue: receive prefetch request to PIQ(0) when move(0) otherwise blocked*/ 726cb6e5d3cSssszwic enqueReq.ready := move(0) 727cb6e5d3cSssszwic when(move(0)) { 728cb6e5d3cSssszwic when(enqueReq.valid) { 729cb6e5d3cSssszwic PIQ(0).valid := true.B 730cb6e5d3cSssszwic PIQ(0).vSetIdx := enqueReq.bits.vSetIdx 731cb6e5d3cSssszwic PIQ(0).paddr := enqueReq.bits.paddr 732cb6e5d3cSssszwic }.otherwise { 733cb6e5d3cSssszwic PIQ(0).valid := false.B 734cb6e5d3cSssszwic } 735cb6e5d3cSssszwic } 736b1ded4e8Sguohongyu 737cb6e5d3cSssszwic /** 3. Free: invalid the entry hitted mainpipe */ 738cb6e5d3cSssszwic (0 until PortNumber) .map (i => 739cb6e5d3cSssszwic when(r_hit_PIQ(i)) { 740cb6e5d3cSssszwic when(move(curr_hit_ptr(i)) && (curr_hit_ptr(i) =/= (nPrefetchEntries-1).U)) { 741cb6e5d3cSssszwic // the hitted entry will be shifted, so invalid next entry 742cb6e5d3cSssszwic PIQ(curr_hit_ptr(i) + 1.U).valid := false.B 743cb6e5d3cSssszwic }.otherwise { 744cb6e5d3cSssszwic PIQ(curr_hit_ptr(i)).valid := false.B 745cb6e5d3cSssszwic } 746cb6e5d3cSssszwic } 747cb6e5d3cSssszwic ) 748cb6e5d3cSssszwic 749cb6e5d3cSssszwic /** 4. Fencei: invalid all PIQ entry when fencei */ 750cb6e5d3cSssszwic when(io.fencei) { 751cb6e5d3cSssszwic PIQ.map ( 752cb6e5d3cSssszwic _.valid := false.B 753cb6e5d3cSssszwic ) 754cb6e5d3cSssszwic } 755cb6e5d3cSssszwic 756cb6e5d3cSssszwic /** 5. Dequeue: move PIQ.last to handle entry when handle entry is free */ 757cb6e5d3cSssszwic // cancel entry when PIQ.last is hitted by mainpipe 758cb6e5d3cSssszwic val cancel = (0 until PortNumber).map (i => r_hit_PIQ(i) && (curr_hit_ptr(i) === (nPrefetchEntries-1).U)).reduce(_||_) 759cb6e5d3cSssszwic when(move(nPrefetchEntries - 1) && !cancel) { 760cb6e5d3cSssszwic handleEntry.valid := PIQ(nPrefetchEntries - 1).valid 761cb6e5d3cSssszwic handleEntry.paddr := PIQ(nPrefetchEntries - 1).paddr 762cb6e5d3cSssszwic handleEntry.vSetIdx := PIQ(nPrefetchEntries - 1).vSetIdx 763cb6e5d3cSssszwic handleEntry.issue := false.B 764cb6e5d3cSssszwic handleEntry.finish := false.B 765cb6e5d3cSssszwic handleEntry.flash := false.B 766cb6e5d3cSssszwic handleEntry.readBeatCnt := 0.U 767cb6e5d3cSssszwic } 768cb6e5d3cSssszwic 769cb6e5d3cSssszwic /** 6. Cancel handleEntry hitted mainpipe or receive fencei if hasn't been issued */ 770cb6e5d3cSssszwic when(cancelHandleEntry) { 771cb6e5d3cSssszwic handleEntry.valid := false.B 772cb6e5d3cSssszwic } 773cb6e5d3cSssszwic 774cb6e5d3cSssszwic /** 7. Valid flash of handleEntry when fencei. Drop data from TileLink port */ 775cb6e5d3cSssszwic when(io.fencei) { 776cb6e5d3cSssszwic handleEntry.flash := true.B 777cb6e5d3cSssszwic } 778cb6e5d3cSssszwic 779cb6e5d3cSssszwic 780cb6e5d3cSssszwic /** 781cb6e5d3cSssszwic ****************************************************************************** 782cb6e5d3cSssszwic * Write Prefetch Data to Prefetch Buffer 783cb6e5d3cSssszwic * - valid signal only hold one cycle 784cb6e5d3cSssszwic ****************************************************************************** 785cb6e5d3cSssszwic */ 786cb6e5d3cSssszwic toIPF.valid := handleEntry.valid && handleEntry.finish 787cb6e5d3cSssszwic toIPF.bits.paddr := handleEntry.paddr 788cb6e5d3cSssszwic toIPF.bits.vSetIdx := handleEntry.vSetIdx 789cb6e5d3cSssszwic toIPF.bits.cacheline := handleEntry.cacheline 790cb6e5d3cSssszwic toIPF.bits.has_hit := piq_hit_req 791cb6e5d3cSssszwic 792cb6e5d3cSssszwic 793cb6e5d3cSssszwic /** 794cb6e5d3cSssszwic ****************************************************************************** 795cb6e5d3cSssszwic * Tilelink Transition 796cb6e5d3cSssszwic * - 1. Send acquire to L2Cache, after which the request cannot be canceled (issue valid) 797cb6e5d3cSssszwic * - 2. Wait data response from Tilelink 798cb6e5d3cSssszwic * - 3. Get data, valid finish (only one cycle) and invalid issue 799cb6e5d3cSssszwic ****************************************************************************** 800cb6e5d3cSssszwic */ 801b1ded4e8Sguohongyu val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant) 802b1ded4e8Sguohongyu 803cb6e5d3cSssszwic val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: Nil = Enum(4) 804cb6e5d3cSssszwic val state = RegInit(s_idle) 805b1ded4e8Sguohongyu 806cb6e5d3cSssszwic // acquire port 807b1ded4e8Sguohongyu io.mem_acquire.bits := edge.Get( 808cb6e5d3cSssszwic fromSource = PortNumber.U, 809cb6e5d3cSssszwic toAddress = Cat(handleEntry.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)), 810b1ded4e8Sguohongyu lgSize = (log2Up(cacheParams.blockBytes)).U)._2 811d2b20d1aSTang Haojin io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B) 812d2b20d1aSTang Haojin io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U) 813b1ded4e8Sguohongyu 814cb6e5d3cSssszwic // grant port 815cb6e5d3cSssszwic io.mem_grant.ready := true.B 816cb6e5d3cSssszwic io.mem_acquire.valid := (state === s_memReadReq) 817cb6e5d3cSssszwic 818cb6e5d3cSssszwic switch(state) { 819cb6e5d3cSssszwic is(s_idle) { 820cb6e5d3cSssszwic when(handleEntry.valid && !cancelHandleEntry) { 821cb6e5d3cSssszwic handleEntry.issue := true.B 822cb6e5d3cSssszwic state := s_memReadReq 823cb6e5d3cSssszwic } 824cb6e5d3cSssszwic } 825cb6e5d3cSssszwic is(s_memReadReq) { 826935edac4STang Haojin state := Mux(io.mem_acquire.fire, s_memReadResp, s_memReadReq) 827cb6e5d3cSssszwic } 828cb6e5d3cSssszwic is(s_memReadResp) { 829935edac4STang Haojin when (edge.hasData(io.mem_grant.bits) && io.mem_grant.fire) { 830cb6e5d3cSssszwic handleEntry.readBeatCnt := handleEntry.readBeatCnt + 1.U 831cb6e5d3cSssszwic handleEntry.respData(handleEntry.readBeatCnt) := io.mem_grant.bits.data 832cb6e5d3cSssszwic when (handleEntry.readBeatCnt === (refillCycles - 1).U) { 833cb6e5d3cSssszwic assert(refill_done, "refill not done!") 834cb6e5d3cSssszwic state := s_write_back 835cb6e5d3cSssszwic when (!io.fencei && !handleEntry.flash) { 836cb6e5d3cSssszwic handleEntry.issue := false.B 837cb6e5d3cSssszwic handleEntry.finish := true.B 838cb6e5d3cSssszwic } 839cb6e5d3cSssszwic } 840cb6e5d3cSssszwic } 841cb6e5d3cSssszwic } 842cb6e5d3cSssszwic is(s_write_back) { 843cb6e5d3cSssszwic state := s_idle 844cb6e5d3cSssszwic handleEntry.valid := false.B 845cb6e5d3cSssszwic } 846cb6e5d3cSssszwic } 847cb6e5d3cSssszwic 848cb6e5d3cSssszwic if (env.EnableDifftest) { 849a0c65233SYinan Xu val diffipfrefill = DifftestModule(new DiffRefillEvent, dontCare = true) 8507d45a146SYinan Xu diffipfrefill.coreid := io.hartId 8517d45a146SYinan Xu diffipfrefill.index := 3.U 8527d45a146SYinan Xu diffipfrefill.valid := handleEntry.valid && handleEntry.finish 8537d45a146SYinan Xu diffipfrefill.addr := handleEntry.paddr 8547d45a146SYinan Xu diffipfrefill.data := handleEntry.cacheline.asTypeOf(diffipfrefill.data) 855935edac4STang Haojin diffipfrefill.idtfr := DontCare 856cb6e5d3cSssszwic } 857cb6e5d3cSssszwic} 858cb6e5d3cSssszwic 859cb6e5d3cSssszwicclass FDIPPrefetchIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle { 860cb6e5d3cSssszwic /** commen */ 861cb6e5d3cSssszwic val fencei = Input(Bool()) 862cb6e5d3cSssszwic val hartId = Input(UInt(8.W)) 863cb6e5d3cSssszwic 864cb6e5d3cSssszwic /** Prefetch Mainpipe IO */ 865cb6e5d3cSssszwic val ftqReq = Flipped(new FtqPrefechBundle) 866cb6e5d3cSssszwic val iTLBInter = new TlbRequestIO 867cb6e5d3cSssszwic val pmp = new ICachePMPBundle 868cb6e5d3cSssszwic val metaReadReq = Decoupled(new ICacheMetaReadReqBundle) 869cb6e5d3cSssszwic val metaReadResp = Input(new ICacheMetaReadRespBundle) 870cb6e5d3cSssszwic val mshrInfo = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W)))) 871cb6e5d3cSssszwic val mainPipeMissInfo = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo))) 872cb6e5d3cSssszwic 873cb6e5d3cSssszwic /** Prefetch Buffer IO */ 874cb6e5d3cSssszwic val IPFBufferRead = new IPFBufferRead 875cb6e5d3cSssszwic val metaWrite = DecoupledIO(new ICacheMetaWriteBundle) 876cb6e5d3cSssszwic val dataWrite = DecoupledIO(new ICacheDataWriteBundle) 877cb6e5d3cSssszwic val IPFReplacer = new IPFReplacer 878cb6e5d3cSssszwic 879cb6e5d3cSssszwic /** Prefetch Queue IO */ 880cb6e5d3cSssszwic val PIQRead = new PIQRead 881cb6e5d3cSssszwic val mem_acquire = new DecoupledIO(new TLBundleA(edge.bundle)) 882cb6e5d3cSssszwic val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 883cb6e5d3cSssszwic} 884cb6e5d3cSssszwic 885cb6e5d3cSssszwicclass FDIPPrefetch(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule 886cb6e5d3cSssszwic{ 887cb6e5d3cSssszwic val io = IO(new FDIPPrefetchIO(edge)) 888cb6e5d3cSssszwic 889cb6e5d3cSssszwic val prefetchPipe = Module(new IPrefetchPipe) 890cb6e5d3cSssszwic val prefetchQueue = Module(new PrefetchQueue(edge)) 891cb6e5d3cSssszwic val prefetchBuffer = Module(new PrefetchBuffer) 892cb6e5d3cSssszwic 893cb6e5d3cSssszwic io.metaReadReq <> prefetchPipe.io.metaReadReq 894cb6e5d3cSssszwic io.metaWrite <> prefetchBuffer.io.metaWrite 895cb6e5d3cSssszwic io.dataWrite <> prefetchBuffer.io.dataWrite 896cb6e5d3cSssszwic io.IPFReplacer <> prefetchBuffer.io.IPFReplacer 897cb6e5d3cSssszwic io.mem_acquire <> prefetchQueue.io.mem_acquire 898cb6e5d3cSssszwic io.mem_grant <> prefetchQueue.io.mem_grant 899cb6e5d3cSssszwic 900cb6e5d3cSssszwic // outside 901cb6e5d3cSssszwic prefetchPipe.io.fencei <> io.fencei 902cb6e5d3cSssszwic prefetchPipe.io.ftqReq <> io.ftqReq 903cb6e5d3cSssszwic prefetchPipe.io.iTLBInter <> io.iTLBInter 904cb6e5d3cSssszwic prefetchPipe.io.pmp <> io.pmp 905cb6e5d3cSssszwic prefetchPipe.io.metaReadResp <> io.metaReadResp 906cb6e5d3cSssszwic prefetchPipe.io.mshrInfo <> io.mshrInfo 907cb6e5d3cSssszwic prefetchPipe.io.mainPipeMissInfo <> io.mainPipeMissInfo 908cb6e5d3cSssszwic 909cb6e5d3cSssszwic // outside 910cb6e5d3cSssszwic prefetchBuffer.io.hartId <> io.hartId 911cb6e5d3cSssszwic prefetchBuffer.io.fencei <> io.fencei 912cb6e5d3cSssszwic prefetchBuffer.io.IPFBufferRead <> io.IPFBufferRead 913cb6e5d3cSssszwic // inside 914cb6e5d3cSssszwic prefetchBuffer.io.IPFFilterRead <> prefetchPipe.io.IPFFilterRead 915cb6e5d3cSssszwic prefetchBuffer.io.IPFBufferWrite <> prefetchQueue.io.IPFBufferWrite 916cb6e5d3cSssszwic 917cb6e5d3cSssszwic // outside 918cb6e5d3cSssszwic prefetchQueue.io.hartId <> io.hartId 919cb6e5d3cSssszwic prefetchQueue.io.fencei <> io.fencei 920cb6e5d3cSssszwic prefetchQueue.io.PIQRead <> io.PIQRead 921cb6e5d3cSssszwic // inside 922cb6e5d3cSssszwic prefetchQueue.io.prefetchReq <> prefetchPipe.io.prefetchReq 923cb6e5d3cSssszwic prefetchQueue.io.PIQFilterRead <> prefetchPipe.io.PIQFilterRead 9247052722fSJay} 925