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