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