xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/WayLookup.scala (revision 6639e9a467468f4e1b05a25a5de4500772aedeb1)
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 chisel3._
20import chisel3.util._
21import org.chipsalliance.cde.config.Parameters
22import utility._
23import xiangshan.cache.mmu.Pbmt
24import xiangshan.frontend.ExceptionType
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  // NOTE: we dont use GPAddrBits here, refer to ICacheMainPipe.scala L43-48 and PR#3795
43  val gpaddr:            UInt = UInt(PAddrBitsMax.W)
44  val isForVSnonLeafPTE: Bool = Bool()
45}
46
47class WayLookupInfo(implicit p: Parameters) extends ICacheBundle {
48  val entry = new WayLookupEntry
49  val gpf   = new WayLookupGPFEntry
50
51  // for compatibility
52  def vSetIdx:           Vec[UInt] = entry.vSetIdx
53  def waymask:           Vec[UInt] = entry.waymask
54  def ptag:              Vec[UInt] = entry.ptag
55  def itlb_exception:    Vec[UInt] = entry.itlb_exception
56  def itlb_pbmt:         Vec[UInt] = entry.itlb_pbmt
57  def meta_codes:        Vec[UInt] = entry.meta_codes
58  def gpaddr:            UInt      = gpf.gpaddr
59  def isForVSnonLeafPTE: Bool      = gpf.isForVSnonLeafPTE
60}
61
62class WayLookupInterface(implicit p: Parameters) extends ICacheBundle {
63  val flush  = Input(Bool())
64  val read   = DecoupledIO(new WayLookupInfo)
65  val write  = Flipped(DecoupledIO(new WayLookupInfo))
66  val update = Flipped(ValidIO(new ICacheMissResp))
67}
68
69class WayLookup(implicit p: Parameters) extends ICacheModule {
70  val io: WayLookupInterface = IO(new WayLookupInterface)
71
72  class WayLookupPtr(implicit p: Parameters) extends CircularQueuePtr[WayLookupPtr](nWayLookupSize)
73  private object WayLookupPtr {
74    def apply(f: Bool, v: UInt)(implicit p: Parameters): WayLookupPtr = {
75      val ptr = Wire(new WayLookupPtr)
76      ptr.flag  := f
77      ptr.value := v
78      ptr
79    }
80  }
81
82  private val entries  = RegInit(VecInit(Seq.fill(nWayLookupSize)(0.U.asTypeOf(new WayLookupEntry))))
83  private val readPtr  = RegInit(WayLookupPtr(false.B, 0.U))
84  private val writePtr = RegInit(WayLookupPtr(false.B, 0.U))
85
86  private val empty = readPtr === writePtr
87  private val full  = (readPtr.value === writePtr.value) && (readPtr.flag ^ writePtr.flag)
88
89  when(io.flush) {
90    writePtr.value := 0.U
91    writePtr.flag  := false.B
92  }.elsewhen(io.write.fire) {
93    writePtr := writePtr + 1.U
94  }
95
96  when(io.flush) {
97    readPtr.value := 0.U
98    readPtr.flag  := false.B
99  }.elsewhen(io.read.fire) {
100    readPtr := readPtr + 1.U
101  }
102
103  private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry)))
104  private val gpfPtr    = RegInit(WayLookupPtr(false.B, 0.U))
105  private val gpf_hit   = gpfPtr === readPtr && gpf_entry.valid
106
107  when(io.flush) {
108    // we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf
109    gpf_entry.valid := false.B
110    gpf_entry.bits  := 0.U.asTypeOf(new WayLookupGPFEntry)
111  }
112
113  /**
114    ******************************************************************************
115    * update
116    ******************************************************************************
117    */
118  private val hits = Wire(Vec(nWayLookupSize, Bool()))
119  entries.zip(hits).foreach { case (entry, hit) =>
120    val hit_vec = Wire(Vec(PortNumber, Bool()))
121    (0 until PortNumber).foreach { i =>
122      val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid
123      val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i)
124      val way_same  = io.update.bits.waymask === entry.waymask(i)
125      when(vset_same) {
126        when(ptag_same) {
127          // miss -> hit
128          entry.waymask(i) := io.update.bits.waymask
129          // also update meta_codes
130          // we have getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i), so we can use entry.ptag(i) for better timing
131          entry.meta_codes(i) := encodeMetaECC(entry.ptag(i))
132        }.elsewhen(way_same) {
133          // data is overwritten: hit -> miss
134          entry.waymask(i) := 0.U
135          // dont care meta_codes, since it's not used for a missed request
136        }
137      }
138      hit_vec(i) := vset_same && (ptag_same || way_same)
139    }
140    hit := hit_vec.reduce(_ || _)
141  }
142
143  /**
144    ******************************************************************************
145    * read
146    ******************************************************************************
147    */
148  // if the entry is empty, but there is a valid write, we can bypass it to read port (maybe timing critical)
149  private val can_bypass = empty && io.write.valid
150  io.read.valid := !empty || io.write.valid
151  when(can_bypass) {
152    io.read.bits := io.write.bits
153  }.otherwise { // can't bypass
154    io.read.bits.entry := entries(readPtr.value)
155    when(gpf_hit) { // ptr match && entry valid
156      io.read.bits.gpf := gpf_entry.bits
157      // also clear gpf_entry.valid when it's read, note this will be override by write (L175)
158      when(io.read.fire) {
159        gpf_entry.valid := false.B
160      }
161    }.otherwise { // gpf not hit
162      io.read.bits.gpf := 0.U.asTypeOf(new WayLookupGPFEntry)
163    }
164  }
165
166  /**
167    ******************************************************************************
168    * write
169    ******************************************************************************
170    */
171  // if there is a valid gpf to be read, we should stall the write
172  private val gpf_stall = gpf_entry.valid && !(io.read.fire && gpf_hit)
173  io.write.ready := !full && !gpf_stall
174  when(io.write.fire) {
175    entries(writePtr.value) := io.write.bits.entry
176    when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_ || _)) {
177      // if gpf_entry is bypassed, we don't need to save it
178      // note this will override the read (L156)
179      gpf_entry.valid := !(can_bypass && io.read.fire)
180      gpf_entry.bits  := io.write.bits.gpf
181      gpfPtr          := writePtr
182    }
183  }
184}
185