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