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