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