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