xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/WayLookup.scala (revision 88895b119ca1fe225ad8674b30e79a0ddaee5c42)
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