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