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 org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import utility._ 23import xiangshan.frontend.ExceptionType 24 25/* WayLookupEntry is for internal storage, while WayLookupInfo is for interface 26 * Notes: 27 * 1. there must be a flush (caused by guest page fault) after excp_tlb_gpf === true.B, 28 * so, we need only the first excp_tlb_gpf and the corresponding gpaddr. 29 * to save area, we separate those signals from WayLookupEntry and store only once. 30 */ 31class WayLookupEntry(implicit p: Parameters) extends ICacheBundle { 32 val vSetIdx : Vec[UInt] = Vec(PortNumber, UInt(idxBits.W)) 33 val waymask : Vec[UInt] = Vec(PortNumber, UInt(nWays.W)) 34 val ptag : Vec[UInt] = Vec(PortNumber, UInt(tagBits.W)) 35 val itlb_exception : Vec[UInt] = Vec(PortNumber, UInt(ExceptionType.width.W)) 36 val meta_corrupt : Vec[Bool] = Vec(PortNumber, Bool()) 37} 38 39class WayLookupGPFEntry(implicit p: Parameters) extends ICacheBundle { 40 val gpaddr : UInt = UInt(GPAddrBits.W) 41} 42 43class WayLookupInfo(implicit p: Parameters) extends ICacheBundle { 44 val entry = new WayLookupEntry 45 val gpf = new WayLookupGPFEntry 46 47 // for compatibility 48 def vSetIdx : Vec[UInt] = entry.vSetIdx 49 def waymask : Vec[UInt] = entry.waymask 50 def ptag : Vec[UInt] = entry.ptag 51 def itlb_exception : Vec[UInt] = entry.itlb_exception 52 def meta_corrupt : Vec[Bool] = entry.meta_corrupt 53 def gpaddr : UInt = gpf.gpaddr 54} 55 56 57// class WayLookupRead(implicit p: Parameters) extends ICacheBundle { 58// val vSetIdx = Vec(PortNumber, UInt(idxBits.W)) 59// val waymask = Vec(PortNumber, UInt(nWays.W)) 60// val ptag = Vec(PortNumber, UInt(tagBits.W)) 61// val excp_tlb_af = Vec(PortNumber, Bool()) 62// val excp_tlb_pf = Vec(PortNumber, Bool()) 63// } 64 65// class WayLookupWrite(implicit p: Parameters) extends ICacheBundle { 66// val vSetIdx = Vec(PortNumber, UInt(idxBits.W)) 67// val ptag = Vec(PortNumber, UInt(tagBits.W)) 68// val waymask = Vec(PortNumber, UInt(nWays.W)) 69// val excp_tlb_af = Vec(PortNumber, Bool()) 70// val excp_tlb_pf = Vec(PortNumber, Bool()) 71// } 72 73class WayLookupInterface(implicit p: Parameters) extends ICacheBundle { 74 val flush = Input(Bool()) 75 val read = DecoupledIO(new WayLookupInfo) 76 val write = Flipped(DecoupledIO(new WayLookupInfo)) 77 val update = Flipped(ValidIO(new ICacheMissResp)) 78} 79 80class WayLookup(implicit p: Parameters) extends ICacheModule { 81 val io: WayLookupInterface = IO(new WayLookupInterface) 82 83 class WayLookupPtr(implicit p: Parameters) extends CircularQueuePtr[WayLookupPtr](nWayLookupSize) 84 private object WayLookupPtr { 85 def apply(f: Bool, v: UInt)(implicit p: Parameters): WayLookupPtr = { 86 val ptr = Wire(new WayLookupPtr) 87 ptr.flag := f 88 ptr.value := v 89 ptr 90 } 91 } 92 93 private val entries = RegInit(VecInit(Seq.fill(nWayLookupSize)(0.U.asTypeOf(new WayLookupEntry)))) 94 private val readPtr = RegInit(WayLookupPtr(false.B, 0.U)) 95 private val writePtr = RegInit(WayLookupPtr(false.B, 0.U)) 96 97 private val empty = readPtr === writePtr 98 private val full = (readPtr.value === writePtr.value) && (readPtr.flag ^ writePtr.flag) 99 100 when(io.flush) { 101 writePtr.value := 0.U 102 writePtr.flag := false.B 103 }.elsewhen(io.write.fire) { 104 writePtr := writePtr + 1.U 105 } 106 107 when(io.flush) { 108 readPtr.value := 0.U 109 readPtr.flag := false.B 110 }.elsewhen(io.read.fire) { 111 readPtr := readPtr + 1.U 112 } 113 114 private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry))) 115 private val gpfPtr = RegInit(WayLookupPtr(false.B, 0.U)) 116 117 when(io.flush) { 118 // we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf 119 gpf_entry.valid := false.B 120 gpf_entry.bits := 0.U.asTypeOf(new WayLookupGPFEntry) 121 } 122 123 /** 124 ****************************************************************************** 125 * update 126 ****************************************************************************** 127 */ 128 private val hits = Wire(Vec(nWayLookupSize, Bool())) 129 entries.zip(hits).foreach{ case(entry, hit) => 130 val hit_vec = Wire(Vec(PortNumber, Bool())) 131 (0 until PortNumber).foreach { i => 132 val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid 133 val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i) 134 val way_same = io.update.bits.waymask === entry.waymask(i) 135 when(vset_same) { 136 when(ptag_same) { 137 // miss -> hit 138 entry.waymask(i) := io.update.bits.waymask 139 // also clear previously found errors since data/metaArray is refilled 140 entry.meta_corrupt(i) := false.B 141 }.elsewhen(way_same) { 142 // data is overwritten: hit -> miss 143 entry.waymask(i) := 0.U 144 // do not clear previously found errors since way_same might be unreliable when error occurs 145 } 146 } 147 hit_vec(i) := vset_same && (ptag_same || way_same) 148 } 149 hit := hit_vec.reduce(_||_) 150 } 151 152 /** 153 ****************************************************************************** 154 * read 155 ****************************************************************************** 156 */ 157 io.read.valid := !empty || io.write.valid 158 when (empty && io.write.valid) { // bypass 159 io.read.bits := io.write.bits 160 }.otherwise { 161 io.read.bits.entry := entries(readPtr.value) 162 io.read.bits.gpf := Mux(readPtr === gpfPtr && gpf_entry.valid, gpf_entry.bits, 0.U.asTypeOf(new WayLookupGPFEntry)) 163 } 164 165 /** 166 ****************************************************************************** 167 * write 168 ****************************************************************************** 169 */ 170 io.write.ready := !full 171 when(io.write.fire) { 172 entries(writePtr.value) := io.write.bits.entry 173 // save gpf iff no gpf is already saved 174 when(!gpf_entry.valid && io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_||_)) { 175 gpf_entry.valid := true.B 176 gpf_entry.bits := io.write.bits.gpf 177 gpfPtr := writePtr 178 } 179 } 180} 181