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 = RegEnable( 150 enable = true.B,//io.deq.ready, 151 next = selectedIdxWire - moveMask(selectedIdxWire) 152 ) 153// selectedIdxReg := selectedIdxWire - moveMask(selectedIdxWire) 154 selectedIdxRegOH := UIntToOH(selectedIdxReg) 155 XSDebug( 156 p"selMaskWire:${Binary(selectMask.asUInt())} selected:$selectedIdxWire" + 157 p" moveMask:${Binary(moveMask)} selectedIdxReg:$selectedIdxReg\n" 158 ) 159 160 161 // read regfile 162 val selectedUop = uopQueue(idxQueue(Mux(io.deq.ready, selectedIdxWire, selectedIdxReg))) 163 164 exuCfg match { 165 case Exu.ldExeUnitCfg => 166 io.readIntRf(0).addr := selectedUop.psrc1 // base 167 XSDebug(p"src1 read addr: ${io.readIntRf(0).addr}\n") 168 case Exu.stExeUnitCfg => 169 io.readIntRf(0).addr := selectedUop.psrc1 // base 170 io.readIntRf(1).addr := selectedUop.psrc2 // store data (int) 171 io.readFpRf(0).addr := selectedUop.psrc2 // store data (fp) 172 XSDebug( 173 p"src1 read addr: ${io.readIntRf(0).addr} src2 read addr: ${io.readIntRf(1).addr}\n" 174 ) 175 case _ => 176 require(requirement = false, "Error: IssueQueue only support ldu and stu!") 177 } 178 179 // (fake) deq to Load/Store unit 180 io.deq.valid := (stateQueue(selectedIdxReg)===s_valid) && readyVec(idxQueue(selectedIdxReg)) 181 io.deq.bits.uop := uopQueue(idxQueue(selectedIdxReg)) 182 183 val src1Bypass = doBypass(io.deq.bits.uop.psrc1, io.deq.bits.uop.ctrl.src1Type) 184 io.deq.bits.src1 := Mux(src1Bypass._1, src1Bypass._2, io.readIntRf(0).data) 185 if(exuCfg == Exu.stExeUnitCfg){ 186 val src2Bypass = doBypass(io.deq.bits.uop.psrc2, io.deq.bits.uop.ctrl.src2Type) 187 io.deq.bits.src2 := Mux(src2Bypass._1, 188 src2Bypass._2, 189 Mux(SrcType.isReg(io.deq.bits.uop.ctrl.src2Type), 190 io.readIntRf(1).data, 191 io.readFpRf(0).data 192 ) 193 ) 194 } else { 195 io.deq.bits.src2 := DontCare 196 } 197 io.deq.bits.src3 := DontCare 198 199 when(io.deq.fire()){ 200 stateQueue(selectedIdxReg - moveMask(selectedIdxReg)) := s_wait 201 assert(stateQueue(selectedIdxReg) === s_valid, "Dequeue a invalid entry to lsu!") 202 } 203 204 assert(!(tailPtr===0.U && tlbHit), "Error: queue is empty but tlbHit is true!") 205 206 val tailAfterRealDeq = tailPtr - moveMask(tailPtr.tail(1)) 207 val isFull = tailAfterRealDeq.head(1).asBool() // tailPtr===qsize.U 208 209 // enq 210 io.enq.ready := !isFull && !tlbMiss && !io.redirect.valid 211 when(io.enq.fire()){ 212 stateQueue(tailAfterRealDeq.tail(1)) := s_valid 213 val uopQIdx = idxQueue(tailPtr.tail(1)) 214 val new_uop = wakeUp(io.enq.bits) 215 uopQueue(uopQIdx) := new_uop 216 } 217 218 tailPtr := tailAfterRealDeq + io.enq.fire() 219 220 XSDebug( 221 realDeqValid, 222 p"firstWait:$firstWait firstBubble:$firstBubble realDeqIdx:$realDeqIdx\n" 223 ) 224 225 XSDebug("State Dump: ") 226 stateQueue.reverse.foreach(s =>{ 227 XSDebug(false, s===s_invalid, "-") 228 XSDebug(false, s===s_valid, "v") 229 XSDebug(false, s===s_wait, "w") 230 XSDebug(false, s===s_replay, "r") 231 }) 232 XSDebug(false, true.B, "\n") 233 234 XSDebug("State Dump: ") 235 idxQueue.reverse.foreach(id =>{ 236 XSDebug(false, true.B, p"$id") 237 }) 238 XSDebug(false, true.B, "\n") 239 240 XSDebug("State Dump: ") 241 readyVec.reverse.foreach(r =>{ 242 XSDebug(false, r, p"r") 243 XSDebug(false, !r, p"-") 244 }) 245 XSDebug(false, true.B, "\n") 246 247 assert(!(tlbMiss && realDeqValid), "Error: realDeqValid should be false when replay valid!") 248 for(i <- 0 until qsize){ 249 val uopQIdx = idxQueue(i) 250 val cnt = cntQueue(uopQIdx) 251 val nextIdx = i.U - moveMask(i) 252 when( 253 (tlbMiss && stateQueue(i)===s_wait) && 254 uopQueue(uopQIdx).isAfter(io.tlbFeedback.bits.roqIdx) 255 ){ 256 // 'i' is enough because 'realDeqValid' must be false here 257 stateQueue(i) := s_replay 258 cnt := (replayDelay-1).U 259 } 260 when(stateQueue(i)===s_replay){ 261 when(cnt === 0.U) { 262 stateQueue(nextIdx) := s_valid 263 if(i == 0) { 264 assert(!moveMask(0), "Error: Attemp to delete a 's_replay' entry!") 265 } 266 }.otherwise({ 267 cnt := cnt - 1.U 268 }) 269 } 270 when(uopQueue(uopQIdx).needFlush(io.redirect)){ 271 stateQueue(nextIdx) := s_invalid 272 } 273 } 274 275 276 // assign outputs 277 // TODO currently set to zero 278 io.numExist := 0.U//Mux(isFull, (qsize-1).U, tailPtr) 279 280 // Debug sigs 281 XSInfo( 282 io.enq.fire(), 283 p"enq fire: pc:${Hexadecimal(io.enq.bits.cf.pc)} roqIdx:${io.enq.bits.roqIdx} " + 284 p"src1: ${io.enq.bits.psrc1} src2:${io.enq.bits.psrc2} pdst:${io.enq.bits.pdest}\n" 285 ) 286 XSInfo( 287 io.deq.fire(), 288 p"deq fire: pc:${Hexadecimal(io.deq.bits.uop.cf.pc)} roqIdx:${io.deq.bits.uop.roqIdx} " + 289 p"src1: ${io.deq.bits.uop.psrc1} data: ${Hexadecimal(io.deq.bits.src1)} " + 290 p"src2: ${io.deq.bits.uop.psrc2} data: ${Hexadecimal(io.deq.bits.src2)} " + 291 p"imm : ${Hexadecimal(io.deq.bits.uop.ctrl.imm)}\npdest: ${io.deq.bits.uop.pdest}\n" 292 ) 293 XSDebug(p"tailPtr:$tailPtr tailAfterDeq:$tailAfterRealDeq tlbHit:${tlbHit}\n") 294} 295