1/*************************************************************************************** 2 * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3 * Copyright (c) 2020-2021 Peng Cheng Laboratory 4 * 5 * XiangShan is licensed under Mulan PSL v2. 6 * You can use this software according to the terms and conditions of the Mulan PSL v2. 7 * You may obtain a copy of Mulan PSL v2 at: 8 * http://license.coscl.org.cn/MulanPSL2 9 * 10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13 * 14 * See the Mulan PSL v2 for more details. 15 ***************************************************************************************/ 16 17package xiangshan.frontend.icache 18 19import chisel3._ 20import chisel3.util._ 21import org.chipsalliance.cde.config.Parameters 22import utility._ 23import xiangshan.cache.mmu.Pbmt 24import xiangshan.frontend.ExceptionType 25 26/* WayLookupEntry is for internal storage, while WayLookupInfo is for interface 27 * Notes: 28 * 1. there must be a flush (caused by guest page fault) after excp_tlb_gpf === true.B, 29 * so, we need only the first excp_tlb_gpf and the corresponding gpaddr. 30 * to save area, we separate those signals from WayLookupEntry and store only once. 31 */ 32class WayLookupEntry(implicit p: Parameters) extends ICacheBundle { 33 val vSetIdx: Vec[UInt] = Vec(PortNumber, UInt(idxBits.W)) 34 val waymask: Vec[UInt] = Vec(PortNumber, UInt(nWays.W)) 35 val ptag: Vec[UInt] = Vec(PortNumber, UInt(tagBits.W)) 36 val itlb_exception: Vec[UInt] = Vec(PortNumber, UInt(ExceptionType.width.W)) 37 val itlb_pbmt: Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W)) 38 val meta_codes: Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W)) 39} 40 41class WayLookupGPFEntry(implicit p: Parameters) extends ICacheBundle { 42 // NOTE: we dont use GPAddrBits here, refer to ICacheMainPipe.scala L43-48 and PR#3795 43 val gpaddr: UInt = UInt(PAddrBitsMax.W) 44 val isForVSnonLeafPTE: Bool = Bool() 45} 46 47class WayLookupInfo(implicit p: Parameters) extends ICacheBundle { 48 val entry = new WayLookupEntry 49 val gpf = new WayLookupGPFEntry 50 51 // for compatibility 52 def vSetIdx: Vec[UInt] = entry.vSetIdx 53 def waymask: Vec[UInt] = entry.waymask 54 def ptag: Vec[UInt] = entry.ptag 55 def itlb_exception: Vec[UInt] = entry.itlb_exception 56 def itlb_pbmt: Vec[UInt] = entry.itlb_pbmt 57 def meta_codes: Vec[UInt] = entry.meta_codes 58 def gpaddr: UInt = gpf.gpaddr 59 def isForVSnonLeafPTE: Bool = gpf.isForVSnonLeafPTE 60} 61 62class WayLookupInterface(implicit p: Parameters) extends ICacheBundle { 63 val flush = Input(Bool()) 64 val read = DecoupledIO(new WayLookupInfo) 65 val write = Flipped(DecoupledIO(new WayLookupInfo)) 66 val update = Flipped(ValidIO(new ICacheMissResp)) 67} 68 69class WayLookup(implicit p: Parameters) extends ICacheModule { 70 val io: WayLookupInterface = IO(new WayLookupInterface) 71 72 class WayLookupPtr(implicit p: Parameters) extends CircularQueuePtr[WayLookupPtr](nWayLookupSize) 73 private object WayLookupPtr { 74 def apply(f: Bool, v: UInt)(implicit p: Parameters): WayLookupPtr = { 75 val ptr = Wire(new WayLookupPtr) 76 ptr.flag := f 77 ptr.value := v 78 ptr 79 } 80 } 81 82 private val entries = RegInit(VecInit(Seq.fill(nWayLookupSize)(0.U.asTypeOf(new WayLookupEntry)))) 83 private val readPtr = RegInit(WayLookupPtr(false.B, 0.U)) 84 private val writePtr = RegInit(WayLookupPtr(false.B, 0.U)) 85 86 private val empty = readPtr === writePtr 87 private val full = (readPtr.value === writePtr.value) && (readPtr.flag ^ writePtr.flag) 88 89 when(io.flush) { 90 writePtr.value := 0.U 91 writePtr.flag := false.B 92 }.elsewhen(io.write.fire) { 93 writePtr := writePtr + 1.U 94 } 95 96 when(io.flush) { 97 readPtr.value := 0.U 98 readPtr.flag := false.B 99 }.elsewhen(io.read.fire) { 100 readPtr := readPtr + 1.U 101 } 102 103 private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry))) 104 private val gpfPtr = RegInit(WayLookupPtr(false.B, 0.U)) 105 private val gpf_hit = gpfPtr === readPtr && gpf_entry.valid 106 107 when(io.flush) { 108 // we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf 109 gpf_entry.valid := false.B 110 gpf_entry.bits := 0.U.asTypeOf(new WayLookupGPFEntry) 111 } 112 113 /** 114 ****************************************************************************** 115 * update 116 ****************************************************************************** 117 */ 118 private val hits = Wire(Vec(nWayLookupSize, Bool())) 119 entries.zip(hits).foreach { case (entry, hit) => 120 val hit_vec = Wire(Vec(PortNumber, Bool())) 121 (0 until PortNumber).foreach { i => 122 val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid 123 val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i) 124 val way_same = io.update.bits.waymask === entry.waymask(i) 125 when(vset_same) { 126 when(ptag_same) { 127 // miss -> hit 128 entry.waymask(i) := io.update.bits.waymask 129 // also update meta_codes 130 // we have getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i), so we can use entry.ptag(i) for better timing 131 entry.meta_codes(i) := encodeMetaECC(entry.ptag(i)) 132 }.elsewhen(way_same) { 133 // data is overwritten: hit -> miss 134 entry.waymask(i) := 0.U 135 // dont care meta_codes, since it's not used for a missed request 136 } 137 } 138 hit_vec(i) := vset_same && (ptag_same || way_same) 139 } 140 hit := hit_vec.reduce(_ || _) 141 } 142 143 /** 144 ****************************************************************************** 145 * read 146 ****************************************************************************** 147 */ 148 // if the entry is empty, but there is a valid write, we can bypass it to read port (maybe timing critical) 149 private val can_bypass = empty && io.write.valid 150 io.read.valid := !empty || io.write.valid 151 when(can_bypass) { 152 io.read.bits := io.write.bits 153 }.otherwise { // can't bypass 154 io.read.bits.entry := entries(readPtr.value) 155 when(gpf_hit) { // ptr match && entry valid 156 io.read.bits.gpf := gpf_entry.bits 157 // also clear gpf_entry.valid when it's read, note this will be override by write (L175) 158 when(io.read.fire) { 159 gpf_entry.valid := false.B 160 } 161 }.otherwise { // gpf not hit 162 io.read.bits.gpf := 0.U.asTypeOf(new WayLookupGPFEntry) 163 } 164 } 165 166 /** 167 ****************************************************************************** 168 * write 169 ****************************************************************************** 170 */ 171 // if there is a valid gpf to be read, we should stall the write 172 private val gpf_stall = gpf_entry.valid && !(io.read.fire && gpf_hit) 173 io.write.ready := !full && !gpf_stall 174 when(io.write.fire) { 175 entries(writePtr.value) := io.write.bits.entry 176 when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_ || _)) { 177 // if gpf_entry is bypassed, we don't need to save it 178 // note this will override the read (L156) 179 gpf_entry.valid := !(can_bypass && io.read.fire) 180 gpf_entry.bits := io.write.bits.gpf 181 gpfPtr := writePtr 182 } 183 } 184} 185