xref: /XiangShan/src/main/scala/xiangshan/frontend/icache/WayLookup.scala (revision 6c106319588f5988a282dc2e7c687a9d44e9c209)
1b92f8445Sssszwic/***************************************************************************************
2*6c106319Sxu_zh* Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3*6c106319Sxu_zh* Copyright (c) 2020-2024 Institute of Computing Technology, Chinese Academy of Sciences
4b92f8445Sssszwic* Copyright (c) 2020-2021 Peng Cheng Laboratory
5b92f8445Sssszwic*
6b92f8445Sssszwic* XiangShan is licensed under Mulan PSL v2.
7b92f8445Sssszwic* You can use this software according to the terms and conditions of the Mulan PSL v2.
8b92f8445Sssszwic* You may obtain a copy of Mulan PSL v2 at:
9b92f8445Sssszwic*          http://license.coscl.org.cn/MulanPSL2
10b92f8445Sssszwic*
11b92f8445Sssszwic* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12b92f8445Sssszwic* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13b92f8445Sssszwic* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14b92f8445Sssszwic*
15b92f8445Sssszwic* See the Mulan PSL v2 for more details.
16b92f8445Sssszwic***************************************************************************************/
17b92f8445Sssszwic
18b92f8445Sssszwicpackage xiangshan.frontend.icache
19b92f8445Sssszwic
20b92f8445Sssszwicimport chisel3._
21b92f8445Sssszwicimport chisel3.util._
22cf7d6b7aSMuziimport org.chipsalliance.cde.config.Parameters
23b92f8445Sssszwicimport utility._
24002c10a4SYanqin Liimport xiangshan.cache.mmu.Pbmt
25cf7d6b7aSMuziimport xiangshan.frontend.ExceptionType
26b92f8445Sssszwic
2791946104Sxu_zh/* WayLookupEntry is for internal storage, while WayLookupInfo is for interface
2891946104Sxu_zh * Notes:
2991946104Sxu_zh *   1. there must be a flush (caused by guest page fault) after excp_tlb_gpf === true.B,
3091946104Sxu_zh *      so, we need only the first excp_tlb_gpf and the corresponding gpaddr.
3191946104Sxu_zh *      to save area, we separate those signals from WayLookupEntry and store only once.
3291946104Sxu_zh */
3391946104Sxu_zhclass WayLookupEntry(implicit p: Parameters) extends ICacheBundle {
3491946104Sxu_zh  val vSetIdx:        Vec[UInt] = Vec(PortNumber, UInt(idxBits.W))
3591946104Sxu_zh  val waymask:        Vec[UInt] = Vec(PortNumber, UInt(nWays.W))
3691946104Sxu_zh  val ptag:           Vec[UInt] = Vec(PortNumber, UInt(tagBits.W))
3788895b11Sxu_zh  val itlb_exception: Vec[UInt] = Vec(PortNumber, UInt(ExceptionType.width.W))
38002c10a4SYanqin Li  val itlb_pbmt:      Vec[UInt] = Vec(PortNumber, UInt(Pbmt.width.W))
398966a895Sxu_zh  val meta_codes:     Vec[UInt] = Vec(PortNumber, UInt(ICacheMetaCodeBits.W))
4091946104Sxu_zh}
4191946104Sxu_zh
4291946104Sxu_zhclass WayLookupGPFEntry(implicit p: Parameters) extends ICacheBundle {
43415fcbe2Sxu_zh  // NOTE: we don't use GPAddrBits here, refer to ICacheMainPipe.scala L43-48 and PR#3795
44dd980d61SXu, Zefan  val gpaddr:            UInt = UInt(PAddrBitsMax.W)
45ad415ae0SXiaokun-Pei  val isForVSnonLeafPTE: Bool = Bool()
4691946104Sxu_zh}
4791946104Sxu_zh
48b92f8445Sssszwicclass WayLookupInfo(implicit p: Parameters) extends ICacheBundle {
4991946104Sxu_zh  val entry = new WayLookupEntry
5091946104Sxu_zh  val gpf   = new WayLookupGPFEntry
5191946104Sxu_zh
5291946104Sxu_zh  // for compatibility
5391946104Sxu_zh  def vSetIdx:           Vec[UInt] = entry.vSetIdx
5491946104Sxu_zh  def waymask:           Vec[UInt] = entry.waymask
5591946104Sxu_zh  def ptag:              Vec[UInt] = entry.ptag
5688895b11Sxu_zh  def itlb_exception:    Vec[UInt] = entry.itlb_exception
57002c10a4SYanqin Li  def itlb_pbmt:         Vec[UInt] = entry.itlb_pbmt
588966a895Sxu_zh  def meta_codes:        Vec[UInt] = entry.meta_codes
5991946104Sxu_zh  def gpaddr:            UInt      = gpf.gpaddr
60ad415ae0SXiaokun-Pei  def isForVSnonLeafPTE: Bool      = gpf.isForVSnonLeafPTE
61b92f8445Sssszwic}
62b92f8445Sssszwic
63b92f8445Sssszwicclass WayLookupInterface(implicit p: Parameters) extends ICacheBundle {
64415fcbe2Sxu_zh  val flush:  Bool                       = Input(Bool())
65415fcbe2Sxu_zh  val read:   DecoupledIO[WayLookupInfo] = DecoupledIO(new WayLookupInfo)
66415fcbe2Sxu_zh  val write:  DecoupledIO[WayLookupInfo] = Flipped(DecoupledIO(new WayLookupInfo))
67415fcbe2Sxu_zh  val update: Valid[ICacheMissResp]      = Flipped(ValidIO(new ICacheMissResp))
68b92f8445Sssszwic}
69b92f8445Sssszwic
70*6c106319Sxu_zhclass WayLookup(implicit p: Parameters) extends ICacheModule with HasICacheECCHelper {
7191946104Sxu_zh  val io: WayLookupInterface = IO(new WayLookupInterface)
72b92f8445Sssszwic
73415fcbe2Sxu_zh  class WayLookupPtr extends CircularQueuePtr[WayLookupPtr](nWayLookupSize)
7491946104Sxu_zh  private object WayLookupPtr {
75415fcbe2Sxu_zh    def apply(f: Bool, v: UInt): WayLookupPtr = {
76b92f8445Sssszwic      val ptr = Wire(new WayLookupPtr)
77b92f8445Sssszwic      ptr.flag  := f
78b92f8445Sssszwic      ptr.value := v
79b92f8445Sssszwic      ptr
80b92f8445Sssszwic    }
81b92f8445Sssszwic  }
82b92f8445Sssszwic
8391946104Sxu_zh  private val entries  = RegInit(VecInit(Seq.fill(nWayLookupSize)(0.U.asTypeOf(new WayLookupEntry))))
8491946104Sxu_zh  private val readPtr  = RegInit(WayLookupPtr(false.B, 0.U))
8591946104Sxu_zh  private val writePtr = RegInit(WayLookupPtr(false.B, 0.U))
86b92f8445Sssszwic
8791946104Sxu_zh  private val empty = readPtr === writePtr
8891946104Sxu_zh  private val full  = (readPtr.value === writePtr.value) && (readPtr.flag ^ writePtr.flag)
89b92f8445Sssszwic
90b92f8445Sssszwic  when(io.flush) {
91b92f8445Sssszwic    writePtr.value := 0.U
92b92f8445Sssszwic    writePtr.flag  := false.B
93b92f8445Sssszwic  }.elsewhen(io.write.fire) {
94b92f8445Sssszwic    writePtr := writePtr + 1.U
95b92f8445Sssszwic  }
96b92f8445Sssszwic
97b92f8445Sssszwic  when(io.flush) {
98b92f8445Sssszwic    readPtr.value := 0.U
99b92f8445Sssszwic    readPtr.flag  := false.B
100b92f8445Sssszwic  }.elsewhen(io.read.fire) {
101b92f8445Sssszwic    readPtr := readPtr + 1.U
102b92f8445Sssszwic  }
103b92f8445Sssszwic
10488895b11Sxu_zh  private val gpf_entry = RegInit(0.U.asTypeOf(Valid(new WayLookupGPFEntry)))
10591946104Sxu_zh  private val gpfPtr    = RegInit(WayLookupPtr(false.B, 0.U))
106b7a4433dSxu_zh  private val gpf_hit   = gpfPtr === readPtr && gpf_entry.valid
10791946104Sxu_zh
10891946104Sxu_zh  when(io.flush) {
10991946104Sxu_zh    // we don't need to reset gpfPtr, since the valid is actually gpf_entries.excp_tlb_gpf
11088895b11Sxu_zh    gpf_entry.valid := false.B
11188895b11Sxu_zh    gpf_entry.bits  := 0.U.asTypeOf(new WayLookupGPFEntry)
11291946104Sxu_zh  }
11391946104Sxu_zh
114b92f8445Sssszwic  /**
115b92f8445Sssszwic    ******************************************************************************
116b92f8445Sssszwic    * update
117b92f8445Sssszwic    ******************************************************************************
118b92f8445Sssszwic    */
11991946104Sxu_zh  private val hits = Wire(Vec(nWayLookupSize, Bool()))
120b92f8445Sssszwic  entries.zip(hits).foreach { case (entry, hit) =>
121b92f8445Sssszwic    val hit_vec = Wire(Vec(PortNumber, Bool()))
122b92f8445Sssszwic    (0 until PortNumber).foreach { i =>
123b92f8445Sssszwic      val vset_same = (io.update.bits.vSetIdx === entry.vSetIdx(i)) && !io.update.bits.corrupt && io.update.valid
124b92f8445Sssszwic      val ptag_same = getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i)
125b92f8445Sssszwic      val way_same  = io.update.bits.waymask === entry.waymask(i)
126b92f8445Sssszwic      when(vset_same) {
127b92f8445Sssszwic        when(ptag_same) {
128b92f8445Sssszwic          // miss -> hit
129b92f8445Sssszwic          entry.waymask(i) := io.update.bits.waymask
1308966a895Sxu_zh          // also update meta_codes
131415fcbe2Sxu_zh          // NOTE: we have getPhyTagFromBlk(io.update.bits.blkPaddr) === entry.ptag(i),
132415fcbe2Sxu_zh          //       so we can use entry.ptag(i) for better timing
1335ce94708Sxu_zh          entry.meta_codes(i) := encodeMetaECC(entry.ptag(i))
134b92f8445Sssszwic        }.elsewhen(way_same) {
135b92f8445Sssszwic          // data is overwritten: hit -> miss
136b92f8445Sssszwic          entry.waymask(i) := 0.U
137415fcbe2Sxu_zh          // don't care meta_codes, since it's not used for a missed request
138b92f8445Sssszwic        }
139b92f8445Sssszwic      }
140b92f8445Sssszwic      hit_vec(i) := vset_same && (ptag_same || way_same)
141b92f8445Sssszwic    }
142b92f8445Sssszwic    hit := hit_vec.reduce(_ || _)
143b92f8445Sssszwic  }
144b92f8445Sssszwic
145b92f8445Sssszwic  /**
146b92f8445Sssszwic    ******************************************************************************
147b92f8445Sssszwic    * read
148b92f8445Sssszwic    ******************************************************************************
149b92f8445Sssszwic    */
150b7a4433dSxu_zh  // if the entry is empty, but there is a valid write, we can bypass it to read port (maybe timing critical)
151b7a4433dSxu_zh  private val can_bypass = empty && io.write.valid
152b92f8445Sssszwic  io.read.valid := !empty || io.write.valid
153b7a4433dSxu_zh  when(can_bypass) {
15491946104Sxu_zh    io.read.bits := io.write.bits
155b7a4433dSxu_zh  }.otherwise { // can't bypass
15691946104Sxu_zh    io.read.bits.entry := entries(readPtr.value)
157b7a4433dSxu_zh    when(gpf_hit) { // ptr match && entry valid
158b7a4433dSxu_zh      io.read.bits.gpf := gpf_entry.bits
159415fcbe2Sxu_zh      // also clear gpf_entry.valid when it's read, note this will be overridden by write (L175)
160b7a4433dSxu_zh      when(io.read.fire) {
161b7a4433dSxu_zh        gpf_entry.valid := false.B
162b7a4433dSxu_zh      }
163b7a4433dSxu_zh    }.otherwise { // gpf not hit
164b7a4433dSxu_zh      io.read.bits.gpf := 0.U.asTypeOf(new WayLookupGPFEntry)
165b7a4433dSxu_zh    }
16691946104Sxu_zh  }
167b92f8445Sssszwic
168b92f8445Sssszwic  /**
169b92f8445Sssszwic    ******************************************************************************
170b92f8445Sssszwic    * write
171b92f8445Sssszwic    ******************************************************************************
172b92f8445Sssszwic    */
173415fcbe2Sxu_zh  // if there is a valid gpf to be read, we should stall write
174b7a4433dSxu_zh  private val gpf_stall = gpf_entry.valid && !(io.read.fire && gpf_hit)
175b7a4433dSxu_zh  io.write.ready := !full && !gpf_stall
176b92f8445Sssszwic  when(io.write.fire) {
17791946104Sxu_zh    entries(writePtr.value) := io.write.bits.entry
178b7a4433dSxu_zh    when(io.write.bits.itlb_exception.map(_ === ExceptionType.gpf).reduce(_ || _)) {
179b7a4433dSxu_zh      // if gpf_entry is bypassed, we don't need to save it
180b7a4433dSxu_zh      // note this will override the read (L156)
181b7a4433dSxu_zh      gpf_entry.valid := !(can_bypass && io.read.fire)
18288895b11Sxu_zh      gpf_entry.bits  := io.write.bits.gpf
18391946104Sxu_zh      gpfPtr          := writePtr
18491946104Sxu_zh    }
185b92f8445Sssszwic  }
186b92f8445Sssszwic}
187