xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueRAR.scala (revision 14a67055130242df761c9ace8347e012d57b32a7)
1e4f69d78Ssfencevma/***************************************************************************************
2e4f69d78Ssfencevma* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3e4f69d78Ssfencevma* Copyright (c) 2020-2021 Peng Cheng Laboratory
4e4f69d78Ssfencevma*
5e4f69d78Ssfencevma* XiangShan is licensed under Mulan PSL v2.
6e4f69d78Ssfencevma* You can use this software according to the terms and conditions of the Mulan PSL v2.
7e4f69d78Ssfencevma* You may obtain a copy of Mulan PSL v2 at:
8e4f69d78Ssfencevma*          http://license.coscl.org.cn/MulanPSL2
9e4f69d78Ssfencevma*
10e4f69d78Ssfencevma* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11e4f69d78Ssfencevma* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12e4f69d78Ssfencevma* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13e4f69d78Ssfencevma*
14e4f69d78Ssfencevma* See the Mulan PSL v2 for more details.
15e4f69d78Ssfencevma***************************************************************************************/
16e4f69d78Ssfencevmapackage xiangshan.mem
17e4f69d78Ssfencevma
18e4f69d78Ssfencevmaimport chisel3._
19e4f69d78Ssfencevmaimport chisel3.util._
20e4f69d78Ssfencevmaimport chipsalliance.rocketchip.config._
21e4f69d78Ssfencevmaimport xiangshan._
22e4f69d78Ssfencevmaimport xiangshan.backend.rob.RobPtr
23e4f69d78Ssfencevmaimport xiangshan.cache._
24e4f69d78Ssfencevmaimport utils._
25e4f69d78Ssfencevmaimport utility._
26e4f69d78Ssfencevma
27e4f69d78Ssfencevmaclass LoadQueueRAR(implicit p: Parameters) extends XSModule
28e4f69d78Ssfencevma  with HasDCacheParameters
29e4f69d78Ssfencevma  with HasCircularQueuePtrHelper
30e4f69d78Ssfencevma  with HasLoadHelper
31e4f69d78Ssfencevma  with HasPerfEvents
32e4f69d78Ssfencevma{
33e4f69d78Ssfencevma  val io = IO(new Bundle() {
34*14a67055Ssfencevma    // control
35e4f69d78Ssfencevma    val redirect = Flipped(Valid(new Redirect))
36*14a67055Ssfencevma
37*14a67055Ssfencevma    // violation query
38*14a67055Ssfencevma    val query = Vec(LoadPipelineWidth, Flipped(new LoadNukeQueryIO))
39*14a67055Ssfencevma
40*14a67055Ssfencevma    // release cacheline
41e4f69d78Ssfencevma    val release = Flipped(Valid(new Release))
42*14a67055Ssfencevma
43*14a67055Ssfencevma    // from VirtualLoadQueue
44e4f69d78Ssfencevma    val ldWbPtr = Input(new LqPtr)
45*14a67055Ssfencevma
46*14a67055Ssfencevma    // global
47e4f69d78Ssfencevma    val lqFull = Output(Bool())
48e4f69d78Ssfencevma  })
49e4f69d78Ssfencevma
50e4f69d78Ssfencevma  println("LoadQueueRAR: size: " + LoadQueueRARSize)
51e4f69d78Ssfencevma  //  LoadQueueRAR field
52e4f69d78Ssfencevma  //  +-------+-------+-------+----------+
53e4f69d78Ssfencevma  //  | Valid |  Uop  | PAddr | Released |
54e4f69d78Ssfencevma  //  +-------+-------+-------+----------+
55e4f69d78Ssfencevma  //
56e4f69d78Ssfencevma  //  Field descriptions:
57e4f69d78Ssfencevma  //  Allocated   : entry is valid.
58e4f69d78Ssfencevma  //  MicroOp     : Micro-op
59e4f69d78Ssfencevma  //  PAddr       : physical address.
60e4f69d78Ssfencevma  //  Released    : DCache released.
61e4f69d78Ssfencevma  //
62e4f69d78Ssfencevma  val allocated = RegInit(VecInit(List.fill(LoadQueueRARSize)(false.B))) // The control signals need to explicitly indicate the initial value
63e4f69d78Ssfencevma  val uop = Reg(Vec(LoadQueueRARSize, new MicroOp))
64e4f69d78Ssfencevma  val paddrModule = Module(new LqPAddrModule(
65e4f69d78Ssfencevma    gen = UInt(PAddrBits.W),
66e4f69d78Ssfencevma    numEntries = LoadQueueRARSize,
67e4f69d78Ssfencevma    numRead = LoadPipelineWidth,
68e4f69d78Ssfencevma    numWrite = LoadPipelineWidth,
69e4f69d78Ssfencevma    numWBank = LoadQueueNWriteBanks,
70e4f69d78Ssfencevma    numWDelay = 2,
71e4f69d78Ssfencevma    numCamPort = LoadPipelineWidth
72e4f69d78Ssfencevma  ))
73e4f69d78Ssfencevma  paddrModule.io := DontCare
74e4f69d78Ssfencevma  val released = RegInit(VecInit(List.fill(LoadQueueRARSize)(false.B)))
75e4f69d78Ssfencevma
76e4f69d78Ssfencevma  // freeliset: store valid entries index.
77e4f69d78Ssfencevma  // +---+---+--------------+-----+-----+
78e4f69d78Ssfencevma  // | 0 | 1 |      ......  | n-2 | n-1 |
79e4f69d78Ssfencevma  // +---+---+--------------+-----+-----+
80e4f69d78Ssfencevma  val freeList = Module(new FreeList(
81e4f69d78Ssfencevma    size = LoadQueueRARSize,
82e4f69d78Ssfencevma    allocWidth = LoadPipelineWidth,
83e4f69d78Ssfencevma    freeWidth = 4,
84e4f69d78Ssfencevma    moduleName = "LoadQueueRAR freelist"
85e4f69d78Ssfencevma  ))
86e4f69d78Ssfencevma  freeList.io := DontCare
87e4f69d78Ssfencevma
88e4f69d78Ssfencevma  // Real-allocation: load_s2
89e4f69d78Ssfencevma  // PAddr write needs 2 cycles, release signal should delay 1 cycle so that
90e4f69d78Ssfencevma  // load enqueue can catch release.
91e4f69d78Ssfencevma  val release1Cycle = io.release
92e4f69d78Ssfencevma  val release2Cycle = RegNext(io.release)
93e4f69d78Ssfencevma  val release2Cycle_dup_lsu = RegNext(io.release)
94e4f69d78Ssfencevma
95e4f69d78Ssfencevma  // LoadQueueRAR enqueue condition:
96e4f69d78Ssfencevma  // There are still not completed load instructions before the current load instruction.
97e4f69d78Ssfencevma  // (e.g. "not completed" means that load instruction get the data or exception).
98e4f69d78Ssfencevma  val canEnqueue = io.query.map(_.req.valid)
99e4f69d78Ssfencevma  val cancelEnqueue = io.query.map(_.req.bits.uop.robIdx.needFlush(io.redirect))
100e4f69d78Ssfencevma  val hasNotWritebackedLoad = io.query.map(_.req.bits.uop.lqIdx).map(lqIdx => isAfter(lqIdx, io.ldWbPtr))
101e4f69d78Ssfencevma  val needEnqueue = canEnqueue.zip(hasNotWritebackedLoad).zip(cancelEnqueue).map { case ((v, r), c) => v && r && !c }
102e4f69d78Ssfencevma
103e4f69d78Ssfencevma  // Allocate logic
104e4f69d78Ssfencevma  val enqValidVec = Wire(Vec(LoadPipelineWidth, Bool()))
105e4f69d78Ssfencevma  val enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt()))
106e4f69d78Ssfencevma
107e4f69d78Ssfencevma  for ((enq, w) <- io.query.map(_.req).zipWithIndex) {
108e4f69d78Ssfencevma    paddrModule.io.wen(w) := false.B
109e4f69d78Ssfencevma    freeList.io.doAllocate(w) := false.B
110e4f69d78Ssfencevma
111e4f69d78Ssfencevma    freeList.io.allocateReq(w) := needEnqueue(w)
112e4f69d78Ssfencevma
113e4f69d78Ssfencevma    //  Allocate ready
114bd65812fSsfencevma    enqValidVec(w) := freeList.io.canAllocate(w)
115bd65812fSsfencevma    enqIndexVec(w) := freeList.io.allocateSlot(w)
116e4f69d78Ssfencevma    enq.ready := Mux(needEnqueue(w), enqValidVec(w), true.B)
117e4f69d78Ssfencevma
118e4f69d78Ssfencevma    val enqIndex = enqIndexVec(w)
119e4f69d78Ssfencevma    when (needEnqueue(w) && enq.ready) {
120e4f69d78Ssfencevma      val debug_robIdx = enq.bits.uop.robIdx.asUInt
121e4f69d78Ssfencevma      XSError(allocated(enqIndex), p"LoadQueueRAR: You can not write an valid entry! check: ldu $w, robIdx $debug_robIdx")
122e4f69d78Ssfencevma
123e4f69d78Ssfencevma      freeList.io.doAllocate(w) := true.B
124e4f69d78Ssfencevma
125e4f69d78Ssfencevma      //  Allocate new entry
126e4f69d78Ssfencevma      allocated(enqIndex) := true.B
127e4f69d78Ssfencevma
128e4f69d78Ssfencevma      //  Write paddr
129e4f69d78Ssfencevma      paddrModule.io.wen(w) := true.B
130e4f69d78Ssfencevma      paddrModule.io.waddr(w) := enqIndex
131e4f69d78Ssfencevma      paddrModule.io.wdata(w) := enq.bits.paddr
132e4f69d78Ssfencevma
133e4f69d78Ssfencevma      //  Fill info
134e4f69d78Ssfencevma      uop(enqIndex) := enq.bits.uop
135e4f69d78Ssfencevma      released(enqIndex) :=
136*14a67055Ssfencevma        enq.bits.data_valid &&
1374ab5d137Ssfencevma        (release2Cycle.valid &&
138e4f69d78Ssfencevma        enq.bits.paddr(PAddrBits-1, DCacheLineOffset) === release2Cycle.bits.paddr(PAddrBits-1, DCacheLineOffset) ||
139e4f69d78Ssfencevma        release1Cycle.valid &&
1404ab5d137Ssfencevma        enq.bits.paddr(PAddrBits-1, DCacheLineOffset) === release1Cycle.bits.paddr(PAddrBits-1, DCacheLineOffset))
141e4f69d78Ssfencevma    }
142e4f69d78Ssfencevma  }
143e4f69d78Ssfencevma
144e4f69d78Ssfencevma  //  LoadQueueRAR deallocate
145e4f69d78Ssfencevma  val freeMaskVec = Wire(Vec(LoadQueueRARSize, Bool()))
146e4f69d78Ssfencevma
147e4f69d78Ssfencevma  // init
148e4f69d78Ssfencevma  freeMaskVec.map(e => e := false.B)
149e4f69d78Ssfencevma
150e4f69d78Ssfencevma  // when the loads that "older than" current load were writebacked,
151e4f69d78Ssfencevma  // current load will be released.
152e4f69d78Ssfencevma  for (i <- 0 until LoadQueueRARSize) {
153e4f69d78Ssfencevma    val deqNotBlock = !isBefore(io.ldWbPtr, uop(i).lqIdx)
154e4f69d78Ssfencevma    val needFlush = uop(i).robIdx.needFlush(io.redirect)
155e4f69d78Ssfencevma
156e4f69d78Ssfencevma    when (allocated(i) && (deqNotBlock || needFlush)) {
157e4f69d78Ssfencevma      allocated(i) := false.B
158e4f69d78Ssfencevma      freeMaskVec(i) := true.B
159e4f69d78Ssfencevma    }
160e4f69d78Ssfencevma  }
161e4f69d78Ssfencevma
162*14a67055Ssfencevma  // if need replay revoke entry
163e4f69d78Ssfencevma  val lastCanAccept = RegNext(VecInit(needEnqueue.zip(enqValidVec).map(x => x._1 && x._2)))
164e4f69d78Ssfencevma  val lastAllocIndex = RegNext(enqIndexVec)
165e4f69d78Ssfencevma
166*14a67055Ssfencevma  for ((revoke, w) <- io.query.map(_.revoke).zipWithIndex) {
167*14a67055Ssfencevma    val revokeValid = revoke && lastCanAccept(w)
168*14a67055Ssfencevma    val revokeIndex = lastAllocIndex(w)
169e4f69d78Ssfencevma
170*14a67055Ssfencevma    when (allocated(revokeIndex) && revokeValid) {
171*14a67055Ssfencevma      allocated(revokeIndex) := false.B
172*14a67055Ssfencevma      freeMaskVec(revokeIndex) := true.B
173e4f69d78Ssfencevma    }
174e4f69d78Ssfencevma  }
175e4f69d78Ssfencevma
176e4f69d78Ssfencevma  freeList.io.free := freeMaskVec.asUInt
177e4f69d78Ssfencevma
178e4f69d78Ssfencevma  // LoadQueueRAR Query
179e4f69d78Ssfencevma  // Load-to-Load violation check condition:
180e4f69d78Ssfencevma  // 1. Physical address match by CAM port.
181e4f69d78Ssfencevma  // 2. release is set.
182e4f69d78Ssfencevma  // 3. Younger than current load instruction.
183e4f69d78Ssfencevma  val ldLdViolation = Wire(Vec(LoadPipelineWidth, Bool()))
184e4f69d78Ssfencevma  val allocatedUInt = RegNext(allocated.asUInt)
185e4f69d78Ssfencevma  for ((query, w) <- io.query.zipWithIndex) {
186e4f69d78Ssfencevma    ldLdViolation(w) := false.B
187e4f69d78Ssfencevma    paddrModule.io.releaseViolationMdata(w) := query.req.bits.paddr
188e4f69d78Ssfencevma
189e4f69d78Ssfencevma    query.resp.valid := RegNext(query.req.valid)
190e4f69d78Ssfencevma    // Generate real violation mask
191e4f69d78Ssfencevma    val robIdxMask = VecInit(uop.map(_.robIdx).map(isAfter(_, query.req.bits.uop.robIdx)))
192e4f69d78Ssfencevma    val matchMask = allocatedUInt &
193e4f69d78Ssfencevma                    RegNext(paddrModule.io.releaseViolationMmask(w).asUInt) &
194e4f69d78Ssfencevma                    RegNext(robIdxMask.asUInt)
195e4f69d78Ssfencevma    //  Load-to-Load violation check result
196e4f69d78Ssfencevma    val ldLdViolationMask = WireInit(matchMask & RegNext(released.asUInt))
197e4f69d78Ssfencevma    ldLdViolationMask.suggestName("ldLdViolationMask_" + w)
198*14a67055Ssfencevma    query.resp.bits.rep_frm_fetch := ldLdViolationMask.orR
199e4f69d78Ssfencevma  }
200e4f69d78Ssfencevma
201e4f69d78Ssfencevma
202e4f69d78Ssfencevma  // When io.release.valid (release1cycle.valid), it uses the last ld-ld paddr cam port to
203e4f69d78Ssfencevma  // update release flag in 1 cycle
204e4f69d78Ssfencevma  val releaseVioMask = Reg(Vec(LoadQueueRARSize, Bool()))
205e4f69d78Ssfencevma  when (release1Cycle.valid) {
206e4f69d78Ssfencevma    paddrModule.io.releaseMdata.takeRight(1)(0) := release1Cycle.bits.paddr
207e4f69d78Ssfencevma  }
208e4f69d78Ssfencevma
209e4f69d78Ssfencevma  (0 until LoadQueueRARSize).map(i => {
210e4f69d78Ssfencevma    when (RegNext(paddrModule.io.releaseMmask.takeRight(1)(0)(i) && allocated(i) && release1Cycle.valid)) {
211e4f69d78Ssfencevma      // Note: if a load has missed in dcache and is waiting for refill in load queue,
212e4f69d78Ssfencevma      // its released flag still needs to be set as true if addr matches.
213e4f69d78Ssfencevma      released(i) := true.B
214e4f69d78Ssfencevma    }
215e4f69d78Ssfencevma  })
216e4f69d78Ssfencevma
217e4f69d78Ssfencevma  io.lqFull := freeList.io.empty
218e4f69d78Ssfencevma
219e4f69d78Ssfencevma  // perf cnt
220e4f69d78Ssfencevma  val canEnqCount = PopCount(io.query.map(_.req.fire))
221e4f69d78Ssfencevma  val validCount = freeList.io.validCount
222e4f69d78Ssfencevma  val allowEnqueue = validCount <= (LoadQueueRARSize - LoadPipelineWidth).U
223*14a67055Ssfencevma  val ldLdViolationCount = PopCount(io.query.map(_.resp).map(resp => resp.valid && resp.bits.rep_frm_fetch))
224e4f69d78Ssfencevma
225e4f69d78Ssfencevma  QueuePerf(LoadQueueRARSize, validCount, !allowEnqueue)
226e4f69d78Ssfencevma  XSPerfAccumulate("enq", canEnqCount)
227e4f69d78Ssfencevma  XSPerfAccumulate("ld_ld_violation", ldLdViolationCount)
228e4f69d78Ssfencevma  val perfEvents: Seq[(String, UInt)] = Seq(
229e4f69d78Ssfencevma    ("enq", canEnqCount),
230e4f69d78Ssfencevma    ("ld_ld_violation", ldLdViolationCount)
231e4f69d78Ssfencevma  )
232e4f69d78Ssfencevma  generatePerfEvent()
233e4f69d78Ssfencevma  // End
234e4f69d78Ssfencevma}