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._ 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) { 250*a0c65233SYinan 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) 25664d7d412Sguohongyu } 25764d7d412Sguohongyu} 258b1ded4e8Sguohongyu 259cb6e5d3cSssszwicclass IPredfetchIO(implicit p: Parameters) extends IPrefetchBundle { 260cb6e5d3cSssszwic val ftqReq = Flipped(new FtqPrefechBundle) 261cb6e5d3cSssszwic val iTLBInter = new TlbRequestIO 262cb6e5d3cSssszwic val pmp = new ICachePMPBundle 263cb6e5d3cSssszwic val metaReadReq = Decoupled(new ICacheMetaReadReqBundle) 264cb6e5d3cSssszwic val metaReadResp = Input(new ICacheMetaReadRespBundle) 265cb6e5d3cSssszwic val prefetchReq = DecoupledIO(new PrefetchReq) 266cb6e5d3cSssszwic val mshrInfo = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W)))) 267cb6e5d3cSssszwic val IPFFilterRead = Flipped(new IPFBufferFilterRead) 268cb6e5d3cSssszwic val PIQFilterRead = Flipped(new PIQFilterRead) 269cb6e5d3cSssszwic /** icache main pipe to prefetch pipe */ 270cb6e5d3cSssszwic val mainPipeMissInfo = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo))) 271cb6e5d3cSssszwic val fencei = Input(Bool()) 2727052722fSJay} 2737052722fSJay 2747052722fSJayclass IPrefetchPipe(implicit p: Parameters) extends IPrefetchModule 2757052722fSJay{ 2767052722fSJay val io = IO(new IPredfetchIO) 2777052722fSJay 278a108d429SJay val enableBit = RegInit(false.B) 279cb6e5d3cSssszwic enableBit := false.B 280a108d429SJay 281cb6e5d3cSssszwic val fromFtq = io.ftqReq 282cb6e5d3cSssszwic val mainPipeMissInfo = io.mainPipeMissInfo 2837052722fSJay val (toITLB, fromITLB) = (io.iTLBInter.req, io.iTLBInter.resp) 284cb6e5d3cSssszwic val (toIMeta, fromIMeta, fromIMetaValid) = (io.metaReadReq, io.metaReadResp.metaData, io.metaReadResp.entryValid) 285cb6e5d3cSssszwic val (toIPFBuffer, fromIPFBuffer) = (io.IPFFilterRead.req, io.IPFFilterRead.resp) 286cb6e5d3cSssszwic val (toPIQ, fromPIQ) = (io.PIQFilterRead.req, io.PIQFilterRead.resp) 2877052722fSJay val (toPMP, fromPMP) = (io.pmp.req, io.pmp.resp) 288cb6e5d3cSssszwic val fromMSHR = io.mshrInfo 289cb6e5d3cSssszwic val toPIQEnqReq = io.prefetchReq 2907052722fSJay 291cb6e5d3cSssszwic val p0_fire, p1_fire, p2_fire = WireInit(false.B) 292cb6e5d3cSssszwic val p0_discard, p1_discard, p2_discard = WireInit(false.B) 293cb6e5d3cSssszwic val p0_ready, p1_ready, p2_ready = WireInit(false.B) 2947052722fSJay 295cb6e5d3cSssszwic /** 296cb6e5d3cSssszwic ****************************************************************************** 297cb6e5d3cSssszwic * IPrefetch Stage 0 298cb6e5d3cSssszwic * - 1. send req to IMeta 299cb6e5d3cSssszwic * - 2. send req to ITLB (no blocked) 300cb6e5d3cSssszwic * - 3. check last req 301cb6e5d3cSssszwic ****************************************************************************** 302cb6e5d3cSssszwic */ 3037052722fSJay val p0_valid = fromFtq.req.valid 304cb6e5d3cSssszwic 305d6b06a99SJay val p0_vaddr = addrAlign(fromFtq.req.bits.target, blockBytes, VAddrBits) 306cb6e5d3cSssszwic val p0_vaddr_reg = RegEnable(p0_vaddr, p0_fire) 307cb6e5d3cSssszwic val p0_req_cancel = Wire(Bool()) 3087052722fSJay 309cb6e5d3cSssszwic /** 1. send req to IMeta */ 3109bba777eSssszwic toIMeta.valid := p0_valid && !p0_req_cancel 3110c26d810Sguohongyu toIMeta.bits.idx := get_idx(p0_vaddr) 3127052722fSJay 313cb6e5d3cSssszwic /** 2. send req to ITLB (no blocked) */ 3149bba777eSssszwic toITLB.valid := p0_valid && !p0_req_cancel 3157052722fSJay toITLB.bits.size := 3.U // TODO: fix the size 3167052722fSJay toITLB.bits.vaddr := p0_vaddr 3177052722fSJay toITLB.bits.debug.pc := p0_vaddr 318f1fe8698SLemover toITLB.bits.kill := DontCare 3197052722fSJay toITLB.bits.cmd := TlbCmd.exec 320f1fe8698SLemover toITLB.bits.debug.robIdx := DontCare 3217052722fSJay toITLB.bits.debug.isFirstIssue := DontCare 322b1ded4e8Sguohongyu toITLB.bits.memidx := DontCare 323b1ded4e8Sguohongyu toITLB.bits.no_translate := false.B 3247052722fSJay fromITLB.ready := true.B 325cb6e5d3cSssszwic // TODO: whether to handle tlb miss for prefetch 326cb6e5d3cSssszwic io.iTLBInter.req_kill := false.B 3277052722fSJay 328cb6e5d3cSssszwic /** FTQ request port */ 329cb6e5d3cSssszwic fromFtq.req.ready := p0_ready 3307052722fSJay 331cb6e5d3cSssszwic /** 3. Check last req: request from FTQ is same as last time or behind */ 332cb6e5d3cSssszwic val p0_hit_behind = Wire(Bool()) 333cb6e5d3cSssszwic 334cb6e5d3cSssszwic /** stage 0 control */ 335cb6e5d3cSssszwic // Cancel request when prefetch not enable or the request from FTQ is same as last time 336cb6e5d3cSssszwic p0_req_cancel := !enableBit || p0_hit_behind || io.fencei 337cb6e5d3cSssszwic p0_ready := p0_req_cancel || p1_ready && toITLB.ready && toIMeta.ready 338cb6e5d3cSssszwic p0_fire := p0_valid && p1_ready && toITLB.ready && toIMeta.ready && enableBit && !p0_req_cancel 339cb6e5d3cSssszwic p0_discard := p0_valid && p0_req_cancel 340cb6e5d3cSssszwic 341cb6e5d3cSssszwic if(DebugFlags.fdip) { 342cb6e5d3cSssszwic when(p0_discard) { 343cb6e5d3cSssszwic printf(p"IPrefetchPipe: discard req in s0.") 344cb6e5d3cSssszwic } 345cb6e5d3cSssszwic } 346cb6e5d3cSssszwic 347cb6e5d3cSssszwic /** 348cb6e5d3cSssszwic ****************************************************************************** 349cb6e5d3cSssszwic * IPrefetch Stage 1 350cb6e5d3cSssszwic * - 1. Receive resp from ITLB (no blocked) 351cb6e5d3cSssszwic * - 2. Receive resp from IMeta 352cb6e5d3cSssszwic * - 3. Check MSHR 353cb6e5d3cSssszwic ****************************************************************************** 354cb6e5d3cSssszwic */ 3557052722fSJay val p1_valid = generatePipeControl(lastFire = p0_fire, thisFire = p1_fire || p1_discard, thisFlush = false.B, lastFlush = false.B) 356cb6e5d3cSssszwic 357005e809bSJiuyang Liu val p1_vaddr = RegEnable(p0_vaddr, p0_fire) 358cb6e5d3cSssszwic val p1_req_cancel = Wire(Bool()) 3597052722fSJay 360cb6e5d3cSssszwic /** 1. Receive resp from ITLB (no blocked) */ 361cb6e5d3cSssszwic val p1_tlb_resp_miss = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.miss) 362cb6e5d3cSssszwic val p1_tlb_resp_paddr = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.paddr(0)) 363cb6e5d3cSssszwic val p1_tlb_resp_pf = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).pf.instr) 364cb6e5d3cSssszwic val p1_tlb_resp_af = ResultHoldBypass(valid = RegNext(p0_fire), data = fromITLB.bits.excp(0).af.instr) 365cb6e5d3cSssszwic val p1_exception = VecInit(Seq(p1_tlb_resp_pf, p1_tlb_resp_af)) 3667052722fSJay val p1_has_except = p1_exception.reduce(_ || _) 367cb6e5d3cSssszwic val p1_paddr = p1_tlb_resp_paddr 3687052722fSJay 369cb6e5d3cSssszwic /** 2. Receive resp from IMeta. Register the data first because of strict timing. */ 3709bba777eSssszwic val p1_meta_ptags_reg = RegEnable(VecInit(fromIMeta.map(way => way.tag)), RegNext(p0_fire)) 3719bba777eSssszwic val p1_meta_valids_reg = RegEnable(fromIMetaValid, RegNext(p0_fire)) 3727052722fSJay 373cb6e5d3cSssszwic /** 3. Check MSHR */ 374cb6e5d3cSssszwic val p1_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p1_paddr, blockBytes, PAddrBits))).reduce(_||_) 375b1ded4e8Sguohongyu 376cb6e5d3cSssszwic /** Stage 1 control */ 377cb6e5d3cSssszwic p1_req_cancel := p1_check_in_mshr || p1_tlb_resp_miss || p1_has_except || io.fencei 3789bba777eSssszwic p1_ready := p1_valid && p2_ready || !p1_valid 3799bba777eSssszwic p1_fire := p1_valid && !p1_req_cancel && p2_ready && enableBit 3809bba777eSssszwic p1_discard := p1_valid && p1_req_cancel 3817052722fSJay 382cb6e5d3cSssszwic when(p1_discard) { 383cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: discard req in s1. vaddr:${p1_vaddr}") 384cb6e5d3cSssszwic } 385cb6e5d3cSssszwic 386cb6e5d3cSssszwic /** 387cb6e5d3cSssszwic ****************************************************************************** 388cb6e5d3cSssszwic * IPrefetch Stage 2 389cb6e5d3cSssszwic * - 1. IMeta Check: check whether req hit in icache 390cb6e5d3cSssszwic * - 2. PMP Check: send req and receive resq in the same cycle 391cb6e5d3cSssszwic * - 3. Check miss handling by main pipe 392cb6e5d3cSssszwic * - 4. Prefetch buffer Check 393cb6e5d3cSssszwic * - 5. Prefetch Queue Check 394cb6e5d3cSssszwic * - 6. MSHR check 395cb6e5d3cSssszwic * - 7. send req to piq 396cb6e5d3cSssszwic ****************************************************************************** 397cb6e5d3cSssszwic */ 3987052722fSJay val p2_valid = generatePipeControl(lastFire = p1_fire, thisFire = p2_fire || p2_discard, thisFlush = false.B, lastFlush = false.B) 399cb6e5d3cSssszwic 4009bba777eSssszwic val p2_paddr = RegEnable(p1_paddr, p1_fire) 4019bba777eSssszwic val p2_vaddr = RegEnable(p1_vaddr, p1_fire) 402cb6e5d3cSssszwic val p2_req_cancel = Wire(Bool()) 403cb6e5d3cSssszwic val p2_vidx = get_idx(p2_vaddr) 4049bba777eSssszwic 405cb6e5d3cSssszwic p0_hit_behind := (p0_vaddr === p1_vaddr) || (p0_vaddr === p2_vaddr) 406cb6e5d3cSssszwic 407cb6e5d3cSssszwic /** 1. IMeta Check */ 4089bba777eSssszwic val p2_ptag = get_phy_tag(p2_paddr) 4099bba777eSssszwic val p2_tag_eq_vec = VecInit(p1_meta_ptags_reg.map(_ === p2_ptag )) 4109bba777eSssszwic 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)}) 4119bba777eSssszwic val p2_tag_match = DataHoldBypass(ParallelOR(p2_tag_match_vec), RegNext(p1_fire)) 4129bba777eSssszwic 413cb6e5d3cSssszwic /** 2. PMP Check */ 414cb6e5d3cSssszwic // TODO: When fromPMP.mmio is low but fromPMP.instr is high, which is a except? 415cb6e5d3cSssszwic val p2_exception = DataHoldBypass((fromPMP.mmio && !fromPMP.instr) || fromPMP.instr, RegNext(p1_fire)) 416cb6e5d3cSssszwic // PMP request 417cb6e5d3cSssszwic toPMP.valid := p2_valid 4189bba777eSssszwic toPMP.bits.addr := p2_paddr 4199bba777eSssszwic toPMP.bits.size := 3.U 4209bba777eSssszwic toPMP.bits.cmd := TlbCmd.exec 421b1ded4e8Sguohongyu 422cb6e5d3cSssszwic /** 3. Check miss handling by main pipe */ 423cb6e5d3cSssszwic val p2_hit_mp_miss = VecInit((0 until PortNumber).map(i => 424cb6e5d3cSssszwic mainPipeMissInfo(i).valid && (mainPipeMissInfo(i).bits.ptage === p2_ptag && 425cb6e5d3cSssszwic (mainPipeMissInfo(i).bits.vSetIdx === p2_vidx)))).reduce(_||_) 42600240ba6SJay 427cb6e5d3cSssszwic /** 4. Prefetch buffer Check */ 428cb6e5d3cSssszwic toIPFBuffer.paddr := p2_paddr 429cb6e5d3cSssszwic val p2_hit_buffer = fromIPFBuffer.ipf_hit 430cb6e5d3cSssszwic 431cb6e5d3cSssszwic /** 5. Prefetch Queue Check */ 432cb6e5d3cSssszwic toPIQ.paddr := p2_paddr 433cb6e5d3cSssszwic val p2_hit_piq = fromPIQ.piq_hit 434cb6e5d3cSssszwic 435cb6e5d3cSssszwic /** 6. MSHR check */ 436cb6e5d3cSssszwic val p2_check_in_mshr = VecInit(fromMSHR.map(mshr => mshr.valid && mshr.bits === addrAlign(p2_paddr, blockBytes, PAddrBits))).reduce(_||_) 437cb6e5d3cSssszwic 438cb6e5d3cSssszwic /** 7. send req to piq */ 439cb6e5d3cSssszwic toPIQEnqReq.valid := p2_valid && !p2_req_cancel 440cb6e5d3cSssszwic toPIQEnqReq.bits.paddr := p2_paddr 441cb6e5d3cSssszwic toPIQEnqReq.bits.vSetIdx := p2_vidx 442cb6e5d3cSssszwic 443cb6e5d3cSssszwic /** Stage 2 control */ 444cb6e5d3cSssszwic p2_req_cancel := p2_tag_match || p2_exception || p2_hit_mp_miss || p2_hit_buffer || p2_hit_piq || p2_check_in_mshr || io.fencei 445cb6e5d3cSssszwic p2_ready := p2_valid && toPIQEnqReq.ready || !p2_valid 446cb6e5d3cSssszwic p2_fire := toPIQEnqReq.fire() 4479bba777eSssszwic p2_discard := p2_valid && p2_req_cancel 448b1ded4e8Sguohongyu 449cb6e5d3cSssszwic when(p2_discard) { 450cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: discard req in s2. vaddr:${p2_vaddr}") 451cb6e5d3cSssszwic } 4529bba777eSssszwic 453cb6e5d3cSssszwic when(p2_fire) { 454cb6e5d3cSssszwic XSDebug(p"IPrefetchPipe: send req to PIQ. vaddr:${p2_vaddr} paddr:${p2_paddr}") 455cb6e5d3cSssszwic } 4569bba777eSssszwic 457cb6e5d3cSssszwic /** PerfAccumulate */ 458cb6e5d3cSssszwic // the number of prefetch request received from ftq 459cb6e5d3cSssszwic XSPerfAccumulate("prefetch_req_receive", fromFtq.req.fire()) 460cb6e5d3cSssszwic // the number of prefetch request sent to PIQ 461cb6e5d3cSssszwic XSPerfAccumulate("prefetch_req_send", toPIQEnqReq.fire()) 462cb6e5d3cSssszwic /** 463cb6e5d3cSssszwic * Count the number of requests that are filtered for various reasons. 464cb6e5d3cSssszwic * The number of prefetch discard in Performance Accumulator may be 465cb6e5d3cSssszwic * a littel larger the number of really discarded. Because there can 466cb6e5d3cSssszwic * be multiple reasons for a canceled request at the same time. 467cb6e5d3cSssszwic */ 468cb6e5d3cSssszwic // discard prefetch request by fencei instruction 469cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_fencei", (p0_discard || p1_discard || p2_discard) && io.fencei) 470cb6e5d3cSssszwic // discard prefetch request by hit hit MSHR 471cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_mshr", (p1_discard && p1_check_in_mshr) || (p2_discard && p2_check_in_mshr)) 472cb6e5d3cSssszwic // discard prefetch request by the request is same as pipeline behind 473cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_behind", p0_discard && p0_hit_behind) 474cb6e5d3cSssszwic // discard prefetch request by tlb miss 475cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_tlb_miss", p1_discard && p1_tlb_resp_miss) 476cb6e5d3cSssszwic // discard prefetch request by tlb except 477cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_tlb_except", p1_discard && p1_has_except) 478cb6e5d3cSssszwic // discard prefetch request by hit icache 479cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_cache", p2_discard && p2_tag_match) 480cb6e5d3cSssszwic // discard prefetch request by pmp except or mmio 481cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_pmp", p2_discard && p2_exception) 482cb6e5d3cSssszwic // discard prefetch request by req is handling by icache mainpipe 483cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_mp", p2_discard && p2_hit_mp_miss) 484cb6e5d3cSssszwic // discard prefetch request by hit in prefetch buffer 485cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_pf", p2_discard && p2_hit_buffer) 486cb6e5d3cSssszwic // discard prefetch request by hit in prefetch queue 487cb6e5d3cSssszwic XSPerfAccumulate("fdip_prefetch_discard_by_hit_piq", p2_discard && p2_hit_piq) 488cb6e5d3cSssszwic} 4897052722fSJay 490cb6e5d3cSssszwic// class PIQEntry(edge: TLEdgeOut, id: Int)(implicit p: Parameters) extends IPrefetchModule 491cb6e5d3cSssszwic// { 492cb6e5d3cSssszwic// val io = IO(new Bundle{ 493cb6e5d3cSssszwic// val id = Input(UInt((log2Ceil(nPrefetchEntries + PortNumber)).W)) 4949bba777eSssszwic 495cb6e5d3cSssszwic// val req = Flipped(DecoupledIO(new PIQReq)) 496a108d429SJay 497cb6e5d3cSssszwic// val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 498cb6e5d3cSssszwic// val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 4997052722fSJay 500cb6e5d3cSssszwic// // write back to Prefetch Buffer 501cb6e5d3cSssszwic// val piq_write_ipbuffer = DecoupledIO(new IPFBufferWrite) 5029bba777eSssszwic 503cb6e5d3cSssszwic// val fencei = Input(Bool()) 504cb6e5d3cSssszwic 505cb6e5d3cSssszwic// val prefetch_entry_data = DecoupledIO(new PIQData) 506cb6e5d3cSssszwic 507cb6e5d3cSssszwic// val ongoing_req = ValidIO(UInt(PAddrBits.W)) 508cb6e5d3cSssszwic// }) 509cb6e5d3cSssszwic 510cb6e5d3cSssszwic// val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: s_finish:: Nil = Enum(5) 511cb6e5d3cSssszwic// val state = RegInit(s_idle) 512cb6e5d3cSssszwic 513cb6e5d3cSssszwic// //req register 514cb6e5d3cSssszwic// val req = Reg(new PIQReq) 515cb6e5d3cSssszwic// val req_idx = req.vSetIdx //virtual index 516cb6e5d3cSssszwic// val req_tag = get_phy_tag(req.paddr) //physical tag 517cb6e5d3cSssszwic 518cb6e5d3cSssszwic// val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant) 519cb6e5d3cSssszwic 520cb6e5d3cSssszwic// //8 for 64 bits bus and 2 for 256 bits 521cb6e5d3cSssszwic// val readBeatCnt = Reg(UInt(log2Up(refillCycles).W)) 522cb6e5d3cSssszwic// val respDataReg = Reg(Vec(refillCycles,UInt(beatBits.W))) 523cb6e5d3cSssszwic 524cb6e5d3cSssszwic// //to main pipe s1 525cb6e5d3cSssszwic// io.prefetch_entry_data.valid := state =/= s_idle 526cb6e5d3cSssszwic// io.prefetch_entry_data.bits.vSetIdx := req_idx 527cb6e5d3cSssszwic// io.prefetch_entry_data.bits.ptage := req_tag 528cb6e5d3cSssszwic// io.prefetch_entry_data.bits.cacheline := respDataReg.asUInt 529cb6e5d3cSssszwic// io.prefetch_entry_data.bits.writeBack := state === s_write_back 530cb6e5d3cSssszwic 531cb6e5d3cSssszwic// //initial 532cb6e5d3cSssszwic// io.mem_acquire.bits := DontCare 533cb6e5d3cSssszwic// io.mem_grant.ready := true.B 534cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits:= DontCare 535cb6e5d3cSssszwic 536cb6e5d3cSssszwic// io.req.ready := state === s_idle 537cb6e5d3cSssszwic// io.mem_acquire.valid := state === s_memReadReq 538cb6e5d3cSssszwic 539cb6e5d3cSssszwic// val needflush_r = RegInit(false.B) 540cb6e5d3cSssszwic// when (state === s_idle) { needflush_r := false.B } 541cb6e5d3cSssszwic// when (state =/= s_idle && io.fencei) { needflush_r := true.B } 542cb6e5d3cSssszwic// val needflush = needflush_r | io.fencei 543cb6e5d3cSssszwic 544cb6e5d3cSssszwic// //state change 545cb6e5d3cSssszwic// switch(state){ 546cb6e5d3cSssszwic// is(s_idle){ 547cb6e5d3cSssszwic// when(io.req.fire()){ 548cb6e5d3cSssszwic// readBeatCnt := 0.U 549cb6e5d3cSssszwic// state := s_memReadReq 550cb6e5d3cSssszwic// req := io.req.bits 551974a902cSguohongyu// } 552cb6e5d3cSssszwic// } 5537052722fSJay 554cb6e5d3cSssszwic// // memory request 555cb6e5d3cSssszwic// is(s_memReadReq){ 556cb6e5d3cSssszwic// when(io.mem_acquire.fire()){ 557cb6e5d3cSssszwic// state := s_memReadResp 558cb6e5d3cSssszwic// } 559cb6e5d3cSssszwic// } 5607052722fSJay 561cb6e5d3cSssszwic// is(s_memReadResp){ 562cb6e5d3cSssszwic// when (edge.hasData(io.mem_grant.bits)) { 563cb6e5d3cSssszwic// when (io.mem_grant.fire()) { 564cb6e5d3cSssszwic// readBeatCnt := readBeatCnt + 1.U 565cb6e5d3cSssszwic// respDataReg(readBeatCnt) := io.mem_grant.bits.data 566cb6e5d3cSssszwic// when (readBeatCnt === (refillCycles - 1).U) { 567cb6e5d3cSssszwic// assert(refill_done, "refill not done!") 568cb6e5d3cSssszwic// state := s_write_back 569cb6e5d3cSssszwic// } 570cb6e5d3cSssszwic// } 571cb6e5d3cSssszwic// } 572cb6e5d3cSssszwic// } 5737052722fSJay 574cb6e5d3cSssszwic// is(s_write_back){ 575cb6e5d3cSssszwic// state := Mux(io.piq_write_ipbuffer.fire() || needflush, s_finish, s_write_back) 576cb6e5d3cSssszwic// } 577cb6e5d3cSssszwic 578cb6e5d3cSssszwic// is(s_finish){ 579cb6e5d3cSssszwic// state := s_idle 580cb6e5d3cSssszwic// } 581cb6e5d3cSssszwic// } 582cb6e5d3cSssszwic 583cb6e5d3cSssszwic// //refill write and meta write 584cb6e5d3cSssszwic// //WARNING: Maybe could not finish refill in 1 cycle 585cb6e5d3cSssszwic// io.piq_write_ipbuffer.valid := (state === s_write_back) && !needflush 586cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.tag := req_tag 587cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.index := req_idx 588cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.meta.paddr := req.paddr 589cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.data := respDataReg.asUInt 590cb6e5d3cSssszwic// io.piq_write_ipbuffer.bits.buffIdx := io.id - PortNumber.U 591cb6e5d3cSssszwic 592cb6e5d3cSssszwic// io.ongoing_req.valid := state =/= s_idle 593cb6e5d3cSssszwic// io.ongoing_req.bits := addrAlign(req.paddr, blockBytes, PAddrBits) 594cb6e5d3cSssszwic 595cb6e5d3cSssszwic// XSPerfAccumulate("PrefetchEntryReq" + Integer.toString(id, 10), io.req.fire()) 596cb6e5d3cSssszwic 597cb6e5d3cSssszwic// //mem request 598cb6e5d3cSssszwic// io.mem_acquire.bits := edge.Get( 599cb6e5d3cSssszwic// fromSource = io.id, 600cb6e5d3cSssszwic// toAddress = Cat(req.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)), 601cb6e5d3cSssszwic// lgSize = (log2Up(cacheParams.blockBytes)).U)._2 602cb6e5d3cSssszwic// io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B) 603cb6e5d3cSssszwic// io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U) 604cb6e5d3cSssszwic// } 605cb6e5d3cSssszwic 606cb6e5d3cSssszwicclass PrefetchQueueIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle { 607cb6e5d3cSssszwic val hartId = Input(UInt(8.W)) 608cb6e5d3cSssszwic val prefetchReq = Flipped(DecoupledIO(new PrefetchReq)) 609cb6e5d3cSssszwic val PIQFilterRead = new PIQFilterRead 610cb6e5d3cSssszwic val PIQRead = new PIQRead 611cb6e5d3cSssszwic val IPFBufferWrite = DecoupledIO(new IPFBufferWrite) 612cb6e5d3cSssszwic /** TileLink Port */ 613b1ded4e8Sguohongyu val mem_acquire = DecoupledIO(new TLBundleA(edge.bundle)) 614b1ded4e8Sguohongyu val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 615b1ded4e8Sguohongyu val fencei = Input(Bool()) 616cb6e5d3cSssszwic} 617b1ded4e8Sguohongyu 618cb6e5d3cSssszwicclass PrefetchQueue(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule { 619cb6e5d3cSssszwic val io = IO(new PrefetchQueueIO(edge)) 620974a902cSguohongyu 621cb6e5d3cSssszwic val enqueReq = io.prefetchReq 622cb6e5d3cSssszwic val fromIPrefetch = io.PIQFilterRead.req 623cb6e5d3cSssszwic val toIPrefetch = io.PIQFilterRead.resp 624cb6e5d3cSssszwic val fromMainPipe = io.PIQRead.req 625cb6e5d3cSssszwic val toMainPipe = io.PIQRead.resp 626cb6e5d3cSssszwic val toIPF = io.IPFBufferWrite 627cb6e5d3cSssszwic 628cb6e5d3cSssszwic /** Define entryt content and initial FIFO queue */ 629cb6e5d3cSssszwic class PrefetchEntry(implicit p: Parameters) extends IPrefetchBundle { 630cb6e5d3cSssszwic val valid = Bool() 631cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 632cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 633cb6e5d3cSssszwic } 634cb6e5d3cSssszwic val PIQ = RegInit(VecInit(Seq.fill(nPrefetchEntries)(0.U.asTypeOf((new PrefetchEntry).cloneType)))) 635cb6e5d3cSssszwic 636cb6e5d3cSssszwic class HandleEntry(implicit p: Parameters) extends IPrefetchBundle { 637cb6e5d3cSssszwic val valid = Bool() 638cb6e5d3cSssszwic val paddr = UInt(PAddrBits.W) 639cb6e5d3cSssszwic val vSetIdx = UInt(idxBits.W) 640cb6e5d3cSssszwic val issue = Bool() 641cb6e5d3cSssszwic val finish = Bool() 642cb6e5d3cSssszwic val flash = Bool() 643cb6e5d3cSssszwic val readBeatCnt = UInt(log2Up(refillCycles).W) 644cb6e5d3cSssszwic val respData = Vec(refillCycles, UInt(beatBits.W)) 645cb6e5d3cSssszwic 646cb6e5d3cSssszwic def cacheline = respData.asUInt 647cb6e5d3cSssszwic } 648cb6e5d3cSssszwic val handleEntry = RegInit(0.U.asTypeOf((new HandleEntry).cloneType)) 649cb6e5d3cSssszwic 650cb6e5d3cSssszwic /** 651cb6e5d3cSssszwic ****************************************************************************** 652cb6e5d3cSssszwic * handle look-up request from IPrefetchPipe 653cb6e5d3cSssszwic * - 1. Receive request from IPrefetch 654cb6e5d3cSssszwic * - 2. Look up whether hit in PIQ and handleEntry 655cb6e5d3cSssszwic * - 3. Send response to IPrefetch at the same cycle 656cb6e5d3cSssszwic ****************************************************************************** 657cb6e5d3cSssszwic */ 658cb6e5d3cSssszwic val fr_block = get_block(fromIPrefetch.paddr) 659cb6e5d3cSssszwic val fr_hit_oh = PIQ.map(e => e.valid && (get_block(e.paddr) === fr_block)) :+ 660cb6e5d3cSssszwic (handleEntry.valid && (get_block(handleEntry.paddr) === fr_block)) 661cb6e5d3cSssszwic val fr_hit = ParallelOR(fr_hit_oh) 662cb6e5d3cSssszwic toIPrefetch.piq_hit := fr_hit 663cb6e5d3cSssszwic // only hit one entry in PIQ 664cb6e5d3cSssszwic assert(PopCount(fr_hit_oh) <= 1.U, "More than 1 hit in L1 PIQ for filter") 665cb6e5d3cSssszwic 666cb6e5d3cSssszwic 667cb6e5d3cSssszwic /** 668cb6e5d3cSssszwic ****************************************************************************** 669cb6e5d3cSssszwic * handle read request from ICacheMainPipe 670cb6e5d3cSssszwic * - 1. Receive request from ICacheMainPipe 671cb6e5d3cSssszwic * - 2. Look up PIQ and handleEntry 672cb6e5d3cSssszwic * - 3. Send response to ICacheMainPipe at the same cycle 673cb6e5d3cSssszwic ****************************************************************************** 674cb6e5d3cSssszwic */ 675cb6e5d3cSssszwic fromMainPipe.foreach(_.ready := DontCare) 676cb6e5d3cSssszwic val r_blocks = fromMainPipe.map (e => get_block(e.bits.paddr)) 677cb6e5d3cSssszwic /** When hit in PIQ, invalid hitted entry */ 678cb6e5d3cSssszwic val r_hit_oh = r_blocks.map (block => PIQ.map(e => e.valid && (get_block(e.paddr) === block))) 679cb6e5d3cSssszwic val curr_hit_ptr = r_hit_oh.map (OHToUInt(_)) 680cb6e5d3cSssszwic val r_hit_PIQ = (0 until PortNumber).map (i => ParallelOR(r_hit_oh(i)) && fromMainPipe(i).valid) 681cb6e5d3cSssszwic // only hit one entry in PIQ 682cb6e5d3cSssszwic (0 until PortNumber).map (i => 683cb6e5d3cSssszwic assert(PopCount(r_hit_oh(i)) <= 1.U, "More than 1 hit in L1 PIQ") 684cb6e5d3cSssszwic ) 685cb6e5d3cSssszwic 686cb6e5d3cSssszwic /** When hit in handleEntry has't been issued, cancel it and return not hit at the same cycle. 687cb6e5d3cSssszwic * When hit in handleEntry has been issued return hit at the same cycle, then return data when transiton finish. 688cb6e5d3cSssszwic * ICacheMainPipe should be blocked during handle handleEntry. 689cb6e5d3cSssszwic */ 690cb6e5d3cSssszwic val r_hit_handle = r_blocks.map(block => handleEntry.valid && (block === get_block(handleEntry.paddr))) 691cb6e5d3cSssszwic val cancelHandleEntry = (((0 until PortNumber).map(i=> fromMainPipe(i).valid && r_hit_handle(i))).reduce(_||_) || io.fencei) && !handleEntry.issue 692cb6e5d3cSssszwic val piq_hit = (0 until PortNumber).map(i => r_hit_handle(i) && handleEntry.issue && !handleEntry.flash && !io.fencei) 693cb6e5d3cSssszwic (0 until PortNumber).foreach (i => { 694cb6e5d3cSssszwic toMainPipe(i).piq_hit := piq_hit(i) 695cb6e5d3cSssszwic toMainPipe(i).cacheline := handleEntry.cacheline 696cb6e5d3cSssszwic toMainPipe(i).data_valid := handleEntry.valid && handleEntry.finish 6977052722fSJay }) 698cb6e5d3cSssszwic val piq_hit_req = RegEnable(piq_hit.reduce(_||_), fromMainPipe.map(_.valid).reduce(_||_)) 6997052722fSJay 700cb6e5d3cSssszwic /** 701cb6e5d3cSssszwic ****************************************************************************** 702cb6e5d3cSssszwic * Manage prefetch requests by queue 703cb6e5d3cSssszwic * - 1. Shift: entry shift when there are free entries behind 704cb6e5d3cSssszwic * - 2. Enqueue: receive prefetch request when first entry free 705cb6e5d3cSssszwic * - 3. Free: invalid the entry hitted mainpipe look up 706cb6e5d3cSssszwic * - 4. Fencei PIQ: invalid all PIQ entry when fencei 707cb6e5d3cSssszwic * - 5. Dequeue: move prefetch request from last entry to handle entry 708cb6e5d3cSssszwic * - 6. Cancel handleEntry hitted mainpipe if hasn't been issued 709cb6e5d3cSssszwic * - 7. Valid flash of handleEntry when fencei if has been issued 710cb6e5d3cSssszwic ****************************************************************************** 711cb6e5d3cSssszwic */ 712cb6e5d3cSssszwic /** 1. Shift: entry shift when there are free entries behind */ 713cb6e5d3cSssszwic val move = Wire(Vec(nPrefetchEntries, Bool())) 714cb6e5d3cSssszwic (0 until nPrefetchEntries).map (i => 715cb6e5d3cSssszwic // shift when there are invalid (free) entry behind 716cb6e5d3cSssszwic move(i) := ParallelOR((i+1 until nPrefetchEntries).map(!PIQ(_).valid) :+ !handleEntry.valid) 717cb6e5d3cSssszwic ) 718cb6e5d3cSssszwic (1 until nPrefetchEntries).map (i => 719cb6e5d3cSssszwic when(move(i-1)) { 720cb6e5d3cSssszwic PIQ(i) := PIQ(i-1) 721cb6e5d3cSssszwic } 722cb6e5d3cSssszwic ) 7237052722fSJay 724cb6e5d3cSssszwic /** 2. Enqueue: receive prefetch request to PIQ(0) when move(0) otherwise blocked*/ 725cb6e5d3cSssszwic enqueReq.ready := move(0) 726cb6e5d3cSssszwic when(move(0)) { 727cb6e5d3cSssszwic when(enqueReq.valid) { 728cb6e5d3cSssszwic PIQ(0).valid := true.B 729cb6e5d3cSssszwic PIQ(0).vSetIdx := enqueReq.bits.vSetIdx 730cb6e5d3cSssszwic PIQ(0).paddr := enqueReq.bits.paddr 731cb6e5d3cSssszwic }.otherwise { 732cb6e5d3cSssszwic PIQ(0).valid := false.B 733cb6e5d3cSssszwic } 734cb6e5d3cSssszwic } 735b1ded4e8Sguohongyu 736cb6e5d3cSssszwic /** 3. Free: invalid the entry hitted mainpipe */ 737cb6e5d3cSssszwic (0 until PortNumber) .map (i => 738cb6e5d3cSssszwic when(r_hit_PIQ(i)) { 739cb6e5d3cSssszwic when(move(curr_hit_ptr(i)) && (curr_hit_ptr(i) =/= (nPrefetchEntries-1).U)) { 740cb6e5d3cSssszwic // the hitted entry will be shifted, so invalid next entry 741cb6e5d3cSssszwic PIQ(curr_hit_ptr(i) + 1.U).valid := false.B 742cb6e5d3cSssszwic }.otherwise { 743cb6e5d3cSssszwic PIQ(curr_hit_ptr(i)).valid := false.B 744cb6e5d3cSssszwic } 745cb6e5d3cSssszwic } 746cb6e5d3cSssszwic ) 747cb6e5d3cSssszwic 748cb6e5d3cSssszwic /** 4. Fencei: invalid all PIQ entry when fencei */ 749cb6e5d3cSssszwic when(io.fencei) { 750cb6e5d3cSssszwic PIQ.map ( 751cb6e5d3cSssszwic _.valid := false.B 752cb6e5d3cSssszwic ) 753cb6e5d3cSssszwic } 754cb6e5d3cSssszwic 755cb6e5d3cSssszwic /** 5. Dequeue: move PIQ.last to handle entry when handle entry is free */ 756cb6e5d3cSssszwic // cancel entry when PIQ.last is hitted by mainpipe 757cb6e5d3cSssszwic val cancel = (0 until PortNumber).map (i => r_hit_PIQ(i) && (curr_hit_ptr(i) === (nPrefetchEntries-1).U)).reduce(_||_) 758cb6e5d3cSssszwic when(move(nPrefetchEntries - 1) && !cancel) { 759cb6e5d3cSssszwic handleEntry.valid := PIQ(nPrefetchEntries - 1).valid 760cb6e5d3cSssszwic handleEntry.paddr := PIQ(nPrefetchEntries - 1).paddr 761cb6e5d3cSssszwic handleEntry.vSetIdx := PIQ(nPrefetchEntries - 1).vSetIdx 762cb6e5d3cSssszwic handleEntry.issue := false.B 763cb6e5d3cSssszwic handleEntry.finish := false.B 764cb6e5d3cSssszwic handleEntry.flash := false.B 765cb6e5d3cSssszwic handleEntry.readBeatCnt := 0.U 766cb6e5d3cSssszwic } 767cb6e5d3cSssszwic 768cb6e5d3cSssszwic /** 6. Cancel handleEntry hitted mainpipe or receive fencei if hasn't been issued */ 769cb6e5d3cSssszwic when(cancelHandleEntry) { 770cb6e5d3cSssszwic handleEntry.valid := false.B 771cb6e5d3cSssszwic } 772cb6e5d3cSssszwic 773cb6e5d3cSssszwic /** 7. Valid flash of handleEntry when fencei. Drop data from TileLink port */ 774cb6e5d3cSssszwic when(io.fencei) { 775cb6e5d3cSssszwic handleEntry.flash := true.B 776cb6e5d3cSssszwic } 777cb6e5d3cSssszwic 778cb6e5d3cSssszwic 779cb6e5d3cSssszwic /** 780cb6e5d3cSssszwic ****************************************************************************** 781cb6e5d3cSssszwic * Write Prefetch Data to Prefetch Buffer 782cb6e5d3cSssszwic * - valid signal only hold one cycle 783cb6e5d3cSssszwic ****************************************************************************** 784cb6e5d3cSssszwic */ 785cb6e5d3cSssszwic toIPF.valid := handleEntry.valid && handleEntry.finish 786cb6e5d3cSssszwic toIPF.bits.paddr := handleEntry.paddr 787cb6e5d3cSssszwic toIPF.bits.vSetIdx := handleEntry.vSetIdx 788cb6e5d3cSssszwic toIPF.bits.cacheline := handleEntry.cacheline 789cb6e5d3cSssszwic toIPF.bits.has_hit := piq_hit_req 790cb6e5d3cSssszwic 791cb6e5d3cSssszwic 792cb6e5d3cSssszwic /** 793cb6e5d3cSssszwic ****************************************************************************** 794cb6e5d3cSssszwic * Tilelink Transition 795cb6e5d3cSssszwic * - 1. Send acquire to L2Cache, after which the request cannot be canceled (issue valid) 796cb6e5d3cSssszwic * - 2. Wait data response from Tilelink 797cb6e5d3cSssszwic * - 3. Get data, valid finish (only one cycle) and invalid issue 798cb6e5d3cSssszwic ****************************************************************************** 799cb6e5d3cSssszwic */ 800b1ded4e8Sguohongyu val (_, _, refill_done, refill_address_inc) = edge.addr_inc(io.mem_grant) 801b1ded4e8Sguohongyu 802cb6e5d3cSssszwic val s_idle :: s_memReadReq :: s_memReadResp :: s_write_back :: Nil = Enum(4) 803cb6e5d3cSssszwic val state = RegInit(s_idle) 804b1ded4e8Sguohongyu 805cb6e5d3cSssszwic // acquire port 806b1ded4e8Sguohongyu io.mem_acquire.bits := edge.Get( 807cb6e5d3cSssszwic fromSource = PortNumber.U, 808cb6e5d3cSssszwic toAddress = Cat(handleEntry.paddr(PAddrBits - 1, log2Ceil(blockBytes)), 0.U(log2Ceil(blockBytes).W)), 809b1ded4e8Sguohongyu lgSize = (log2Up(cacheParams.blockBytes)).U)._2 810d2b20d1aSTang Haojin io.mem_acquire.bits.user.lift(PreferCacheKey).foreach(_ := true.B) 811d2b20d1aSTang Haojin io.mem_acquire.bits.user.lift(ReqSourceKey).foreach(_ := MemReqSource.L1InstPrefetch.id.U) 812b1ded4e8Sguohongyu 813cb6e5d3cSssszwic // grant port 814cb6e5d3cSssszwic io.mem_grant.ready := true.B 815cb6e5d3cSssszwic io.mem_acquire.valid := (state === s_memReadReq) 816cb6e5d3cSssszwic 817cb6e5d3cSssszwic switch(state) { 818cb6e5d3cSssszwic is(s_idle) { 819cb6e5d3cSssszwic when(handleEntry.valid && !cancelHandleEntry) { 820cb6e5d3cSssszwic handleEntry.issue := true.B 821cb6e5d3cSssszwic state := s_memReadReq 822cb6e5d3cSssszwic } 823cb6e5d3cSssszwic } 824cb6e5d3cSssszwic is(s_memReadReq) { 825cb6e5d3cSssszwic state := Mux(io.mem_acquire.fire(), s_memReadResp, s_memReadReq) 826cb6e5d3cSssszwic } 827cb6e5d3cSssszwic is(s_memReadResp) { 828cb6e5d3cSssszwic when (edge.hasData(io.mem_grant.bits) && io.mem_grant.fire()) { 829cb6e5d3cSssszwic handleEntry.readBeatCnt := handleEntry.readBeatCnt + 1.U 830cb6e5d3cSssszwic handleEntry.respData(handleEntry.readBeatCnt) := io.mem_grant.bits.data 831cb6e5d3cSssszwic when (handleEntry.readBeatCnt === (refillCycles - 1).U) { 832cb6e5d3cSssszwic assert(refill_done, "refill not done!") 833cb6e5d3cSssszwic state := s_write_back 834cb6e5d3cSssszwic when (!io.fencei && !handleEntry.flash) { 835cb6e5d3cSssszwic handleEntry.issue := false.B 836cb6e5d3cSssszwic handleEntry.finish := true.B 837cb6e5d3cSssszwic } 838cb6e5d3cSssszwic } 839cb6e5d3cSssszwic } 840cb6e5d3cSssszwic } 841cb6e5d3cSssszwic is(s_write_back) { 842cb6e5d3cSssszwic state := s_idle 843cb6e5d3cSssszwic handleEntry.valid := false.B 844cb6e5d3cSssszwic } 845cb6e5d3cSssszwic } 846cb6e5d3cSssszwic 847cb6e5d3cSssszwic if (env.EnableDifftest) { 848*a0c65233SYinan Xu val diffipfrefill = DifftestModule(new DiffRefillEvent, dontCare = true) 8497d45a146SYinan Xu diffipfrefill.coreid := io.hartId 8507d45a146SYinan Xu diffipfrefill.index := 3.U 8517d45a146SYinan Xu diffipfrefill.valid := handleEntry.valid && handleEntry.finish 8527d45a146SYinan Xu diffipfrefill.addr := handleEntry.paddr 8537d45a146SYinan Xu diffipfrefill.data := handleEntry.cacheline.asTypeOf(diffipfrefill.data) 854cb6e5d3cSssszwic } 855cb6e5d3cSssszwic} 856cb6e5d3cSssszwic 857cb6e5d3cSssszwicclass FDIPPrefetchIO(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchBundle { 858cb6e5d3cSssszwic /** commen */ 859cb6e5d3cSssszwic val fencei = Input(Bool()) 860cb6e5d3cSssszwic val hartId = Input(UInt(8.W)) 861cb6e5d3cSssszwic 862cb6e5d3cSssszwic /** Prefetch Mainpipe IO */ 863cb6e5d3cSssszwic val ftqReq = Flipped(new FtqPrefechBundle) 864cb6e5d3cSssszwic val iTLBInter = new TlbRequestIO 865cb6e5d3cSssszwic val pmp = new ICachePMPBundle 866cb6e5d3cSssszwic val metaReadReq = Decoupled(new ICacheMetaReadReqBundle) 867cb6e5d3cSssszwic val metaReadResp = Input(new ICacheMetaReadRespBundle) 868cb6e5d3cSssszwic val mshrInfo = Flipped(Vec(PortNumber, ValidIO(UInt(PAddrBits.W)))) 869cb6e5d3cSssszwic val mainPipeMissInfo = Flipped(Vec(PortNumber,ValidIO(new MainPipeMissInfo))) 870cb6e5d3cSssszwic 871cb6e5d3cSssszwic /** Prefetch Buffer IO */ 872cb6e5d3cSssszwic val IPFBufferRead = new IPFBufferRead 873cb6e5d3cSssszwic val metaWrite = DecoupledIO(new ICacheMetaWriteBundle) 874cb6e5d3cSssszwic val dataWrite = DecoupledIO(new ICacheDataWriteBundle) 875cb6e5d3cSssszwic val IPFReplacer = new IPFReplacer 876cb6e5d3cSssszwic 877cb6e5d3cSssszwic /** Prefetch Queue IO */ 878cb6e5d3cSssszwic val PIQRead = new PIQRead 879cb6e5d3cSssszwic val mem_acquire = new DecoupledIO(new TLBundleA(edge.bundle)) 880cb6e5d3cSssszwic val mem_grant = Flipped(DecoupledIO(new TLBundleD(edge.bundle))) 881cb6e5d3cSssszwic} 882cb6e5d3cSssszwic 883cb6e5d3cSssszwicclass FDIPPrefetch(edge: TLEdgeOut)(implicit p: Parameters) extends IPrefetchModule 884cb6e5d3cSssszwic{ 885cb6e5d3cSssszwic val io = IO(new FDIPPrefetchIO(edge)) 886cb6e5d3cSssszwic 887cb6e5d3cSssszwic val prefetchPipe = Module(new IPrefetchPipe) 888cb6e5d3cSssszwic val prefetchQueue = Module(new PrefetchQueue(edge)) 889cb6e5d3cSssszwic val prefetchBuffer = Module(new PrefetchBuffer) 890cb6e5d3cSssszwic 891cb6e5d3cSssszwic io.metaReadReq <> prefetchPipe.io.metaReadReq 892cb6e5d3cSssszwic io.metaWrite <> prefetchBuffer.io.metaWrite 893cb6e5d3cSssszwic io.dataWrite <> prefetchBuffer.io.dataWrite 894cb6e5d3cSssszwic io.IPFReplacer <> prefetchBuffer.io.IPFReplacer 895cb6e5d3cSssszwic io.mem_acquire <> prefetchQueue.io.mem_acquire 896cb6e5d3cSssszwic io.mem_grant <> prefetchQueue.io.mem_grant 897cb6e5d3cSssszwic 898cb6e5d3cSssszwic // outside 899cb6e5d3cSssszwic prefetchPipe.io.fencei <> io.fencei 900cb6e5d3cSssszwic prefetchPipe.io.ftqReq <> io.ftqReq 901cb6e5d3cSssszwic prefetchPipe.io.iTLBInter <> io.iTLBInter 902cb6e5d3cSssszwic prefetchPipe.io.pmp <> io.pmp 903cb6e5d3cSssszwic prefetchPipe.io.metaReadResp <> io.metaReadResp 904cb6e5d3cSssszwic prefetchPipe.io.mshrInfo <> io.mshrInfo 905cb6e5d3cSssszwic prefetchPipe.io.mainPipeMissInfo <> io.mainPipeMissInfo 906cb6e5d3cSssszwic 907cb6e5d3cSssszwic // outside 908cb6e5d3cSssszwic prefetchBuffer.io.hartId <> io.hartId 909cb6e5d3cSssszwic prefetchBuffer.io.fencei <> io.fencei 910cb6e5d3cSssszwic prefetchBuffer.io.IPFBufferRead <> io.IPFBufferRead 911cb6e5d3cSssszwic // inside 912cb6e5d3cSssszwic prefetchBuffer.io.IPFFilterRead <> prefetchPipe.io.IPFFilterRead 913cb6e5d3cSssszwic prefetchBuffer.io.IPFBufferWrite <> prefetchQueue.io.IPFBufferWrite 914cb6e5d3cSssszwic 915cb6e5d3cSssszwic // outside 916cb6e5d3cSssszwic prefetchQueue.io.hartId <> io.hartId 917cb6e5d3cSssszwic prefetchQueue.io.fencei <> io.fencei 918cb6e5d3cSssszwic prefetchQueue.io.PIQRead <> io.PIQRead 919cb6e5d3cSssszwic // inside 920cb6e5d3cSssszwic prefetchQueue.io.prefetchReq <> prefetchPipe.io.prefetchReq 921cb6e5d3cSssszwic prefetchQueue.io.PIQFilterRead <> prefetchPipe.io.PIQFilterRead 9227052722fSJay} 923