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 24import xiangshan.cache.mmu.Pbmt 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 val gpaddr : UInt = UInt(GPAddrBits.W) 43 val isForVSnonLeafPTE : Bool = Bool() 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 itlb_exception : Vec[UInt] = entry.itlb_exception 55 def itlb_pbmt : Vec[UInt] = entry.itlb_pbmt 56 def meta_codes : Vec[UInt] = entry.meta_codes 57 def gpaddr : UInt = gpf.gpaddr 58 def isForVSnonLeafPTE : Bool = gpf.isForVSnonLeafPTE 59} 60 61class WayLookupInterface(implicit p: Parameters) extends ICacheBundle { 62 val flush = Input(Bool()) 63 val read = DecoupledIO(new WayLookupInfo) 64 val write = Flipped(DecoupledIO(new WayLookupInfo)) 65 val update = Flipped(ValidIO(new ICacheMissResp)) 66} 67 68class WayLookup(implicit p: Parameters) extends ICacheModule { 69 val io: WayLookupInterface = IO(new WayLookupInterface) 70 71 class WayLookupPtr(implicit p: Parameters) extends CircularQueuePtr[WayLookupPtr](nWayLookupSize) 72 private object WayLookupPtr { 73 def apply(f: Bool, v: UInt)(implicit p: Parameters): WayLookupPtr = { 74 val ptr = Wire(new WayLookupPtr) 75 ptr.flag := f 76 ptr.value := v 77 ptr 78 } 79 } 80 81 private val entries = RegInit(VecInit(Seq.fill(nWayLookupSize)(0.U.asTypeOf(new WayLookupEntry)))) 82 private val readPtr = RegInit(WayLookupPtr(false.B, 0.U)) 83 private val writePtr = RegInit(WayLookupPtr(false.B, 0.U)) 84 85 private val empty = readPtr === writePtr 86 private val full = (readPtr.value === writePtr.value) && (readPtr.flag ^ writePtr.flag) 87 88 when(io.flush) { 89 writePtr.value := 0.U 90 writePtr.flag := false.B 91 }.elsewhen(io.write.fire) { 92 writePtr := writePtr + 1.U 93 } 94 95 when(io.flush) { 96 readPtr.value := 0.U 97 readPtr.flag := false.B 98 }.elsewhen(io.read.fire) { 99 readPtr := readPtr + 1.U 100 } 101 102 private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry))) 103 private val gpfPtr = RegInit(WayLookupPtr(false.B, 0.U)) 104 105 when(io.flush) { 106 // we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf 107 gpf_entry.valid := false.B 108 gpf_entry.bits := 0.U.asTypeOf(new WayLookupGPFEntry) 109 } 110 111 /** 112 ****************************************************************************** 113 * update 114 ****************************************************************************** 115 */ 116 private val hits = Wire(Vec(nWayLookupSize, Bool())) 117 entries.zip(hits).foreach{ case(entry, hit) => 118 val hit_vec = Wire(Vec(PortNumber, Bool())) 119 (0 until PortNumber).foreach { i => 120 val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid 121 val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i) 122 val way_same = io.update.bits.waymask === entry.waymask(i) 123 when(vset_same) { 124 when(ptag_same) { 125 // miss -> hit 126 entry.waymask(i) := io.update.bits.waymask 127 // also update meta_codes 128 // we have getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i), so we can use entry.ptag(i) for better timing 129 entry.meta_codes(i) := encodeMetaECC(entry.ptag(i)) 130 }.elsewhen(way_same) { 131 // data is overwritten: hit -> miss 132 entry.waymask(i) := 0.U 133 // dont care meta_codes, since it's not used for a missed request 134 } 135 } 136 hit_vec(i) := vset_same && (ptag_same || way_same) 137 } 138 hit := hit_vec.reduce(_||_) 139 } 140 141 /** 142 ****************************************************************************** 143 * read 144 ****************************************************************************** 145 */ 146 io.read.valid := !empty || io.write.valid 147 when (empty && io.write.valid) { // bypass 148 io.read.bits := io.write.bits 149 }.otherwise { 150 io.read.bits.entry := entries(readPtr.value) 151 io.read.bits.gpf := Mux(readPtr === gpfPtr && gpf_entry.valid, gpf_entry.bits, 0.U.asTypeOf(new WayLookupGPFEntry)) 152 } 153 154 /** 155 ****************************************************************************** 156 * write 157 ****************************************************************************** 158 */ 159 io.write.ready := !full 160 when(io.write.fire) { 161 entries(writePtr.value) := io.write.bits.entry 162 // save gpf iff no gpf is already saved 163 when(!gpf_entry.valid && io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_||_)) { 164 gpf_entry.valid := true.B 165 gpf_entry.bits := io.write.bits.gpf 166 gpfPtr := writePtr 167 } 168 } 169} 170