xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/StoreQueue.scala (revision dc597826530cb6803c2396d6ab0e5eb176b732e0)
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.mem
18
19import chipsalliance.rocketchip.config.Parameters
20import chisel3._
21import chisel3.util._
22import utils._
23import xiangshan._
24import xiangshan.cache._
25import xiangshan.cache.{DCacheWordIO, DCacheLineIO, MemoryOpConstants}
26import xiangshan.backend.roq.{RoqLsqIO, RoqPtr}
27import difftest._
28import device.RAMHelper
29
30class SqPtr(implicit p: Parameters) extends CircularQueuePtr[SqPtr](
31  p => p(XSCoreParamsKey).StoreQueueSize
32){
33  override def cloneType = (new SqPtr).asInstanceOf[this.type]
34}
35
36object SqPtr {
37  def apply(f: Bool, v: UInt)(implicit p: Parameters): SqPtr = {
38    val ptr = Wire(new SqPtr)
39    ptr.flag := f
40    ptr.value := v
41    ptr
42  }
43}
44
45class SqEnqIO(implicit p: Parameters) extends XSBundle {
46  val canAccept = Output(Bool())
47  val lqCanAccept = Input(Bool())
48  val needAlloc = Vec(RenameWidth, Input(Bool()))
49  val req = Vec(RenameWidth, Flipped(ValidIO(new MicroOp)))
50  val resp = Vec(RenameWidth, Output(new SqPtr))
51}
52
53// Store Queue
54class StoreQueue(implicit p: Parameters) extends XSModule with HasDCacheParameters with HasCircularQueuePtrHelper {
55  val io = IO(new Bundle() {
56    val enq = new SqEnqIO
57    val brqRedirect = Flipped(ValidIO(new Redirect))
58    val flush = Input(Bool())
59    val storeIn = Vec(StorePipelineWidth, Flipped(Valid(new LsPipelineBundle))) // store addr, data is not included
60    val storeDataIn = Vec(StorePipelineWidth, Flipped(Valid(new StoreDataBundle))) // store data, send to sq from rs
61    val sbuffer = Vec(StorePipelineWidth, Decoupled(new DCacheWordReq)) // write commited store to sbuffer
62    val mmioStout = DecoupledIO(new ExuOutput) // writeback uncached store
63    val forward = Vec(LoadPipelineWidth, Flipped(new PipeLoadForwardQueryIO))
64    val roq = Flipped(new RoqLsqIO)
65    val uncache = new DCacheWordIO
66    // val refill = Flipped(Valid(new DCacheLineReq ))
67    val exceptionAddr = new ExceptionAddrIO
68    val sqempty = Output(Bool())
69    val issuePtrExt = Output(new SqPtr) // used to wake up delayed load/store
70    val sqFull = Output(Bool())
71  })
72
73  println("StoreQueue: size:" + StoreQueueSize)
74
75  // data modules
76  val uop = Reg(Vec(StoreQueueSize, new MicroOp))
77  // val data = Reg(Vec(StoreQueueSize, new LsqEntry))
78  val dataModule = Module(new SQDataModule(StoreQueueSize, numRead = StorePipelineWidth, numWrite = StorePipelineWidth, numForward = StorePipelineWidth))
79  dataModule.io := DontCare
80  val paddrModule = Module(new SQPaddrModule(StoreQueueSize, numRead = StorePipelineWidth, numWrite = StorePipelineWidth, numForward = StorePipelineWidth))
81  paddrModule.io := DontCare
82  val vaddrModule = Module(new SyncDataModuleTemplate(UInt(VAddrBits.W), StoreQueueSize, numRead = 1, numWrite = StorePipelineWidth))
83  vaddrModule.io := DontCare
84
85  // state & misc
86  val allocated = RegInit(VecInit(List.fill(StoreQueueSize)(false.B))) // sq entry has been allocated
87  val addrvalid = RegInit(VecInit(List.fill(StoreQueueSize)(false.B))) // non-mmio addr is valid
88  val datavalid = RegInit(VecInit(List.fill(StoreQueueSize)(false.B))) // non-mmio data is valid
89  val allvalid  = VecInit((0 until StoreQueueSize).map(i => addrvalid(i) && datavalid(i))) // non-mmio data & addr is valid
90  val commited = Reg(Vec(StoreQueueSize, Bool())) // inst has been commited by roq
91  val pending = Reg(Vec(StoreQueueSize, Bool())) // mmio pending: inst is an mmio inst, it will not be executed until it reachs the end of roq
92  val mmio = Reg(Vec(StoreQueueSize, Bool())) // mmio: inst is an mmio inst
93
94  // ptr
95  require(StoreQueueSize > RenameWidth)
96  val enqPtrExt = RegInit(VecInit((0 until RenameWidth).map(_.U.asTypeOf(new SqPtr))))
97  val deqPtrExt = RegInit(VecInit((0 until StorePipelineWidth).map(_.U.asTypeOf(new SqPtr))))
98  val cmtPtrExt = RegInit(VecInit((0 until CommitWidth).map(_.U.asTypeOf(new SqPtr))))
99  val issuePtrExt = RegInit(0.U.asTypeOf(new SqPtr))
100  val validCounter = RegInit(0.U(log2Ceil(LoadQueueSize + 1).W))
101  val allowEnqueue = RegInit(true.B)
102
103  val enqPtr = enqPtrExt(0).value
104  val deqPtr = deqPtrExt(0).value
105  val cmtPtr = cmtPtrExt(0).value
106
107  val deqMask = UIntToMask(deqPtr, StoreQueueSize)
108  val enqMask = UIntToMask(enqPtr, StoreQueueSize)
109
110  val commitCount = RegNext(io.roq.scommit)
111
112  // Read dataModule
113  // deqPtrExtNext and deqPtrExtNext+1 entry will be read from dataModule
114  // if !sbuffer.fire(), read the same ptr
115  // if sbuffer.fire(), read next
116  val deqPtrExtNext = WireInit(Mux(io.sbuffer(1).fire(),
117    VecInit(deqPtrExt.map(_ + 2.U)),
118    Mux(io.sbuffer(0).fire() || io.mmioStout.fire(),
119      VecInit(deqPtrExt.map(_ + 1.U)),
120      deqPtrExt
121    )
122  ))
123  for (i <- 0 until StorePipelineWidth) {
124    dataModule.io.raddr(i) := deqPtrExtNext(i).value
125    paddrModule.io.raddr(i) := deqPtrExtNext(i).value
126  }
127
128  // no inst will be commited 1 cycle before tval update
129  vaddrModule.io.raddr(0) := (cmtPtrExt(0) + commitCount).value
130
131  /**
132    * Enqueue at dispatch
133    *
134    * Currently, StoreQueue only allows enqueue when #emptyEntries > RenameWidth(EnqWidth)
135    */
136  io.enq.canAccept := allowEnqueue
137  for (i <- 0 until RenameWidth) {
138    val offset = if (i == 0) 0.U else PopCount(io.enq.needAlloc.take(i))
139    val sqIdx = enqPtrExt(offset)
140    val index = sqIdx.value
141    when (io.enq.req(i).valid && io.enq.canAccept && io.enq.lqCanAccept && !(io.brqRedirect.valid || io.flush)) {
142      uop(index) := io.enq.req(i).bits
143      allocated(index) := true.B
144      datavalid(index) := false.B
145      addrvalid(index) := false.B
146      commited(index) := false.B
147      pending(index) := false.B
148    }
149    io.enq.resp(i) := sqIdx
150  }
151  XSDebug(p"(ready, valid): ${io.enq.canAccept}, ${Binary(Cat(io.enq.req.map(_.valid)))}\n")
152
153  /**
154    * Update issuePtr when issue from rs
155    */
156  // update issuePtr
157  val IssuePtrMoveStride = 4
158  require(IssuePtrMoveStride >= 2)
159
160  val issueLookupVec = (0 until IssuePtrMoveStride).map(issuePtrExt + _.U)
161  val issueLookup = issueLookupVec.map(ptr => allocated(ptr.value) && addrvalid(ptr.value) && datavalid(ptr.value) && ptr =/= enqPtrExt(0))
162  val nextIssuePtr = issuePtrExt + PriorityEncoder(VecInit(issueLookup.map(!_) :+ true.B))
163  issuePtrExt := nextIssuePtr
164
165  when (io.brqRedirect.valid || io.flush) {
166    issuePtrExt := Mux(
167      isAfter(cmtPtrExt(0), deqPtrExt(0)),
168      cmtPtrExt(0),
169      deqPtrExtNext(0) // for mmio insts, deqPtr may be ahead of cmtPtr
170    )
171  }
172  // send issuePtrExt to rs
173  // io.issuePtrExt := cmtPtrExt(0)
174  io.issuePtrExt := issuePtrExt
175
176  /**
177    * Writeback store from store units
178    *
179    * Most store instructions writeback to regfile in the previous cycle.
180    * However,
181    *   (1) For an mmio instruction with exceptions, we need to mark it as addrvalid
182    * (in this way it will trigger an exception when it reaches ROB's head)
183    * instead of pending to avoid sending them to lower level.
184    *   (2) For an mmio instruction without exceptions, we mark it as pending.
185    * When the instruction reaches ROB's head, StoreQueue sends it to uncache channel.
186    * Upon receiving the response, StoreQueue writes back the instruction
187    * through arbiter with store units. It will later commit as normal.
188    */
189
190  // Write addr to sq
191  for (i <- 0 until StorePipelineWidth) {
192    paddrModule.io.wen(i) := false.B
193    dataModule.io.mask.wen(i) := false.B
194    val stWbIndex = io.storeIn(i).bits.uop.sqIdx.value
195    when (io.storeIn(i).fire()) {
196      addrvalid(stWbIndex) := true.B//!io.storeIn(i).bits.mmio
197      pending(stWbIndex) := io.storeIn(i).bits.mmio
198
199      dataModule.io.mask.waddr(i) := stWbIndex
200      dataModule.io.mask.wdata(i) := io.storeIn(i).bits.mask
201      dataModule.io.mask.wen(i) := true.B
202
203      paddrModule.io.waddr(i) := stWbIndex
204      paddrModule.io.wdata(i) := io.storeIn(i).bits.paddr
205      paddrModule.io.wen(i) := true.B
206
207      mmio(stWbIndex) := io.storeIn(i).bits.mmio
208
209      XSInfo("store addr write to sq idx %d pc 0x%x vaddr %x paddr %x mmio %x\n",
210        io.storeIn(i).bits.uop.sqIdx.value,
211        io.storeIn(i).bits.uop.cf.pc,
212        io.storeIn(i).bits.vaddr,
213        io.storeIn(i).bits.paddr,
214        io.storeIn(i).bits.mmio
215      )
216    }
217    // vaddrModule write is delayed, as vaddrModule will not be read right after write
218    vaddrModule.io.waddr(i) := RegNext(stWbIndex)
219    vaddrModule.io.wdata(i) := RegNext(io.storeIn(i).bits.vaddr)
220    vaddrModule.io.wen(i) := RegNext(io.storeIn(i).fire())
221  }
222
223  // Write data to sq
224  for (i <- 0 until StorePipelineWidth) {
225    dataModule.io.data.wen(i) := false.B
226    io.roq.storeDataRoqWb(i).valid := false.B
227    io.roq.storeDataRoqWb(i).bits := DontCare
228    val stWbIndex = io.storeDataIn(i).bits.uop.sqIdx.value
229    when (io.storeDataIn(i).fire()) {
230      datavalid(stWbIndex) := true.B
231
232      dataModule.io.data.waddr(i) := stWbIndex
233      dataModule.io.data.wdata(i) := genWdata(io.storeDataIn(i).bits.data, io.storeDataIn(i).bits.uop.ctrl.fuOpType(1,0))
234      dataModule.io.data.wen(i) := true.B
235
236      io.roq.storeDataRoqWb(i).valid := true.B
237      io.roq.storeDataRoqWb(i).bits := io.storeDataIn(i).bits.uop.roqIdx
238
239      XSInfo("store data write to sq idx %d pc 0x%x data %x -> %x\n",
240        io.storeDataIn(i).bits.uop.sqIdx.value,
241        io.storeDataIn(i).bits.uop.cf.pc,
242        io.storeDataIn(i).bits.data,
243        dataModule.io.data.wdata(i)
244      )
245    }
246  }
247
248  /**
249    * load forward query
250    *
251    * Check store queue for instructions that is older than the load.
252    * The response will be valid at the next cycle after req.
253    */
254  // check over all lq entries and forward data from the first matched store
255  for (i <- 0 until LoadPipelineWidth) {
256    io.forward(i).forwardMask := 0.U(8.W).asBools
257    io.forward(i).forwardData := DontCare
258
259    // Compare deqPtr (deqPtr) and forward.sqIdx, we have two cases:
260    // (1) if they have the same flag, we need to check range(tail, sqIdx)
261    // (2) if they have different flags, we need to check range(tail, LoadQueueSize) and range(0, sqIdx)
262    // Forward1: Mux(same_flag, range(tail, sqIdx), range(tail, LoadQueueSize))
263    // Forward2: Mux(same_flag, 0.U,                   range(0, sqIdx)    )
264    // i.e. forward1 is the target entries with the same flag bits and forward2 otherwise
265    val differentFlag = deqPtrExt(0).flag =/= io.forward(i).sqIdx.flag
266    val forwardMask = io.forward(i).sqIdxMask
267    // all addrvalid terms need to be checked
268    val addrValidVec = WireInit(VecInit((0 until StoreQueueSize).map(i => addrvalid(i) && allocated(i))))
269    val dataValidVec = WireInit(VecInit((0 until StoreQueueSize).map(i => datavalid(i))))
270    val allValidVec = WireInit(VecInit((0 until StoreQueueSize).map(i => addrvalid(i) && datavalid(i) && allocated(i))))
271    val canForward1 = Mux(differentFlag, ~deqMask, deqMask ^ forwardMask) & allValidVec.asUInt
272    val canForward2 = Mux(differentFlag, forwardMask, 0.U(StoreQueueSize.W)) & allValidVec.asUInt
273    val needForward = Mux(differentFlag, ~deqMask | forwardMask, deqMask ^ forwardMask)
274
275    XSDebug(p"$i f1 ${Binary(canForward1)} f2 ${Binary(canForward2)} " +
276      p"sqIdx ${io.forward(i).sqIdx} pa ${Hexadecimal(io.forward(i).paddr)}\n"
277    )
278
279    // do real fwd query (cam lookup in load_s1)
280    dataModule.io.needForward(i)(0) := canForward1 & paddrModule.io.forwardMmask(i).asUInt
281    dataModule.io.needForward(i)(1) := canForward2 & paddrModule.io.forwardMmask(i).asUInt
282
283    paddrModule.io.forwardMdata(i) := io.forward(i).paddr
284
285    // Forward result will be generated 1 cycle later (load_s2)
286    io.forward(i).forwardMask := dataModule.io.forwardMask(i)
287    io.forward(i).forwardData := dataModule.io.forwardData(i)
288
289    // If addr match, data not ready, mark it as dataInvalid
290    // load_s1: generate dataInvalid in load_s1 to set fastUop to
291    io.forward(i).dataInvalidFast := (addrValidVec.asUInt & ~dataValidVec.asUInt & paddrModule.io.forwardMmask(i).asUInt & needForward).orR
292    // load_s2
293    io.forward(i).dataInvalid := RegNext(io.forward(i).dataInvalidFast)
294  }
295
296  /**
297    * Memory mapped IO / other uncached operations
298    *
299    * States:
300    * (1) writeback from store units: mark as pending
301    * (2) when they reach ROB's head, they can be sent to uncache channel
302    * (3) response from uncache channel: mark as datavalidmask.wen
303    * (4) writeback to ROB (and other units): mark as writebacked
304    * (5) ROB commits the instruction: same as normal instructions
305    */
306  //(2) when they reach ROB's head, they can be sent to uncache channel
307  val s_idle :: s_req :: s_resp :: s_wb :: s_wait :: Nil = Enum(5)
308  val uncacheState = RegInit(s_idle)
309  switch(uncacheState) {
310    is(s_idle) {
311      when(io.roq.pendingst && pending(deqPtr) && allocated(deqPtr) && datavalid(deqPtr) && addrvalid(deqPtr)) {
312        uncacheState := s_req
313      }
314    }
315    is(s_req) {
316      when(io.uncache.req.fire()) {
317        uncacheState := s_resp
318      }
319    }
320    is(s_resp) {
321      when(io.uncache.resp.fire()) {
322        uncacheState := s_wb
323      }
324    }
325    is(s_wb) {
326      when (io.mmioStout.fire()) {
327        uncacheState := s_wait
328      }
329    }
330    is(s_wait) {
331      when(io.roq.commit) {
332        uncacheState := s_idle // ready for next mmio
333      }
334    }
335  }
336  io.uncache.req.valid := uncacheState === s_req
337
338  io.uncache.req.bits.cmd  := MemoryOpConstants.M_XWR
339  io.uncache.req.bits.addr := paddrModule.io.rdata(0) // data(deqPtr) -> rdata(0)
340  io.uncache.req.bits.data := dataModule.io.rdata(0).data
341  io.uncache.req.bits.mask := dataModule.io.rdata(0).mask
342
343  io.uncache.req.bits.id   := DontCare
344
345  when(io.uncache.req.fire()){
346    // mmio store should not be committed until uncache req is sent
347    pending(deqPtr) := false.B
348
349    XSDebug(
350      p"uncache req: pc ${Hexadecimal(uop(deqPtr).cf.pc)} " +
351      p"addr ${Hexadecimal(io.uncache.req.bits.addr)} " +
352      p"data ${Hexadecimal(io.uncache.req.bits.data)} " +
353      p"op ${Hexadecimal(io.uncache.req.bits.cmd)} " +
354      p"mask ${Hexadecimal(io.uncache.req.bits.mask)}\n"
355    )
356  }
357
358  // (3) response from uncache channel: mark as datavalid
359  io.uncache.resp.ready := true.B
360
361  // (4) writeback to ROB (and other units): mark as writebacked
362  io.mmioStout.valid := uncacheState === s_wb
363  io.mmioStout.bits.uop := uop(deqPtr)
364  io.mmioStout.bits.uop.sqIdx := deqPtrExt(0)
365  io.mmioStout.bits.data := dataModule.io.rdata(0).data // dataModule.io.rdata.read(deqPtr)
366  io.mmioStout.bits.redirectValid := false.B
367  io.mmioStout.bits.redirect := DontCare
368  io.mmioStout.bits.debug.isMMIO := true.B
369  io.mmioStout.bits.debug.paddr := DontCare
370  io.mmioStout.bits.debug.isPerfCnt := false.B
371  io.mmioStout.bits.fflags := DontCare
372  // Remove MMIO inst from store queue after MMIO request is being sent
373  // That inst will be traced by uncache state machine
374  when (io.mmioStout.fire()) {
375    allocated(deqPtr) := false.B
376  }
377
378  /**
379    * ROB commits store instructions (mark them as commited)
380    *
381    * (1) When store commits, mark it as commited.
382    * (2) They will not be cancelled and can be sent to lower level.
383    */
384  XSError(uncacheState === s_wait && commitCount > 1.U, "should only commit one instruction when there's an MMIO\n")
385  XSError(uncacheState =/= s_idle && uncacheState =/= s_wait && commitCount > 0.U,
386   "should not commit instruction when MMIO has not been finished\n")
387  for (i <- 0 until CommitWidth) {
388    when (commitCount > i.U && uncacheState === s_idle) { // MMIO inst is not in progress
389      commited(cmtPtrExt(i).value) := true.B
390    }
391  }
392  cmtPtrExt := cmtPtrExt.map(_ + commitCount)
393
394  // Commited stores will not be cancelled and can be sent to lower level.
395  // remove retired insts from sq, add retired store to sbuffer
396  for (i <- 0 until StorePipelineWidth) {
397    // We use RegNext to prepare data for sbuffer
398    val ptr = deqPtrExt(i).value
399    // if !sbuffer.fire(), read the same ptr
400    // if sbuffer.fire(), read next
401    io.sbuffer(i).valid := allocated(ptr) && commited(ptr) && !mmio(ptr)
402    // Note that store data/addr should both be valid after store's commit
403    assert(!io.sbuffer(i).valid || allvalid(ptr))
404    io.sbuffer(i).bits.cmd  := MemoryOpConstants.M_XWR
405    io.sbuffer(i).bits.addr := paddrModule.io.rdata(i)
406    io.sbuffer(i).bits.data := dataModule.io.rdata(i).data
407    io.sbuffer(i).bits.mask := dataModule.io.rdata(i).mask
408    io.sbuffer(i).bits.id   := DontCare
409
410    when (io.sbuffer(i).fire()) {
411      allocated(ptr) := false.B
412      XSDebug("sbuffer "+i+" fire: ptr %d\n", ptr)
413    }
414  }
415  when (io.sbuffer(1).fire()) {
416    assert(io.sbuffer(0).fire())
417  }
418  if (useFakeDCache) {
419    for (i <- 0 until StorePipelineWidth) {
420      val ptr = deqPtrExt(i).value
421      val fakeRAM = Module(new RAMHelper(64L * 1024 * 1024 * 1024))
422      fakeRAM.io.clk   := clock
423      fakeRAM.io.en    := allocated(ptr) && commited(ptr) && !mmio(ptr)
424      fakeRAM.io.rIdx  := 0.U
425      fakeRAM.io.wIdx  := (paddrModule.io.rdata(i) - "h80000000".U) >> 3
426      fakeRAM.io.wdata := dataModule.io.rdata(i).data
427      fakeRAM.io.wmask := MaskExpand(dataModule.io.rdata(i).mask)
428      fakeRAM.io.wen   := allocated(ptr) && commited(ptr) && !mmio(ptr)
429    }
430  }
431
432  if (!env.FPGAPlatform) {
433    for (i <- 0 until StorePipelineWidth) {
434      val storeCommit = io.sbuffer(i).fire()
435      val waddr = SignExt(io.sbuffer(i).bits.addr, 64)
436      val wdata = io.sbuffer(i).bits.data & MaskExpand(io.sbuffer(i).bits.mask)
437      val wmask = io.sbuffer(i).bits.mask
438
439      val difftest = Module(new DifftestStoreEvent)
440      difftest.io.clock       := clock
441      difftest.io.coreid      := hardId.U
442      difftest.io.index       := i.U
443      difftest.io.valid       := storeCommit
444      difftest.io.storeAddr   := waddr
445      difftest.io.storeData   := wdata
446      difftest.io.storeMask   := wmask
447    }
448  }
449
450  // Read vaddr for mem exception
451  io.exceptionAddr.vaddr := vaddrModule.io.rdata(0)
452
453  // misprediction recovery / exception redirect
454  // invalidate sq term using robIdx
455  val needCancel = Wire(Vec(StoreQueueSize, Bool()))
456  for (i <- 0 until StoreQueueSize) {
457    needCancel(i) := uop(i).roqIdx.needFlush(io.brqRedirect, io.flush) && allocated(i) && !commited(i)
458    when (needCancel(i)) {
459        allocated(i) := false.B
460    }
461  }
462
463  /**
464    * update pointers
465    */
466  val lastCycleRedirect = RegNext(io.brqRedirect.valid)
467  val lastCycleFlush = RegNext(io.flush)
468  val lastCycleCancelCount = PopCount(RegNext(needCancel))
469  // when io.brqRedirect.valid, we don't allow eneuque even though it may fire.
470  val enqNumber = Mux(io.enq.canAccept && io.enq.lqCanAccept && !(io.brqRedirect.valid || io.flush), PopCount(io.enq.req.map(_.valid)), 0.U)
471  when (lastCycleRedirect || lastCycleFlush) {
472    // we recover the pointers in the next cycle after redirect
473    enqPtrExt := VecInit(enqPtrExt.map(_ - lastCycleCancelCount))
474  }.otherwise {
475    enqPtrExt := VecInit(enqPtrExt.map(_ + enqNumber))
476  }
477
478  deqPtrExt := deqPtrExtNext
479
480  val dequeueCount = Mux(io.sbuffer(1).fire(), 2.U, Mux(io.sbuffer(0).fire() || io.mmioStout.fire(), 1.U, 0.U))
481  val validCount = distanceBetween(enqPtrExt(0), deqPtrExt(0))
482
483  allowEnqueue := validCount + enqNumber <= (StoreQueueSize - RenameWidth).U
484
485  // io.sqempty will be used by sbuffer
486  // We delay it for 1 cycle for better timing
487  // When sbuffer need to check if it is empty, the pipeline is blocked, which means delay io.sqempty
488  // for 1 cycle will also promise that sq is empty in that cycle
489  io.sqempty := RegNext(enqPtrExt(0).value === deqPtrExt(0).value && enqPtrExt(0).flag === deqPtrExt(0).flag)
490
491  // perf counter
492  QueuePerf(StoreQueueSize, validCount, !allowEnqueue)
493  io.sqFull := !allowEnqueue
494  XSPerfAccumulate("mmioCycle", uncacheState =/= s_idle) // lq is busy dealing with uncache req
495  XSPerfAccumulate("mmioCnt", io.uncache.req.fire())
496  XSPerfAccumulate("mmio_wb_success", io.mmioStout.fire())
497  XSPerfAccumulate("mmio_wb_blocked", io.mmioStout.valid && !io.mmioStout.ready)
498  XSPerfAccumulate("validEntryCnt", distanceBetween(enqPtrExt(0), deqPtrExt(0)))
499  XSPerfAccumulate("cmtEntryCnt", distanceBetween(cmtPtrExt(0), deqPtrExt(0)))
500  XSPerfAccumulate("nCmtEntryCnt", distanceBetween(enqPtrExt(0), cmtPtrExt(0)))
501
502  // debug info
503  XSDebug("enqPtrExt %d:%d deqPtrExt %d:%d\n", enqPtrExt(0).flag, enqPtr, deqPtrExt(0).flag, deqPtr)
504
505  def PrintFlag(flag: Bool, name: String): Unit = {
506    when(flag) {
507      XSDebug(false, true.B, name)
508    }.otherwise {
509      XSDebug(false, true.B, " ")
510    }
511  }
512
513  for (i <- 0 until StoreQueueSize) {
514    if (i % 4 == 0) XSDebug("")
515    XSDebug(false, true.B, "%x ", uop(i).cf.pc)
516    PrintFlag(allocated(i), "a")
517    PrintFlag(allocated(i) && addrvalid(i), "a")
518    PrintFlag(allocated(i) && datavalid(i), "d")
519    PrintFlag(allocated(i) && commited(i), "c")
520    PrintFlag(allocated(i) && pending(i), "p")
521    PrintFlag(allocated(i) && mmio(i), "m")
522    XSDebug(false, true.B, " ")
523    if (i % 4 == 3 || i == StoreQueueSize - 1) XSDebug(false, true.B, "\n")
524  }
525
526}
527