xref: /XiangShan/src/main/scala/xiangshan/cache/mmu/Repeater.scala (revision a273862e37f1d43bee748f2a6353320a2f52f6f4)
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.cache.mmu
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import xiangshan.cache.{HasDCacheParameters, MemoryOpConstants}
24import utils._
25import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
26import freechips.rocketchip.tilelink._
27
28class PTWReapterIO(Width: Int)(implicit p: Parameters) extends MMUIOBaseBundle {
29  val tlb = Flipped(new TlbPtwIO(Width))
30  val ptw = new TlbPtwIO
31
32  override def cloneType: this.type = (new PTWReapterIO(Width)).asInstanceOf[this.type]
33}
34
35class PTWRepeater(Width: Int = 1)(implicit p: Parameters) extends XSModule with HasPtwConst {
36  val io = IO(new PTWReapterIO(Width))
37
38  val req_in = if (Width == 1) {
39    io.tlb.req(0)
40  } else {
41    val arb = Module(new RRArbiter(io.tlb.req(0).bits.cloneType, Width))
42    arb.io.in <> io.tlb.req
43    arb.io.out
44  }
45  val (tlb, ptw, flush) = (io.tlb, io.ptw, RegNext(io.sfence.valid || io.csr.satp.changed))
46  val req = RegEnable(req_in.bits, req_in.fire())
47  val resp = RegEnable(ptw.resp.bits, ptw.resp.fire())
48  val haveOne = BoolStopWatch(req_in.fire(), tlb.resp.fire() || flush)
49  val sent = BoolStopWatch(ptw.req(0).fire(), req_in.fire() || flush)
50  val recv = BoolStopWatch(ptw.resp.fire(), req_in.fire() || flush)
51
52  req_in.ready := !haveOne
53  ptw.req(0).valid := haveOne && !sent
54  ptw.req(0).bits := req
55
56  tlb.resp.bits := resp
57  tlb.resp.valid := haveOne && recv
58  ptw.resp.ready := !recv
59
60  XSPerfAccumulate("req_count", ptw.req(0).fire())
61  XSPerfAccumulate("tlb_req_cycle", BoolStopWatch(req_in.fire(), tlb.resp.fire() || flush))
62  XSPerfAccumulate("ptw_req_cycle", BoolStopWatch(ptw.req(0).fire(), ptw.resp.fire() || flush))
63
64  XSDebug(haveOne, p"haveOne:${haveOne} sent:${sent} recv:${recv} sfence:${flush} req:${req} resp:${resp}")
65  XSDebug(req_in.valid || io.tlb.resp.valid, p"tlb: ${tlb}\n")
66  XSDebug(io.ptw.req(0).valid || io.ptw.resp.valid, p"ptw: ${ptw}\n")
67  assert(!RegNext(recv && io.ptw.resp.valid, init = false.B), "re-receive ptw.resp")
68  TimeOutAssert(sent && !recv, timeOutThreshold, "Repeater doesn't recv resp in time")
69}
70
71/* dtlb
72 *
73 */
74class PTWFilterIO(Width: Int)(implicit p: Parameters) extends MMUIOBaseBundle {
75  val tlb = Flipped(new BTlbPtwIO(Width))
76  val ptw = new TlbPtwIO()
77
78  override def cloneType: this.type = (new PTWFilterIO(Width)).asInstanceOf[this.type]
79}
80
81class PTWFilter(Width: Int, Size: Int)(implicit p: Parameters) extends XSModule with HasPtwConst {
82  require(Size >= Width)
83
84  val io = IO(new PTWFilterIO(Width))
85
86  val v = RegInit(VecInit(Seq.fill(Size)(false.B)))
87  val ports = Reg(Vec(Size, Vec(Width, Bool()))) // record which port(s) the entry come from, may not able to cover all the ports
88  val vpn = Reg(Vec(Size, UInt(vpnLen.W)))
89  val enqPtr = RegInit(0.U(log2Up(Size).W)) // Enq
90  val issPtr = RegInit(0.U(log2Up(Size).W)) // Iss to Ptw
91  val deqPtr = RegInit(0.U(log2Up(Size).W)) // Deq
92  val mayFullDeq = RegInit(false.B)
93  val mayFullIss = RegInit(false.B)
94  val counter = RegInit(0.U(log2Up(Size+1).W))
95
96  val flush = RegNext(io.sfence.valid || io.csr.satp.changed)
97  val ptwResp = RegEnable(io.ptw.resp.bits, io.ptw.resp.fire())
98  val ptwResp_valid = RegNext(io.ptw.resp.valid, init = false.B)
99  val tlb_req = io.tlb.req
100  val oldMatchVec = tlb_req.map(a => vpn.zip(v).map{case (pi, vi) => vi && a.valid && pi === a.bits.vpn })
101  val newMatchVec = tlb_req.map(a => tlb_req.map(b => b.valid && a.valid && b.bits.vpn === a.bits.vpn ))
102  val ptwResp_newMatchVec = tlb_req.map(a => ptwResp_valid && ptwResp.entry.hit(a.bits.vpn, io.csr.satp.asid, allType = true) && a.valid) // TODO: may have long latency
103  val ptwResp_oldMatchVec = vpn.zip(v).map{ case (pi, vi) => vi && ptwResp.entry.hit(pi, io.csr.satp.asid, allType = true) }
104  val update_ports = v.indices.map(i => oldMatchVec.map(j => j(i)))
105  val ports_init = (0 until Width).map(i => (1 << i).U(Width.W))
106  val filter_ports = (0 until Width).map(i => ParallelMux(newMatchVec(i).zip(ports_init).drop(i)))
107  val resp_vector = ParallelMux(ptwResp_oldMatchVec zip ports)
108  val resp_still_valid = ParallelOR(ptwResp_oldMatchVec).asBool
109
110  def canMerge(index: Int) : Bool = {
111    ptwResp_newMatchVec(index) ||
112    Cat(oldMatchVec(index)).orR ||
113    Cat(newMatchVec(index).take(index)).orR
114  }
115
116  def filter_req() = {
117    val reqs =  tlb_req.indices.map{ i =>
118      val req = Wire(ValidIO(new PtwReq()))
119      val merge = canMerge(i)
120      req.bits := tlb_req(i).bits
121      req.valid := !merge && tlb_req(i).valid
122      req
123    }
124    reqs
125  }
126
127  val reqs = filter_req()
128  val req_ports = filter_ports
129  var enqPtr_next = WireInit(deqPtr)
130  val isFull = enqPtr === deqPtr && mayFullDeq
131  val isEmptyDeq = enqPtr === deqPtr && !mayFullDeq
132  val isEmptyIss = enqPtr === issPtr && !mayFullIss
133  val accumEnqNum = (0 until Width).map(i => PopCount(reqs.take(i).map(_.valid)))
134  val enqPtrVec = VecInit((0 until Width).map(i => enqPtr + accumEnqNum(i)))
135  val enqNum = PopCount(reqs.map(_.valid))
136  val canEnqueue = counter +& enqNum <= Size.U
137
138  io.tlb.req.map(_.ready := true.B) // NOTE: just drop un-fire reqs
139  io.tlb.resp.valid := ptwResp_valid && resp_still_valid
140  io.tlb.resp.bits.data := ptwResp
141  io.tlb.resp.bits.vector := resp_vector
142  io.ptw.req(0).valid := v(issPtr) && !isEmptyIss && !(ptwResp_valid && ptwResp.entry.hit(io.ptw.req(0).bits.vpn, io.csr.satp.asid, ignoreAsid = true))
143  io.ptw.req(0).bits.vpn := vpn(issPtr)
144  io.ptw.resp.ready := true.B
145
146  reqs.zipWithIndex.map{
147    case (req, i) =>
148      when (req.valid && canEnqueue) {
149        v(enqPtrVec(i)) := true.B
150        vpn(enqPtrVec(i)) := req.bits.vpn
151        ports(enqPtrVec(i)) := req_ports(i).asBools
152      }
153  }
154  for (i <- ports.indices) {
155    when (v(i)) {
156      ports(i) := ports(i).zip(update_ports(i)).map(a => a._1 || a._2)
157    }
158  }
159
160  val do_enq = canEnqueue && Cat(reqs.map(_.valid)).orR
161  val do_deq = (!v(deqPtr) && !isEmptyDeq)
162  val do_iss = io.ptw.req(0).fire() || (!v(issPtr) && !isEmptyIss)
163  when (do_enq) {
164    enqPtr := enqPtr + enqNum
165  }
166  when (do_deq) {
167    deqPtr := deqPtr + 1.U
168  }
169  when (do_iss) {
170    issPtr := issPtr + 1.U
171  }
172  when (do_enq =/= do_deq) {
173    mayFullDeq := do_enq
174  }
175  when (do_enq =/= do_iss) {
176    mayFullIss := do_enq
177  }
178
179  when (ptwResp_valid) {
180    v.zip(ptwResp_oldMatchVec).map{ case (vi, mi) => when (mi) { vi := false.B }}
181  }
182
183  counter := counter - do_deq + Mux(do_enq, enqNum, 0.U)
184  assert(counter <= Size.U, "counter should be less than Size")
185  when (counter === 0.U) {
186    assert(!io.ptw.req(0).fire(), "when counter is 0, should not req")
187    assert(isEmptyDeq && isEmptyIss, "when counter is 0, should be empty")
188  }
189  when (counter === Size.U) {
190    assert(mayFullDeq, "when counter is Size, should be full")
191  }
192
193  when (flush) {
194    v.map(_ := false.B)
195    deqPtr := 0.U
196    enqPtr := 0.U
197    issPtr := 0.U
198    ptwResp_valid := false.B
199    mayFullDeq := false.B
200    mayFullIss := false.B
201    counter := 0.U
202  }
203
204  // perf
205  val inflight_counter = RegInit(0.U(log2Up(Size + 1).W))
206  when (io.ptw.req(0).fire() =/= io.ptw.resp.fire()) {
207    inflight_counter := Mux(io.ptw.req(0).fire(), inflight_counter + 1.U, inflight_counter - 1.U)
208  }
209  when (flush) {
210    inflight_counter := 0.U
211  }
212  XSPerfAccumulate("tlb_req_count", PopCount(Cat(io.tlb.req.map(_.valid))))
213  XSPerfAccumulate("tlb_req_count_filtered", Mux(do_enq, accumEnqNum(Width - 1), 0.U))
214  XSPerfAccumulate("ptw_req_count", io.ptw.req(0).fire())
215  XSPerfAccumulate("ptw_req_cycle", inflight_counter)
216  XSPerfAccumulate("tlb_resp_count", io.tlb.resp.fire())
217  XSPerfAccumulate("ptw_resp_count", io.ptw.resp.fire())
218  XSPerfAccumulate("inflight_cycle", !isEmptyDeq)
219  for (i <- 0 until Size + 1) {
220    XSPerfAccumulate(s"counter${i}", counter === i.U)
221  }
222
223  for (i <- 0 until Size) {
224    TimeOutAssert(v(i), timeOutThreshold, s"Filter ${i} doesn't recv resp in time")
225  }
226}
227
228object PTWRepeater {
229  def apply(
230    tlb: TlbPtwIO,
231    sfence: SfenceBundle,
232    csr: TlbCsrBundle
233  )(implicit p: Parameters) = {
234    val width = tlb.req.size
235    val repeater = Module(new PTWRepeater(width))
236    repeater.io.tlb <> tlb
237    repeater.io.sfence <> sfence
238    repeater.io.csr <> csr
239
240    repeater
241  }
242
243  def apply(
244    tlb: TlbPtwIO,
245    ptw: TlbPtwIO,
246    sfence: SfenceBundle,
247    csr: TlbCsrBundle
248  )(implicit p: Parameters) = {
249    val width = tlb.req.size
250    val repeater = Module(new PTWRepeater(width))
251    repeater.io.tlb <> tlb
252    repeater.io.ptw <> ptw
253    repeater.io.sfence <> sfence
254    repeater.io.csr <> csr
255
256    repeater
257  }
258}
259
260object PTWFilter {
261  def apply(
262    tlb: BTlbPtwIO,
263    ptw: TlbPtwIO,
264    sfence: SfenceBundle,
265    csr: TlbCsrBundle,
266    size: Int
267  )(implicit p: Parameters) = {
268    val width = tlb.req.size
269    val filter = Module(new PTWFilter(width, size))
270    filter.io.tlb <> tlb
271    filter.io.ptw <> ptw
272    filter.io.sfence <> sfence
273    filter.io.csr <> csr
274
275    filter
276  }
277}