xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/LoadQueueUncache.scala (revision afa1262c29a131f306a9ca1f6e157f360d97e8c4)
1e9e6cd09SYanqin Li/***************************************************************************************
2e9e6cd09SYanqin Li * Copyright (c) 2024 Beijing Institute of Open Source Chip (BOSC)
3e9e6cd09SYanqin Li * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
4e9e6cd09SYanqin Li * Copyright (c) 2020-2021 Peng Cheng Laboratory
5e9e6cd09SYanqin Li *
6e9e6cd09SYanqin Li * XiangShan is licensed under Mulan PSL v2.
7e9e6cd09SYanqin Li * You can use this software according to the terms and conditions of the Mulan PSL v2.
8e9e6cd09SYanqin Li * You may obtain a copy of Mulan PSL v2 at:
9e9e6cd09SYanqin Li *          http://license.coscl.org.cn/MulanPSL2
10e9e6cd09SYanqin Li *
11e9e6cd09SYanqin Li * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12e9e6cd09SYanqin Li * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13e9e6cd09SYanqin Li * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14e9e6cd09SYanqin Li *
15e9e6cd09SYanqin Li * See the Mulan PSL v2 for more details.
16e9e6cd09SYanqin Li ***************************************************************************************/
17e9e6cd09SYanqin Lipackage xiangshan.mem
18e9e6cd09SYanqin Li
199e12e8edScz4eimport org.chipsalliance.cde.config._
20e9e6cd09SYanqin Liimport chisel3._
21e9e6cd09SYanqin Liimport chisel3.util._
22e9e6cd09SYanqin Liimport utils._
23e9e6cd09SYanqin Liimport utility._
249e12e8edScz4eimport xiangshan._
259e12e8edScz4eimport xiangshan.ExceptionNO._
269e12e8edScz4eimport xiangshan.backend.rob.{RobPtr, RobLsqIO}
27e9e6cd09SYanqin Liimport xiangshan.backend.Bundles
28e9e6cd09SYanqin Liimport xiangshan.backend.Bundles.{DynInst, MemExuOutput}
29e9e6cd09SYanqin Liimport xiangshan.backend.fu.FuConfig.LduCfg
309e12e8edScz4eimport xiangshan.mem.Bundles._
319e12e8edScz4eimport xiangshan.cache._
32e9e6cd09SYanqin Li
33e9e6cd09SYanqin Liclass UncacheEntry(entryIndex: Int)(implicit p: Parameters) extends XSModule
34e9e6cd09SYanqin Li  with HasCircularQueuePtrHelper
35e9e6cd09SYanqin Li  with HasLoadHelper
36e9e6cd09SYanqin Li{
37e9e6cd09SYanqin Li  val io = IO(new Bundle() {
38e9e6cd09SYanqin Li    /* control */
39e9e6cd09SYanqin Li    val redirect = Flipped(Valid(new Redirect))
40e9e6cd09SYanqin Li    // redirect flush
41e9e6cd09SYanqin Li    val flush = Output(Bool())
42e9e6cd09SYanqin Li    // mmio commit
43e9e6cd09SYanqin Li    val rob = Flipped(new RobLsqIO)
44e9e6cd09SYanqin Li    // mmio select
45e9e6cd09SYanqin Li    val mmioSelect = Output(Bool())
4674050fc0SYanqin Li    // slaveId
4774050fc0SYanqin Li    val slaveId = ValidIO(UInt(UncacheBufferIndexWidth.W))
48e9e6cd09SYanqin Li
49e9e6cd09SYanqin Li    /* transaction */
50e9e6cd09SYanqin Li    // from ldu
51e9e6cd09SYanqin Li    val req = Flipped(Valid(new LqWriteBundle))
52e9e6cd09SYanqin Li    // to ldu: mmio, data
53e9e6cd09SYanqin Li    val mmioOut = DecoupledIO(new MemExuOutput)
54e9e6cd09SYanqin Li    val mmioRawData = Output(new LoadDataFromLQBundle)
55e9e6cd09SYanqin Li    // to ldu: nc with data
56e9e6cd09SYanqin Li    val ncOut = DecoupledIO(new LsPipelineBundle)
57e9e6cd09SYanqin Li    // <=> uncache
58e9e6cd09SYanqin Li    val uncache = new UncacheWordIO
59e9e6cd09SYanqin Li    // exception generated by outer bus
60e9e6cd09SYanqin Li    val exception = Valid(new LqWriteBundle)
61e9e6cd09SYanqin Li  })
62e9e6cd09SYanqin Li
63e9e6cd09SYanqin Li  val req_valid = RegInit(false.B)
64e9e6cd09SYanqin Li  val req = Reg(new LqWriteBundle)
6574050fc0SYanqin Li  val slaveAccept = RegInit(false.B)
6674050fc0SYanqin Li  val slaveId = Reg(UInt(UncacheBufferIndexWidth.W))
67e9e6cd09SYanqin Li
68e9e6cd09SYanqin Li  val s_idle :: s_req :: s_resp :: s_wait :: Nil = Enum(4)
69e9e6cd09SYanqin Li  val uncacheState = RegInit(s_idle)
70e9e6cd09SYanqin Li  val uncacheData = Reg(io.uncache.resp.bits.data.cloneType)
71e9e6cd09SYanqin Li  val nderr = RegInit(false.B)
72e9e6cd09SYanqin Li
73e9e6cd09SYanqin Li  val writeback = Mux(req.nc, io.ncOut.fire, io.mmioOut.fire)
7474050fc0SYanqin Li  val slaveAck = req_valid && io.uncache.idResp.valid && io.uncache.idResp.bits.mid === entryIndex.U
75e9e6cd09SYanqin Li
76e9e6cd09SYanqin Li  /**
77e9e6cd09SYanqin Li    * Flush
78e9e6cd09SYanqin Li    *
79e9e6cd09SYanqin Li    * 1. direct flush during idle
80e9e6cd09SYanqin Li    * 2. otherwise delayed flush until receiving uncache resp
81e9e6cd09SYanqin Li    */
82e9e6cd09SYanqin Li  val needFlushReg = RegInit(false.B)
83e9e6cd09SYanqin Li  val needFlush = req_valid && req.uop.robIdx.needFlush(io.redirect)
84*afa1262cSYanqin Li  val flush = WireInit(false.B)
85e9e6cd09SYanqin Li  when(flush){
86e9e6cd09SYanqin Li    needFlushReg := false.B
87e9e6cd09SYanqin Li  }.elsewhen(needFlush){
88e9e6cd09SYanqin Li    needFlushReg := true.B
89e9e6cd09SYanqin Li  }
90e9e6cd09SYanqin Li
91e9e6cd09SYanqin Li  /* enter req */
92e9e6cd09SYanqin Li  when (flush) {
93e9e6cd09SYanqin Li    req_valid := false.B
9474050fc0SYanqin Li    slaveAccept := false.B
95e9e6cd09SYanqin Li  } .elsewhen (io.req.valid) {
96e9e6cd09SYanqin Li    req_valid := true.B
9774050fc0SYanqin Li    slaveAccept := false.B
98e9e6cd09SYanqin Li    req := io.req.bits
99e9e6cd09SYanqin Li    nderr := false.B
10074050fc0SYanqin Li  } .elsewhen(slaveAck) {
10174050fc0SYanqin Li    slaveAccept := true.B
10274050fc0SYanqin Li    slaveId := io.uncache.idResp.bits.sid
103e9e6cd09SYanqin Li  } .elsewhen (writeback) {
104e9e6cd09SYanqin Li    req_valid := false.B
10574050fc0SYanqin Li    slaveAccept := false.B
106e9e6cd09SYanqin Li  }
1078b33cd30Sklin02  XSError(!flush && io.req.valid && req_valid, p"LoadQueueUncache: You can not write an valid entry: $entryIndex")
108e9e6cd09SYanqin Li
109e9e6cd09SYanqin Li  /**
110e9e6cd09SYanqin Li    * Memory mapped IO / NC operations
111e9e6cd09SYanqin Li    *
112e9e6cd09SYanqin Li    * States:
113e9e6cd09SYanqin Li    * (1) s_idle: wait for mmio reaching ROB's head / nc req valid from loadunit
114e9e6cd09SYanqin Li    * (2) s_req: wait to be sent to uncache channel until req selected and uncache ready
115e9e6cd09SYanqin Li    * (3) s_resp: wait for response from uncache channel
116e9e6cd09SYanqin Li    * (4) s_wait: wait for loadunit to receive writeback req
117e9e6cd09SYanqin Li    */
118e9e6cd09SYanqin Li  val pendingld = GatedValidRegNext(io.rob.pendingMMIOld)
119e9e6cd09SYanqin Li  val pendingPtr = GatedRegNext(io.rob.pendingPtr)
120e9e6cd09SYanqin Li  val canSendReq = req_valid && !needFlush && Mux(
121e9e6cd09SYanqin Li    req.nc, true.B,
122e9e6cd09SYanqin Li    pendingld && req.uop.robIdx === pendingPtr
123e9e6cd09SYanqin Li  )
124e9e6cd09SYanqin Li  switch (uncacheState) {
125e9e6cd09SYanqin Li    is (s_idle) {
126*afa1262cSYanqin Li      when (needFlush) {
127*afa1262cSYanqin Li        uncacheState := s_idle
128*afa1262cSYanqin Li        flush := true.B
129*afa1262cSYanqin Li      }.elsewhen (canSendReq) {
130e9e6cd09SYanqin Li        uncacheState := s_req
131e9e6cd09SYanqin Li      }
132e9e6cd09SYanqin Li    }
133e9e6cd09SYanqin Li    is (s_req) {
134*afa1262cSYanqin Li      when(needFlush){
135*afa1262cSYanqin Li        uncacheState := s_idle
136*afa1262cSYanqin Li        flush := true.B
137*afa1262cSYanqin Li      }.elsewhen(io.uncache.req.fire) {
138e9e6cd09SYanqin Li        uncacheState := s_resp
139e9e6cd09SYanqin Li      }
140e9e6cd09SYanqin Li    }
141e9e6cd09SYanqin Li    is (s_resp) {
142e9e6cd09SYanqin Li      when (io.uncache.resp.fire) {
143*afa1262cSYanqin Li        when (needFlush || needFlushReg) {
144e9e6cd09SYanqin Li          uncacheState := s_idle
145*afa1262cSYanqin Li          flush := true.B
146e9e6cd09SYanqin Li        }.otherwise{
147e9e6cd09SYanqin Li          uncacheState := s_wait
148e9e6cd09SYanqin Li        }
149e9e6cd09SYanqin Li      }
150e9e6cd09SYanqin Li    }
151e9e6cd09SYanqin Li    is (s_wait) {
152*afa1262cSYanqin Li      when (needFlush || writeback) {
153e9e6cd09SYanqin Li        uncacheState := s_idle
154*afa1262cSYanqin Li        flush := true.B
155e9e6cd09SYanqin Li      }
156e9e6cd09SYanqin Li    }
157e9e6cd09SYanqin Li  }
158e9e6cd09SYanqin Li
159e9e6cd09SYanqin Li  /* control */
160e9e6cd09SYanqin Li  io.flush := flush
161e9e6cd09SYanqin Li  io.rob.mmio := DontCare
162e9e6cd09SYanqin Li  io.rob.uop := DontCare
163e9e6cd09SYanqin Li  io.mmioSelect := (uncacheState =/= s_idle) && req.mmio
16474050fc0SYanqin Li  io.slaveId.valid := slaveAccept
16574050fc0SYanqin Li  io.slaveId.bits := slaveId
166e9e6cd09SYanqin Li
167e9e6cd09SYanqin Li  /* uncahce req */
168*afa1262cSYanqin Li  io.uncache.req.valid     := uncacheState === s_req && !needFlush
169e9e6cd09SYanqin Li  io.uncache.req.bits      := DontCare
170e9e6cd09SYanqin Li  io.uncache.req.bits.cmd  := MemoryOpConstants.M_XRD
171e9e6cd09SYanqin Li  io.uncache.req.bits.data := DontCare
172e9e6cd09SYanqin Li  io.uncache.req.bits.addr := req.paddr
173e9e6cd09SYanqin Li  io.uncache.req.bits.vaddr:= req.vaddr
174e9e6cd09SYanqin Li  io.uncache.req.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
175e9e6cd09SYanqin Li  io.uncache.req.bits.id   := entryIndex.U
176e9e6cd09SYanqin Li  io.uncache.req.bits.instrtype := DontCare
177e9e6cd09SYanqin Li  io.uncache.req.bits.replayCarry := DontCare
178e9e6cd09SYanqin Li  io.uncache.req.bits.atomic := req.atomic
179e9e6cd09SYanqin Li  io.uncache.req.bits.nc := req.nc
180519244c7SYanqin Li  io.uncache.req.bits.memBackTypeMM := req.memBackTypeMM
181e9e6cd09SYanqin Li
182e9e6cd09SYanqin Li  io.uncache.resp.ready := true.B
183e9e6cd09SYanqin Li
184e9e6cd09SYanqin Li  /* uncahce resp */
185e9e6cd09SYanqin Li  when (io.uncache.resp.fire) {
186e9e6cd09SYanqin Li    uncacheData := io.uncache.resp.bits.data
187e9e6cd09SYanqin Li    nderr := io.uncache.resp.bits.nderr
188e9e6cd09SYanqin Li  }
189e9e6cd09SYanqin Li
190e9e6cd09SYanqin Li  /* uncahce writeback */
191e9e6cd09SYanqin Li  val selUop = req.uop
192e9e6cd09SYanqin Li  val func = selUop.fuOpType
193e9e6cd09SYanqin Li  val raddr = req.paddr
194e9e6cd09SYanqin Li  val rdataSel = LookupTree(raddr(2, 0), List(
195e9e6cd09SYanqin Li      "b000".U -> uncacheData(63,  0),
196e9e6cd09SYanqin Li      "b001".U -> uncacheData(63,  8),
197e9e6cd09SYanqin Li      "b010".U -> uncacheData(63, 16),
198e9e6cd09SYanqin Li      "b011".U -> uncacheData(63, 24),
199e9e6cd09SYanqin Li      "b100".U -> uncacheData(63, 32),
200e9e6cd09SYanqin Li      "b101".U -> uncacheData(63, 40),
201e9e6cd09SYanqin Li      "b110".U -> uncacheData(63, 48),
202e9e6cd09SYanqin Li      "b111".U -> uncacheData(63, 56)
203e9e6cd09SYanqin Li    ))
204e9e6cd09SYanqin Li  val rdataPartialLoad = rdataHelper(selUop, rdataSel)
205e9e6cd09SYanqin Li
206e9e6cd09SYanqin Li  io.mmioOut.valid := false.B
207e9e6cd09SYanqin Li  io.mmioOut.bits := DontCare
208e9e6cd09SYanqin Li  io.mmioRawData := DontCare
209e9e6cd09SYanqin Li  io.ncOut.valid := false.B
210e9e6cd09SYanqin Li  io.ncOut.bits := DontCare
211e9e6cd09SYanqin Li
212e9e6cd09SYanqin Li  when(req.nc){
213*afa1262cSYanqin Li    io.ncOut.valid := (uncacheState === s_wait) && !needFlush
214e9e6cd09SYanqin Li    io.ncOut.bits := DontCare
215e9e6cd09SYanqin Li    io.ncOut.bits.uop := selUop
216e9e6cd09SYanqin Li    io.ncOut.bits.uop.lqIdx := req.uop.lqIdx
217e9e6cd09SYanqin Li    io.ncOut.bits.uop.exceptionVec(loadAccessFault) := nderr
218e9e6cd09SYanqin Li    io.ncOut.bits.data := rdataPartialLoad
219e9e6cd09SYanqin Li    io.ncOut.bits.paddr := req.paddr
220e9e6cd09SYanqin Li    io.ncOut.bits.vaddr := req.vaddr
221e9e6cd09SYanqin Li    io.ncOut.bits.nc := true.B
222e9e6cd09SYanqin Li    io.ncOut.bits.mask := Mux(req.paddr(3), req.mask(15, 8), req.mask(7, 0))
223e9e6cd09SYanqin Li    io.ncOut.bits.schedIndex := req.schedIndex
224e9e6cd09SYanqin Li    io.ncOut.bits.isvec := req.isvec
225e9e6cd09SYanqin Li    io.ncOut.bits.is128bit := req.is128bit
226e9e6cd09SYanqin Li    io.ncOut.bits.vecActive := req.vecActive
227e9e6cd09SYanqin Li  }.otherwise{
228*afa1262cSYanqin Li    io.mmioOut.valid := (uncacheState === s_wait) && !needFlush
229e9e6cd09SYanqin Li    io.mmioOut.bits := DontCare
230e9e6cd09SYanqin Li    io.mmioOut.bits.uop := selUop
231e9e6cd09SYanqin Li    io.mmioOut.bits.uop.lqIdx := req.uop.lqIdx
232e9e6cd09SYanqin Li    io.mmioOut.bits.uop.exceptionVec(loadAccessFault) := nderr
233e9e6cd09SYanqin Li    io.mmioOut.bits.data := rdataPartialLoad
234e9e6cd09SYanqin Li    io.mmioOut.bits.debug.isMMIO := true.B
235e9e6cd09SYanqin Li    io.mmioOut.bits.debug.isNC := false.B
236e9e6cd09SYanqin Li    io.mmioOut.bits.debug.paddr := req.paddr
237e9e6cd09SYanqin Li    io.mmioOut.bits.debug.vaddr := req.vaddr
238e9e6cd09SYanqin Li    io.mmioRawData.lqData := uncacheData
239e9e6cd09SYanqin Li    io.mmioRawData.uop := req.uop
240e9e6cd09SYanqin Li    io.mmioRawData.addrOffset := req.paddr
241e9e6cd09SYanqin Li  }
242e9e6cd09SYanqin Li
243e9e6cd09SYanqin Li  io.exception.valid := writeback
244e9e6cd09SYanqin Li  io.exception.bits := req
245e9e6cd09SYanqin Li  io.exception.bits.uop.exceptionVec(loadAccessFault) := nderr
246e9e6cd09SYanqin Li
247e9e6cd09SYanqin Li  /* debug log */
2488b33cd30Sklin02  XSDebug(io.uncache.req.fire,
2498b33cd30Sklin02    "uncache req: pc %x addr %x data %x op %x mask %x\n",
250e9e6cd09SYanqin Li    req.uop.pc,
251e9e6cd09SYanqin Li    io.uncache.req.bits.addr,
252e9e6cd09SYanqin Li    io.uncache.req.bits.data,
253e9e6cd09SYanqin Li    io.uncache.req.bits.cmd,
254e9e6cd09SYanqin Li    io.uncache.req.bits.mask
255e9e6cd09SYanqin Li  )
2568b33cd30Sklin02  XSInfo(io.ncOut.fire,
2578b33cd30Sklin02    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
258e9e6cd09SYanqin Li    io.ncOut.bits.uop.robIdx.asUInt,
259e9e6cd09SYanqin Li    io.ncOut.bits.uop.lqIdx.asUInt,
260e9e6cd09SYanqin Li    io.ncOut.bits.uop.pc,
261e9e6cd09SYanqin Li    true.B
262e9e6cd09SYanqin Li  )
2638b33cd30Sklin02  XSInfo(io.mmioOut.fire,
2648b33cd30Sklin02    "int load miss write to cbd robidx %d lqidx %d pc 0x%x mmio %x\n",
265e9e6cd09SYanqin Li    io.mmioOut.bits.uop.robIdx.asUInt,
266e9e6cd09SYanqin Li    io.mmioOut.bits.uop.lqIdx.asUInt,
267e9e6cd09SYanqin Li    io.mmioOut.bits.uop.pc,
268e9e6cd09SYanqin Li    true.B
269e9e6cd09SYanqin Li  )
270e9e6cd09SYanqin Li
271e9e6cd09SYanqin Li}
272e9e6cd09SYanqin Li
273e9e6cd09SYanqin Liclass LoadQueueUncache(implicit p: Parameters) extends XSModule
274e9e6cd09SYanqin Li  with HasCircularQueuePtrHelper
275e9e6cd09SYanqin Li  with HasMemBlockParameters
276e9e6cd09SYanqin Li{
277e9e6cd09SYanqin Li  val io = IO(new Bundle() {
278e9e6cd09SYanqin Li    /* control */
279e9e6cd09SYanqin Li    val redirect = Flipped(Valid(new Redirect))
280e9e6cd09SYanqin Li    // mmio commit
281e9e6cd09SYanqin Li    val rob = Flipped(new RobLsqIO)
282e9e6cd09SYanqin Li
283e9e6cd09SYanqin Li    /* transaction */
284e9e6cd09SYanqin Li    // enqueue: from ldu s3
285e9e6cd09SYanqin Li    val req = Vec(LoadPipelineWidth, Flipped(Decoupled(new LqWriteBundle)))
286e9e6cd09SYanqin Li    // writeback: mmio to ldu s0, s3
287e9e6cd09SYanqin Li    val mmioOut = Vec(LoadPipelineWidth, DecoupledIO(new MemExuOutput))
288e9e6cd09SYanqin Li    val mmioRawData = Vec(LoadPipelineWidth, Output(new LoadDataFromLQBundle))
289e9e6cd09SYanqin Li    // writeback: nc to ldu s0--s3
290e9e6cd09SYanqin Li    val ncOut = Vec(LoadPipelineWidth, Decoupled(new LsPipelineBundle))
291e9e6cd09SYanqin Li    // <=>uncache
292e9e6cd09SYanqin Li    val uncache = new UncacheWordIO
293e9e6cd09SYanqin Li
294e9e6cd09SYanqin Li    /* except */
295e9e6cd09SYanqin Li    // rollback from frontend when buffer is full
296e9e6cd09SYanqin Li    val rollback = Output(Valid(new Redirect))
297e9e6cd09SYanqin Li    // exception generated by outer bus
298e9e6cd09SYanqin Li    val exception = Valid(new LqWriteBundle)
299e9e6cd09SYanqin Li  })
300e9e6cd09SYanqin Li
301e9e6cd09SYanqin Li  /******************************************************************
302e9e6cd09SYanqin Li   * Structure
303e9e6cd09SYanqin Li   ******************************************************************/
304e9e6cd09SYanqin Li  val entries = Seq.tabulate(LoadUncacheBufferSize)(i => Module(new UncacheEntry(i)))
305e9e6cd09SYanqin Li
306e9e6cd09SYanqin Li  val freeList = Module(new FreeList(
307e9e6cd09SYanqin Li    size = LoadUncacheBufferSize,
308e9e6cd09SYanqin Li    allocWidth = LoadPipelineWidth,
309e9e6cd09SYanqin Li    freeWidth = 4,
310e9e6cd09SYanqin Li    enablePreAlloc = true,
311e9e6cd09SYanqin Li    moduleName = "LoadQueueUncache freelist"
312e9e6cd09SYanqin Li  ))
313e9e6cd09SYanqin Li  freeList.io := DontCare
314e9e6cd09SYanqin Li
315e9e6cd09SYanqin Li  // set default IO
316e9e6cd09SYanqin Li  entries.foreach {
317e9e6cd09SYanqin Li    case (e) =>
318e9e6cd09SYanqin Li      e.io.req.valid := false.B
319e9e6cd09SYanqin Li      e.io.req.bits := DontCare
320e9e6cd09SYanqin Li      e.io.uncache.req.ready := false.B
32174050fc0SYanqin Li      e.io.uncache.idResp.valid := false.B
32274050fc0SYanqin Li      e.io.uncache.idResp.bits := DontCare
323e9e6cd09SYanqin Li      e.io.uncache.resp.valid := false.B
324e9e6cd09SYanqin Li      e.io.uncache.resp.bits := DontCare
325e9e6cd09SYanqin Li      e.io.ncOut.ready := false.B
326e9e6cd09SYanqin Li      e.io.mmioOut.ready := false.B
327e9e6cd09SYanqin Li  }
328e9e6cd09SYanqin Li  io.uncache.req.valid := false.B
329e9e6cd09SYanqin Li  io.uncache.req.bits := DontCare
330e9e6cd09SYanqin Li  io.uncache.resp.ready := false.B
331e9e6cd09SYanqin Li  for (w <- 0 until LoadPipelineWidth) {
332e9e6cd09SYanqin Li    io.mmioOut(w).valid := false.B
333e9e6cd09SYanqin Li    io.mmioOut(w).bits := DontCare
334e9e6cd09SYanqin Li    io.mmioRawData(w) := DontCare
335e9e6cd09SYanqin Li    io.ncOut(w).valid := false.B
336e9e6cd09SYanqin Li    io.ncOut(w).bits := DontCare
337e9e6cd09SYanqin Li  }
338e9e6cd09SYanqin Li
339e9e6cd09SYanqin Li
340e9e6cd09SYanqin Li  /******************************************************************
341e9e6cd09SYanqin Li   * Enqueue
342e9e6cd09SYanqin Li   *
343e9e6cd09SYanqin Li   * s1: hold
344e9e6cd09SYanqin Li   * s2: confirm enqueue and write entry
345e9e6cd09SYanqin Li   *    valid: no redirect, no exception, no replay, is mmio/nc
346e9e6cd09SYanqin Li   *    ready: freelist can allocate
347e9e6cd09SYanqin Li   ******************************************************************/
348e9e6cd09SYanqin Li
349a035c20dSYanqin Li  val s1_sortedVec = HwSort(VecInit(io.req.map { case x => DataWithPtr(x.valid, x.bits, x.bits.uop.robIdx) }))
350a035c20dSYanqin Li  val s1_req = VecInit(s1_sortedVec.map(_.bits))
351a035c20dSYanqin Li  val s1_valid = VecInit(s1_sortedVec.map(_.valid))
352e9e6cd09SYanqin Li  val s2_enqueue = Wire(Vec(LoadPipelineWidth, Bool()))
353e9e6cd09SYanqin Li  io.req.zipWithIndex.foreach{ case (r, i) =>
354a035c20dSYanqin Li    r.ready := true.B
355e9e6cd09SYanqin Li  }
356e9e6cd09SYanqin Li
357e9e6cd09SYanqin Li  // s2: enqueue
358e9e6cd09SYanqin Li  val s2_req = (0 until LoadPipelineWidth).map(i => {RegEnable(s1_req(i), s1_valid(i))})
359e9e6cd09SYanqin Li  val s2_valid = (0 until LoadPipelineWidth).map(i => {
360e9e6cd09SYanqin Li    RegNext(s1_valid(i)) &&
361e9e6cd09SYanqin Li    !s2_req(i).uop.robIdx.needFlush(RegNext(io.redirect)) &&
362e9e6cd09SYanqin Li    !s2_req(i).uop.robIdx.needFlush(io.redirect)
363e9e6cd09SYanqin Li  })
364e9e6cd09SYanqin Li  val s2_has_exception = s2_req.map(x => ExceptionNO.selectByFu(x.uop.exceptionVec, LduCfg).asUInt.orR)
365e9e6cd09SYanqin Li  val s2_need_replay = s2_req.map(_.rep_info.need_rep)
366e9e6cd09SYanqin Li
367e9e6cd09SYanqin Li  for (w <- 0 until LoadPipelineWidth) {
368e9e6cd09SYanqin Li    s2_enqueue(w) := s2_valid(w) && !s2_has_exception(w) && !s2_need_replay(w) && (s2_req(w).mmio || s2_req(w).nc)
369e9e6cd09SYanqin Li  }
370e9e6cd09SYanqin Li
371e9e6cd09SYanqin Li  val s2_enqValidVec = Wire(Vec(LoadPipelineWidth, Bool()))
372e9e6cd09SYanqin Li  val s2_enqIndexVec = Wire(Vec(LoadPipelineWidth, UInt()))
373e9e6cd09SYanqin Li
374e9e6cd09SYanqin Li  for (w <- 0 until LoadPipelineWidth) {
375e9e6cd09SYanqin Li    freeList.io.allocateReq(w) := true.B
376e9e6cd09SYanqin Li  }
377e9e6cd09SYanqin Li
378e9e6cd09SYanqin Li  // freeList real-allocate
379e9e6cd09SYanqin Li  for (w <- 0 until LoadPipelineWidth) {
380e9e6cd09SYanqin Li    freeList.io.doAllocate(w) := s2_enqValidVec(w)
381e9e6cd09SYanqin Li  }
382e9e6cd09SYanqin Li
383e9e6cd09SYanqin Li  for (w <- 0 until LoadPipelineWidth) {
384e9e6cd09SYanqin Li    val offset = PopCount(s2_enqueue.take(w))
38554b55f34SYanqin Li    s2_enqValidVec(w) := s2_enqueue(w) && freeList.io.canAllocate(offset)
386e9e6cd09SYanqin Li    s2_enqIndexVec(w) := freeList.io.allocateSlot(offset)
387e9e6cd09SYanqin Li  }
388e9e6cd09SYanqin Li
389e9e6cd09SYanqin Li
390e9e6cd09SYanqin Li  /******************************************************************
391e9e6cd09SYanqin Li   * Uncache Transaction
392e9e6cd09SYanqin Li   *
393e9e6cd09SYanqin Li   * 1. uncache req
394e9e6cd09SYanqin Li   * 2. uncache resp
395e9e6cd09SYanqin Li   * 3. writeback
396e9e6cd09SYanqin Li   ******************************************************************/
397e9e6cd09SYanqin Li  private val NC_WB_MOD = NCWBPorts.length
398e9e6cd09SYanqin Li
399e9e6cd09SYanqin Li  val uncacheReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
400e9e6cd09SYanqin Li  val mmioSelect = entries.map(e => e.io.mmioSelect).reduce(_ || _)
401e9e6cd09SYanqin Li  val mmioReq = Wire(DecoupledIO(io.uncache.req.bits.cloneType))
402e9e6cd09SYanqin Li  // TODO lyq: It's best to choose in robIdx order / the order in which they enter
403e9e6cd09SYanqin Li  val ncReqArb = Module(new RRArbiterInit(io.uncache.req.bits.cloneType, LoadUncacheBufferSize))
404e9e6cd09SYanqin Li
405e9e6cd09SYanqin Li  val mmioOut = Wire(DecoupledIO(io.mmioOut(0).bits.cloneType))
406e9e6cd09SYanqin Li  val mmioRawData = Wire(io.mmioRawData(0).cloneType)
407e9e6cd09SYanqin Li  val ncOut = Wire(chiselTypeOf(io.ncOut))
408e9e6cd09SYanqin Li  val ncOutValidVec = VecInit(entries.map(e => e.io.ncOut.valid))
409e9e6cd09SYanqin Li  val ncOutValidVecRem = SubVec.getMaskRem(ncOutValidVec, NC_WB_MOD)
410e9e6cd09SYanqin Li
411e9e6cd09SYanqin Li  // init
412e9e6cd09SYanqin Li  uncacheReq.valid := false.B
413e9e6cd09SYanqin Li  uncacheReq.bits  := DontCare
414e9e6cd09SYanqin Li  mmioReq.valid := false.B
415e9e6cd09SYanqin Li  mmioReq.bits := DontCare
416e9e6cd09SYanqin Li  mmioOut.valid := false.B
417e9e6cd09SYanqin Li  mmioOut.bits := DontCare
418e9e6cd09SYanqin Li  mmioRawData := DontCare
419e9e6cd09SYanqin Li  for (i <- 0 until LoadUncacheBufferSize) {
420e9e6cd09SYanqin Li    ncReqArb.io.in(i).valid := false.B
421e9e6cd09SYanqin Li    ncReqArb.io.in(i).bits := DontCare
422e9e6cd09SYanqin Li  }
423e9e6cd09SYanqin Li  for (i <- 0 until LoadPipelineWidth) {
424e9e6cd09SYanqin Li    ncOut(i).valid := false.B
425e9e6cd09SYanqin Li    ncOut(i).bits := DontCare
426e9e6cd09SYanqin Li  }
427e9e6cd09SYanqin Li
428e9e6cd09SYanqin Li  entries.zipWithIndex.foreach {
429e9e6cd09SYanqin Li    case (e, i) =>
430e9e6cd09SYanqin Li      // enqueue
431e9e6cd09SYanqin Li      for (w <- 0 until LoadPipelineWidth) {
432e9e6cd09SYanqin Li        when (s2_enqValidVec(w) && (i.U === s2_enqIndexVec(w))) {
433e9e6cd09SYanqin Li          e.io.req.valid := true.B
434e9e6cd09SYanqin Li          e.io.req.bits := s2_req(w)
435e9e6cd09SYanqin Li        }
436e9e6cd09SYanqin Li      }
437e9e6cd09SYanqin Li
438e9e6cd09SYanqin Li      // control
439e9e6cd09SYanqin Li      e.io.redirect <> io.redirect
440e9e6cd09SYanqin Li      e.io.rob <> io.rob
441e9e6cd09SYanqin Li
442e9e6cd09SYanqin Li      // uncache req, writeback
443e9e6cd09SYanqin Li      when (e.io.mmioSelect) {
444e9e6cd09SYanqin Li        mmioReq.valid := e.io.uncache.req.valid
445e9e6cd09SYanqin Li        mmioReq.bits := e.io.uncache.req.bits
446e9e6cd09SYanqin Li        e.io.uncache.req.ready := mmioReq.ready
447e9e6cd09SYanqin Li
448e9e6cd09SYanqin Li        e.io.mmioOut.ready := mmioOut.ready
449e9e6cd09SYanqin Li        mmioOut.valid := e.io.mmioOut.valid
450e9e6cd09SYanqin Li        mmioOut.bits := e.io.mmioOut.bits
451e9e6cd09SYanqin Li        mmioRawData := e.io.mmioRawData
452e9e6cd09SYanqin Li
453e9e6cd09SYanqin Li      }.otherwise{
454e9e6cd09SYanqin Li        ncReqArb.io.in(i).valid := e.io.uncache.req.valid
455e9e6cd09SYanqin Li        ncReqArb.io.in(i).bits := e.io.uncache.req.bits
456e9e6cd09SYanqin Li        e.io.uncache.req.ready := ncReqArb.io.in(i).ready
457e9e6cd09SYanqin Li
458e9e6cd09SYanqin Li        (0 until NC_WB_MOD).map { w =>
459e9e6cd09SYanqin Li          val (idx, ncOutValid) = PriorityEncoderWithFlag(ncOutValidVecRem(w))
460e9e6cd09SYanqin Li          val port = NCWBPorts(w)
461e9e6cd09SYanqin Li          when((i.U === idx) && ncOutValid) {
462e9e6cd09SYanqin Li            ncOut(port).valid := ncOutValid
463e9e6cd09SYanqin Li            ncOut(port).bits := e.io.ncOut.bits
464e9e6cd09SYanqin Li            e.io.ncOut.ready := ncOut(port).ready
465e9e6cd09SYanqin Li          }
466e9e6cd09SYanqin Li        }
467e9e6cd09SYanqin Li
468e9e6cd09SYanqin Li      }
469e9e6cd09SYanqin Li
47074050fc0SYanqin Li      // uncache idResp
47174050fc0SYanqin Li      when(i.U === io.uncache.idResp.bits.mid) {
47274050fc0SYanqin Li        e.io.uncache.idResp <> io.uncache.idResp
47374050fc0SYanqin Li      }
47474050fc0SYanqin Li
475e9e6cd09SYanqin Li      // uncache resp
47674050fc0SYanqin Li      when (e.io.slaveId.valid && e.io.slaveId.bits === io.uncache.resp.bits.id) {
477e9e6cd09SYanqin Li        e.io.uncache.resp <> io.uncache.resp
478e9e6cd09SYanqin Li      }
479e9e6cd09SYanqin Li
480e9e6cd09SYanqin Li  }
481e9e6cd09SYanqin Li
482e9e6cd09SYanqin Li  mmioReq.ready := false.B
483e9e6cd09SYanqin Li  ncReqArb.io.out.ready := false.B
484e9e6cd09SYanqin Li  when(mmioSelect){
485e9e6cd09SYanqin Li    uncacheReq <> mmioReq
486e9e6cd09SYanqin Li  }.otherwise{
487e9e6cd09SYanqin Li    uncacheReq <> ncReqArb.io.out
488e9e6cd09SYanqin Li  }
489e9e6cd09SYanqin Li
490e9e6cd09SYanqin Li  // uncache Request
491e9e6cd09SYanqin Li  AddPipelineReg(uncacheReq, io.uncache.req, false.B)
492e9e6cd09SYanqin Li
493e9e6cd09SYanqin Li  // uncache Writeback
494e9e6cd09SYanqin Li  AddPipelineReg(mmioOut, io.mmioOut(UncacheWBPort), false.B)
495e9e6cd09SYanqin Li  io.mmioRawData(UncacheWBPort) := RegEnable(mmioRawData, mmioOut.fire)
496e9e6cd09SYanqin Li
497e9e6cd09SYanqin Li  (0 until LoadPipelineWidth).foreach { i => AddPipelineReg(ncOut(i), io.ncOut(i), false.B) }
498e9e6cd09SYanqin Li
499e9e6cd09SYanqin Li  // uncache exception
500e9e6cd09SYanqin Li  io.exception.valid := Cat(entries.map(_.io.exception.valid)).orR
501e9e6cd09SYanqin Li  io.exception.bits := ParallelPriorityMux(entries.map(e =>
502e9e6cd09SYanqin Li    (e.io.exception.valid, e.io.exception.bits)
503e9e6cd09SYanqin Li  ))
504e9e6cd09SYanqin Li
505e9e6cd09SYanqin Li  // rob
506e9e6cd09SYanqin Li  for (i <- 0 until LoadPipelineWidth) {
507e9e6cd09SYanqin Li    io.rob.mmio(i) := RegNext(s1_valid(i) && s1_req(i).mmio)
508e9e6cd09SYanqin Li    io.rob.uop(i) := RegEnable(s1_req(i).uop, s1_valid(i))
509e9e6cd09SYanqin Li  }
510e9e6cd09SYanqin Li
511e9e6cd09SYanqin Li
512e9e6cd09SYanqin Li  /******************************************************************
513e9e6cd09SYanqin Li   * Deallocate
514e9e6cd09SYanqin Li   ******************************************************************/
515e9e6cd09SYanqin Li  // UncacheBuffer deallocate
516e9e6cd09SYanqin Li  val freeMaskVec = Wire(Vec(LoadUncacheBufferSize, Bool()))
517e9e6cd09SYanqin Li
518e9e6cd09SYanqin Li  // init
519e9e6cd09SYanqin Li  freeMaskVec.map(e => e := false.B)
520e9e6cd09SYanqin Li
521e9e6cd09SYanqin Li  // dealloc logic
522e9e6cd09SYanqin Li  entries.zipWithIndex.foreach {
523e9e6cd09SYanqin Li    case (e, i) =>
524e9e6cd09SYanqin Li      when ((e.io.mmioSelect && e.io.mmioOut.fire) || e.io.ncOut.fire || e.io.flush) {
525e9e6cd09SYanqin Li        freeMaskVec(i) := true.B
526e9e6cd09SYanqin Li      }
527e9e6cd09SYanqin Li  }
528e9e6cd09SYanqin Li
529e9e6cd09SYanqin Li  freeList.io.free := freeMaskVec.asUInt
530e9e6cd09SYanqin Li
531e9e6cd09SYanqin Li
532e9e6cd09SYanqin Li  /******************************************************************
533e9e6cd09SYanqin Li   * Uncache rollback detection
534e9e6cd09SYanqin Li   *
535e9e6cd09SYanqin Li   * When uncache loads enqueue, it searches uncache loads, They can not enqueue and need re-execution.
536e9e6cd09SYanqin Li   *
537e9e6cd09SYanqin Li   * Cycle 0: uncache enqueue.
538e9e6cd09SYanqin Li   * Cycle 1: Select oldest uncache loads.
539e9e6cd09SYanqin Li   * Cycle 2: Redirect Fire.
540e9e6cd09SYanqin Li   *   Choose the oldest load from LoadPipelineWidth oldest loads.
541e9e6cd09SYanqin Li   *   Prepare redirect request according to the detected rejection.
542e9e6cd09SYanqin Li   *   Fire redirect request (if valid)
543e9e6cd09SYanqin Li   *
544e9e6cd09SYanqin Li   *               Load_S3  .... Load_S3
545e9e6cd09SYanqin Li   * stage 0:        lq            lq
546e9e6cd09SYanqin Li   *                 |             | (can not enqueue)
547e9e6cd09SYanqin Li   * stage 1:        lq            lq
548e9e6cd09SYanqin Li   *                 |             |
549e9e6cd09SYanqin Li   *                 ---------------
550e9e6cd09SYanqin Li   *                        |
551e9e6cd09SYanqin Li   * stage 2:               lq
552e9e6cd09SYanqin Li   *                        |
553e9e6cd09SYanqin Li   *                     rollback req
554e9e6cd09SYanqin Li   *
555e9e6cd09SYanqin Li   ******************************************************************/
556e9e6cd09SYanqin Li  def selectOldestRedirect(xs: Seq[Valid[Redirect]]): Vec[Bool] = {
557e9e6cd09SYanqin Li    val compareVec = (0 until xs.length).map(i => (0 until i).map(j => isAfter(xs(j).bits.robIdx, xs(i).bits.robIdx)))
558e9e6cd09SYanqin Li    val resultOnehot = VecInit((0 until xs.length).map(i => Cat((0 until xs.length).map(j =>
559e9e6cd09SYanqin Li      (if (j < i) !xs(j).valid || compareVec(i)(j)
560e9e6cd09SYanqin Li      else if (j == i) xs(i).valid
561e9e6cd09SYanqin Li      else !xs(j).valid || !compareVec(j)(i))
562e9e6cd09SYanqin Li    )).andR))
563e9e6cd09SYanqin Li    resultOnehot
564e9e6cd09SYanqin Li  }
565e9e6cd09SYanqin Li  val reqNeedCheck = VecInit((0 until LoadPipelineWidth).map(w =>
566e9e6cd09SYanqin Li    s2_enqueue(w) && !s2_enqValidVec(w)
567e9e6cd09SYanqin Li  ))
568e9e6cd09SYanqin Li  val reqSelUops = VecInit(s2_req.map(_.uop))
569e9e6cd09SYanqin Li  val allRedirect = (0 until LoadPipelineWidth).map(i => {
570e9e6cd09SYanqin Li    val redirect = Wire(Valid(new Redirect))
571e9e6cd09SYanqin Li    redirect.valid := reqNeedCheck(i)
572e9e6cd09SYanqin Li    redirect.bits             := DontCare
573e9e6cd09SYanqin Li    redirect.bits.isRVC       := reqSelUops(i).preDecodeInfo.isRVC
574e9e6cd09SYanqin Li    redirect.bits.robIdx      := reqSelUops(i).robIdx
575e9e6cd09SYanqin Li    redirect.bits.ftqIdx      := reqSelUops(i).ftqPtr
576e9e6cd09SYanqin Li    redirect.bits.ftqOffset   := reqSelUops(i).ftqOffset
577e9e6cd09SYanqin Li    redirect.bits.level       := RedirectLevel.flush
578e9e6cd09SYanqin Li    redirect.bits.cfiUpdate.target := reqSelUops(i).pc // TODO: check if need pc
579e9e6cd09SYanqin Li    redirect.bits.debug_runahead_checkpoint_id := reqSelUops(i).debugInfo.runahead_checkpoint_id
580e9e6cd09SYanqin Li    redirect
581e9e6cd09SYanqin Li  })
582e9e6cd09SYanqin Li  val oldestOneHot = selectOldestRedirect(allRedirect)
583e9e6cd09SYanqin Li  val oldestRedirect = Mux1H(oldestOneHot, allRedirect)
584e9e6cd09SYanqin Li  val lastCycleRedirect = Wire(Valid(new Redirect))
585e9e6cd09SYanqin Li  lastCycleRedirect.valid := RegNext(io.redirect.valid)
586e9e6cd09SYanqin Li  lastCycleRedirect.bits := RegEnable(io.redirect.bits, io.redirect.valid)
587e9e6cd09SYanqin Li  val lastLastCycleRedirect = Wire(Valid(new Redirect))
588e9e6cd09SYanqin Li  lastLastCycleRedirect.valid := RegNext(lastCycleRedirect.valid)
589e9e6cd09SYanqin Li  lastLastCycleRedirect.bits := RegEnable(lastCycleRedirect.bits, lastCycleRedirect.valid)
590e9e6cd09SYanqin Li  io.rollback.valid := GatedValidRegNext(oldestRedirect.valid &&
591e9e6cd09SYanqin Li                      !oldestRedirect.bits.robIdx.needFlush(io.redirect) &&
592e9e6cd09SYanqin Li                      !oldestRedirect.bits.robIdx.needFlush(lastCycleRedirect) &&
593e9e6cd09SYanqin Li                      !oldestRedirect.bits.robIdx.needFlush(lastLastCycleRedirect))
594e9e6cd09SYanqin Li  io.rollback.bits := RegEnable(oldestRedirect.bits, oldestRedirect.valid)
595e9e6cd09SYanqin Li
596e9e6cd09SYanqin Li
597e9e6cd09SYanqin Li  /******************************************************************
598e9e6cd09SYanqin Li   * Perf Counter
599e9e6cd09SYanqin Li   ******************************************************************/
600e9e6cd09SYanqin Li  val validCount = freeList.io.validCount
601e9e6cd09SYanqin Li  val allowEnqueue = !freeList.io.empty
602e9e6cd09SYanqin Li  QueuePerf(LoadUncacheBufferSize, validCount, !allowEnqueue)
603e9e6cd09SYanqin Li
604e9e6cd09SYanqin Li  XSPerfAccumulate("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc)
605e9e6cd09SYanqin Li  XSPerfAccumulate("mmio_writeback_success", io.mmioOut(0).fire)
606e9e6cd09SYanqin Li  XSPerfAccumulate("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready)
607e9e6cd09SYanqin Li  XSPerfAccumulate("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc)
608e9e6cd09SYanqin Li  XSPerfAccumulate("nc_writeback_success", io.ncOut(0).fire)
609e9e6cd09SYanqin Li  XSPerfAccumulate("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready)
610e9e6cd09SYanqin Li  XSPerfAccumulate("uncache_full_rollback", io.rollback.valid)
611e9e6cd09SYanqin Li
612e9e6cd09SYanqin Li  val perfEvents: Seq[(String, UInt)] = Seq(
613e9e6cd09SYanqin Li    ("mmio_uncache_req", io.uncache.req.fire && !io.uncache.req.bits.nc),
614e9e6cd09SYanqin Li    ("mmio_writeback_success", io.mmioOut(0).fire),
615e9e6cd09SYanqin Li    ("mmio_writeback_blocked", io.mmioOut(0).valid && !io.mmioOut(0).ready),
616e9e6cd09SYanqin Li    ("nc_uncache_req", io.uncache.req.fire && io.uncache.req.bits.nc),
617e9e6cd09SYanqin Li    ("nc_writeback_success", io.ncOut(0).fire),
618e9e6cd09SYanqin Li    ("nc_writeback_blocked", io.ncOut(0).valid && !io.ncOut(0).ready),
619e9e6cd09SYanqin Li    ("uncache_full_rollback", io.rollback.valid)
620e9e6cd09SYanqin Li  )
621e9e6cd09SYanqin Li  // end
622e9e6cd09SYanqin Li}
623