xref: /XiangShan/src/main/scala/xiangshan/backend/issue/IssueQueue.scala (revision 95bfe4c03ef37cfa7866474159f6afb8e3bcc3cc)
1package xiangshan.backend.issue
2
3import chisel3.{util, _}
4import chisel3.util._
5import utils.{ParallelMux, ParallelOR, PriorityEncoderWithFlag, XSDebug, XSInfo}
6import xiangshan._
7import xiangshan.backend.exu.{Exu, ExuConfig}
8import xiangshan.backend.regfile.RfReadPort
9
10class IssueQueue
11(
12  val exuCfg: ExuConfig,
13  val wakeupCnt: Int,
14  val bypassCnt: Int = 0
15) extends XSModule with HasIQConst {
16  val io = IO(new Bundle() {
17    val redirect = Flipped(ValidIO(new Redirect))
18    val enq = Flipped(DecoupledIO(new MicroOp))
19    val readIntRf = Vec(exuCfg.intSrcCnt, Flipped(new RfReadPort))
20    val readFpRf = Vec(exuCfg.fpSrcCnt, Flipped(new RfReadPort))
21    val deq = DecoupledIO(new ExuInput)
22    val wakeUpPorts = Vec(wakeupCnt, Flipped(ValidIO(new ExuOutput)))
23    val bypassUops = Vec(bypassCnt, Flipped(ValidIO(new MicroOp)))
24    val bypassData = Vec(bypassCnt, Flipped(ValidIO(new ExuOutput)))
25    val numExist = Output(UInt(iqIdxWidth.W))
26    // tlb hit, inst can deq
27    val tlbFeedback = Flipped(ValidIO(new TlbFeedback))
28  })
29
30  def qsize: Int = IssQueSize
31  def idxWidth = log2Up(qsize)
32  def replayDelay = 16
33
34  require(isPow2(qsize))
35
36  val tlbHit = io.tlbFeedback.valid && io.tlbFeedback.bits.hit
37  val tlbMiss = io.tlbFeedback.valid && !io.tlbFeedback.bits.hit
38
39  XSDebug(io.tlbFeedback.valid,
40    "tlb feedback: hit: %d roqIdx: %d\n",
41    io.tlbFeedback.bits.hit,
42    io.tlbFeedback.bits.roqIdx
43  )
44  /*
45      invalid --[enq]--> valid --[deq]--> wait --[tlbHit]--> invalid
46                                          wait --[replay]--> replay --[cnt]--> valid
47   */
48  val s_invalid :: s_valid :: s_wait :: s_replay :: Nil = Enum(4)
49
50  val idxQueue = RegInit(VecInit((0 until qsize).map(_.U(idxWidth.W))))
51  val stateQueue = RegInit(VecInit(Seq.fill(qsize)(s_invalid)))
52
53  val readyVec = Wire(Vec(qsize, Bool()))
54  val uopQueue = Reg(Vec(qsize, new MicroOp))
55  val cntQueue = Reg(Vec(qsize, UInt(log2Up(replayDelay).W)))
56
57  val tailPtr = RegInit(0.U((idxWidth+1).W))
58
59  // real deq
60
61  /*
62    example: realDeqIdx = 2       |  realDeqIdx=0
63             moveMask = 11111100  |  moveMask=11111111
64 */
65
66  val (firstBubble, findBubble) = PriorityEncoderWithFlag(stateQueue.map(_ === s_invalid))
67  val realDeqIdx = firstBubble
68  val realDeqValid = (firstBubble < tailPtr) && findBubble
69  val moveMask = {
70    (Fill(qsize, 1.U(1.W)) << realDeqIdx)(qsize-1, 0)
71  } & Fill(qsize, realDeqValid)
72
73  for(i <- 0 until qsize-1){
74    when(moveMask(i)){
75      idxQueue(i) := idxQueue(i+1)
76      stateQueue(i) := stateQueue(i+1)
77    }
78  }
79  when(realDeqValid){
80    idxQueue.last := idxQueue(realDeqIdx)
81    stateQueue.last := s_invalid
82  }
83
84
85  // wake up
86  def getSrcSeq(uop: MicroOp): Seq[UInt] = Seq(uop.psrc1, uop.psrc2, uop.psrc3)
87  def getSrcTypeSeq(uop: MicroOp): Seq[UInt] = Seq(
88    uop.ctrl.src1Type, uop.ctrl.src2Type, uop.ctrl.src3Type
89  )
90  def getSrcStateSeq(uop: MicroOp): Seq[UInt] = Seq(
91    uop.src1State, uop.src2State, uop.src3State
92  )
93
94  def writeBackHit(src: UInt, srcType: UInt, wbUop: (Bool, MicroOp)): Bool = {
95    val (v, uop) = wbUop
96    val isSameType =
97      (SrcType.isReg(srcType) && uop.ctrl.rfWen && src =/= 0.U) || (SrcType.isFp(srcType) && uop.ctrl.fpWen)
98
99    v && isSameType && (src===uop.pdest)
100  }
101
102  //TODO: opt this, do bypass select in 'select' stage not 'issue' stage
103  val bypassData = RegNext(io.bypassData)
104  def doBypass(src: UInt, srcType: UInt): (Bool, UInt) = {
105    val hitVec = bypassData.map(p => (p.valid, p.bits.uop)).
106      map(wbUop => writeBackHit(src, srcType, wbUop))
107    val data = ParallelMux(hitVec.zip(bypassData.map(_.bits.data)))
108    (ParallelOR(hitVec).asBool(), data)
109  }
110
111  def wakeUp(uop: MicroOp): MicroOp = {
112    def getNewSrcState(i: Int): UInt = {
113      val src = getSrcSeq(uop)(i)
114      val srcType = getSrcTypeSeq(uop)(i)
115      val srcState = getSrcStateSeq(uop)(i)
116      val hitVec = (
117        io.wakeUpPorts.map(w => (w.valid, w.bits.uop)) ++
118        io.bypassUops.map(p => (p.valid, p.bits))
119        ).map(wbUop => writeBackHit(src, srcType, wbUop))
120      val hit = ParallelOR(hitVec).asBool()
121      Mux(hit, SrcState.rdy, srcState)
122    }
123    val new_uop = WireInit(uop)
124    new_uop.src1State := getNewSrcState(0)
125    if(exuCfg==Exu.stExeUnitCfg) new_uop.src2State := getNewSrcState(1)
126    new_uop
127  }
128
129  def uopIsRdy(uop: MicroOp): Bool = {
130    def srcIsRdy(srcType: UInt, srcState: UInt): Bool = {
131      SrcType.isPcImm(srcType) || srcState===SrcState.rdy
132    }
133    exuCfg match {
134      case Exu.ldExeUnitCfg =>
135        srcIsRdy(uop.ctrl.src1Type, uop.src1State)
136      case Exu.stExeUnitCfg =>
137        srcIsRdy(uop.ctrl.src1Type, uop.src1State) && srcIsRdy(uop.ctrl.src2Type, uop.src2State)
138    }
139  }
140
141
142  // 1. wake up
143  for(i <- 0 until qsize){
144    uopQueue(i) := wakeUp(uopQueue(i))
145  }
146
147  // 2. select
148  for(i <- 0 until qsize){
149    readyVec(i) := uopIsRdy(uopQueue(i))
150  }
151
152  val selectedIdxRegOH = Wire(UInt(qsize.W))
153  val selectMask = WireInit(VecInit(
154    (0 until qsize).map(i =>
155      (stateQueue(i)===s_valid) && readyVec(idxQueue(i)) && !(selectedIdxRegOH(i) && io.deq.fire())
156    )
157  ))
158  val (selectedIdxWire, sel) = PriorityEncoderWithFlag(selectMask)
159  val selReg = RegNext(sel)
160  val selectedIdxReg = RegNext(selectedIdxWire - moveMask(selectedIdxWire))
161  selectedIdxRegOH := UIntToOH(selectedIdxReg)
162  XSDebug(
163    p"selMaskWire:${Binary(selectMask.asUInt())} selected:$selectedIdxWire" +
164      p" moveMask:${Binary(moveMask)} selectedIdxReg:$selectedIdxReg\n"
165  )
166
167
168  // read regfile
169  val selectedUop = uopQueue(idxQueue(selectedIdxWire))
170
171  exuCfg match {
172    case Exu.ldExeUnitCfg =>
173      io.readIntRf(0).addr := selectedUop.psrc1 // base
174      XSDebug(p"src1 read addr: ${io.readIntRf(0).addr}\n")
175    case Exu.stExeUnitCfg =>
176      io.readIntRf(0).addr := selectedUop.psrc1 // base
177      io.readIntRf(1).addr := selectedUop.psrc2 // store data (int)
178      io.readFpRf(0).addr := selectedUop.psrc2  // store data (fp)
179      XSDebug(
180        p"src1 read addr: ${io.readIntRf(0).addr} src2 read addr: ${io.readIntRf(1).addr}\n"
181      )
182    case _ =>
183      require(requirement = false, "Error: IssueQueue only support ldu and stu!")
184  }
185
186  // (fake) deq to Load/Store unit
187  io.deq.valid := (stateQueue(selectedIdxReg)===s_valid) && selReg
188  io.deq.bits.uop := uopQueue(idxQueue(selectedIdxReg))
189
190  val src1Bypass = doBypass(io.deq.bits.uop.psrc1, io.deq.bits.uop.ctrl.src1Type)
191  io.deq.bits.src1 := Mux(src1Bypass._1, src1Bypass._2, io.readIntRf(0).data)
192  if(exuCfg == Exu.stExeUnitCfg){
193    val src2Bypass = doBypass(io.deq.bits.uop.psrc2, io.deq.bits.uop.ctrl.src2Type)
194    io.deq.bits.src2 := Mux(src2Bypass._1,
195      src2Bypass._2,
196      Mux(SrcType.isReg(io.deq.bits.uop.ctrl.src2Type),
197        io.readIntRf(1).data,
198        io.readFpRf(0).data
199      )
200    )
201  } else {
202    io.deq.bits.src2 := DontCare
203  }
204  io.deq.bits.src3 := DontCare
205
206  when(io.deq.fire()){
207    stateQueue(selectedIdxReg - moveMask(selectedIdxReg)) := s_wait
208    assert(stateQueue(selectedIdxReg) === s_valid, "Dequeue a invalid entry to lsu!")
209  }
210
211//  assert(!(tailPtr===0.U && tlbHit), "Error: queue is empty but tlbHit is true!")
212
213  val tailAfterRealDeq = tailPtr - moveMask(tailPtr.tail(1))
214  val isFull = tailAfterRealDeq.head(1).asBool() // tailPtr===qsize.U
215
216  // enq
217  io.enq.ready := !isFull && !io.redirect.valid
218  when(io.enq.fire()){
219    stateQueue(tailAfterRealDeq.tail(1)) := s_valid
220    val uopQIdx = idxQueue(tailPtr.tail(1))
221    val new_uop = wakeUp(io.enq.bits)
222    uopQueue(uopQIdx) := new_uop
223  }
224
225  tailPtr := tailAfterRealDeq + io.enq.fire()
226
227  XSDebug(
228    realDeqValid,
229    p"realDeqIdx:$realDeqIdx\n"
230  )
231
232  XSDebug("State Dump: ")
233  stateQueue.reverse.foreach(s =>{
234    XSDebug(false, s===s_invalid, "-")
235    XSDebug(false, s===s_valid, "v")
236    XSDebug(false, s===s_wait, "w")
237    XSDebug(false, s===s_replay, "p")
238  })
239  XSDebug(false, true.B, "\n")
240
241  XSDebug("State Dump: ")
242  idxQueue.reverse.foreach(id =>{
243    XSDebug(false, true.B, p"$id")
244  })
245  XSDebug(false, true.B, "\n")
246
247  XSDebug("State Dump: ")
248  for(i <- readyVec.indices.reverse){
249    val r = readyVec(idxQueue(i))
250    XSDebug(false, r, p"r")
251    XSDebug(false, !r, p"-")
252  }
253  XSDebug(false, true.B, "\n")
254
255//  assert(!(tlbMiss && realDeqValid), "Error: realDeqValid should be false when replay valid!")
256  for(i <- 0 until qsize){
257    val uopQIdx = idxQueue(i)
258    val uop = uopQueue(uopQIdx)
259    val cnt = cntQueue(uopQIdx)
260    val nextIdx = i.U - moveMask(i)
261    //TODO: support replay
262    val roqIdxMatch = uop.roqIdx === io.tlbFeedback.bits.roqIdx
263    val notEmpty = stateQueue(i)=/=s_invalid
264    val replayThis = (stateQueue(i)===s_wait) && tlbMiss && roqIdxMatch
265    val tlbHitThis = notEmpty && tlbHit && roqIdxMatch
266    val flushThis = notEmpty && uop.needFlush(io.redirect)
267
268    when(replayThis){
269      stateQueue(nextIdx) := s_replay
270      cnt := (replayDelay-1).U
271    }
272    when(stateQueue(i)===s_replay){
273      when(cnt === 0.U){
274        stateQueue(nextIdx) := s_valid
275      }.otherwise({
276        cnt := cnt - 1.U
277      })
278    }
279    when(flushThis || tlbHitThis){
280      stateQueue(nextIdx) := s_invalid
281    }
282  }
283
284
285  // assign outputs
286  io.numExist := Mux(isFull, (qsize-1).U, tailPtr)
287
288  // Debug sigs
289  XSInfo(
290    io.enq.fire(),
291    p"enq fire: pc:${Hexadecimal(io.enq.bits.cf.pc)} roqIdx:${io.enq.bits.roqIdx} " +
292      p"src1: ${io.enq.bits.psrc1} src2:${io.enq.bits.psrc2} pdst:${io.enq.bits.pdest}\n"
293  )
294  XSInfo(
295    io.deq.fire(),
296    p"deq fire: pc:${Hexadecimal(io.deq.bits.uop.cf.pc)} roqIdx:${io.deq.bits.uop.roqIdx} " +
297      p"src1: ${io.deq.bits.uop.psrc1} data: ${Hexadecimal(io.deq.bits.src1)} " +
298      p"src2: ${io.deq.bits.uop.psrc2} data: ${Hexadecimal(io.deq.bits.src2)} " +
299      p"imm : ${Hexadecimal(io.deq.bits.uop.ctrl.imm)}\npdest: ${io.deq.bits.uop.pdest}\n"
300  )
301  XSDebug(p"tailPtr:$tailPtr tailAfterDeq:$tailAfterRealDeq tlbHit:$tlbHit\n")
302}
303