1package xiangshan.backend.issue 2 3import chisel3._ 4import chisel3.util._ 5import xiangshan._ 6import xiangshan.utils._ 7 8trait IQConst{ 9 val iqSize = 8 10 val iqIdxWidth = log2Up(iqSize) 11 val layer1Size = iqSize 12 val layer2Size = iqSize/2 13} 14 15sealed abstract class IQBundle extends XSBundle with IQConst 16sealed abstract class IQModule extends XSModule with IQConst with NeedImpl 17 18sealed class CmpInputBundle extends IQBundle{ 19 val instRdy = Input(Bool()) 20 val roqIdx = Input(UInt(RoqIdxWidth.W)) 21 val iqIdx = Input(UInt(iqIdxWidth.W)) 22} 23 24 25sealed class CompareCircuitUnit(layer: Int = 0, id: Int = 0) extends IQModule { 26 val io = IO(new Bundle(){ 27 val in1 = new CmpInputBundle 28 val in2 = new CmpInputBundle 29 val out = Flipped(new CmpInputBundle) 30 }) 31 32 val roqIdx1 = io.in1.roqIdx 33 val roqIdx2 = io.in2.roqIdx 34 val iqIdx1 = io.in1.iqIdx 35 val iqIdx2 = io.in2.iqIdx 36 37 val inst1Rdy = io.in1.instRdy 38 val inst2Rdy = io.in2.instRdy 39 40 io.out.instRdy := inst1Rdy | inst2Rdy 41 io.out.roqIdx := roqIdx2 42 io.out.iqIdx := iqIdx2 43 44 when((inst1Rdy && !inst2Rdy) || (inst1Rdy && inst2Rdy && (roqIdx1 < roqIdx2))){ 45 io.out.roqIdx := roqIdx1 46 io.out.iqIdx := iqIdx1 47 } 48 49} 50 51class IssueQueue(val fuTypeInt: BigInt, val wakeupCnt: Int, val bypassCnt: Int = 0, val fixedDelay: Int = 1) extends IQModule { 52 53 val useBypass = bypassCnt > 0 54 55 val io = IO(new Bundle() { 56 // flush Issue Queue 57 val redirect = Flipped(ValidIO(new Redirect)) 58 59 // enq Ctrl sigs at dispatch-2 60 val enqCtrl = Flipped(DecoupledIO(new MicroOp)) 61 // enq Data at next cycle (regfile has 1 cycle latency) 62 val enqData = Flipped(ValidIO(new ExuInput)) 63 64 // broadcast selected uop to other issue queues which has bypasses 65 val selectedUop = if(useBypass) ValidIO(new MicroOp) else null 66 67 // send to exu 68 val deq = DecoupledIO(new ExuInput) 69 70 // listen to write back bus 71 val wakeUpPorts = Vec(wakeupCnt, Flipped(ValidIO(new ExuOutput))) 72 73 // use bypass uops to speculative wake-up 74 val bypassUops = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new MicroOp))) else null 75 val bypassData = if(useBypass) Vec(bypassCnt, Flipped(ValidIO(new ExuOutput))) else null 76 }) 77 //--------------------------------------------------------- 78 // Issue Queue 79 //--------------------------------------------------------- 80 81 //Tag Queue 82 val ctrlFlow = Mem(iqSize,new CtrlFlow) 83 val ctrlSig = Mem(iqSize,new CtrlSignals) 84 val brMask = RegInit(VecInit(Seq.fill(iqSize)(0.U(BrqSize.W)))) 85 val valid = RegInit(VecInit(Seq.fill(iqSize)(false.B))) 86 val src1Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B))) 87 val src2Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B))) 88 val src3Rdy = RegInit(VecInit(Seq.fill(iqSize)(false.B))) 89 val prfSrc1 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 90 val prfSrc2 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 91 val prfSrc3 = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 92 val prfDest = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 93 val oldPDest = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 94 val freelistAllocPtr = Reg(Vec(iqSize, UInt(PhyRegIdxWidth.W))) 95 val roqIdx = Reg(Vec(iqSize, UInt(RoqIdxWidth.W))) 96 97 val instRdy = WireInit(VecInit(List.tabulate(iqSize)(i => src1Rdy(i) && src2Rdy(i) && valid(i)))) 98 99 100 //tag enqueue 101 val iqEmty = !valid.asUInt.orR 102 val iqFull = valid.asUInt.andR 103 val iqAllowIn = !iqFull 104 io.enqCtrl.ready := iqAllowIn 105 106 //enqueue pointer 107 val emptySlot = ~valid.asUInt 108 val enqueueSelect = PriorityEncoder(emptySlot) 109 //assert(!io.enqCtrl.valid && io.redirect.valid,"enqueue valid should be false when redirect valid") 110 111 when(io.enqCtrl.fire()){ 112 ctrlFlow(enqueueSelect) := io.enqCtrl.bits.cf 113 ctrlSig(enqueueSelect) := io.enqCtrl.bits.ctrl 114 brMask(enqueueSelect) := io.enqCtrl.bits.brMask 115 valid(enqueueSelect) := true.B 116 src1Rdy(enqueueSelect) := io.enqCtrl.bits.src1State === SrcState.rdy 117 src2Rdy(enqueueSelect) := io.enqCtrl.bits.src2State === SrcState.rdy 118 src3Rdy(enqueueSelect) := io.enqCtrl.bits.src3State === SrcState.rdy 119 prfSrc1(enqueueSelect) := io.enqCtrl.bits.psrc1 120 prfSrc2(enqueueSelect) := io.enqCtrl.bits.psrc2 121 prfSrc3(enqueueSelect) := io.enqCtrl.bits.psrc3 122 prfDest(enqueueSelect) := io.enqCtrl.bits.pdest 123 oldPDest(enqueueSelect) := io.enqCtrl.bits.old_pdest 124 freelistAllocPtr(enqueueSelect) := io.enqCtrl.bits.freelistAllocPtr 125 roqIdx(enqueueSelect) := io.enqCtrl.bits.roqIdx 126 127 } 128 129 //Data Queue 130 val src1Data = Reg(Vec(iqSize, UInt(XLEN.W))) 131 val src2Data = Reg(Vec(iqSize, UInt(XLEN.W))) 132 val src3Data = Reg(Vec(iqSize, UInt(XLEN.W))) 133 134 val enqSelNext = RegNext(enqueueSelect) 135 val enqFireNext = RegNext(io.enqCtrl.fire()) 136 137 // Read RegFile 138 when (enqFireNext) { 139 src1Data(enqSelNext) := io.enqData.bits.src1 140 src2Data(enqSelNext) := io.enqData.bits.src2 141 src3Data(enqSelNext) := io.enqData.bits.src3 142 } 143 144 // From Common Data Bus(wakeUpPort) 145 // chisel claims that firrtl will optimize Mux1H to and/or tree 146 // TODO: ignore ALU'cdb srcRdy, for byPass has done it 147 if(wakeupCnt > 0) { 148 val cdbValid = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).valid) 149 val cdbData = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.data) 150 val cdbPdest = List.tabulate(wakeupCnt)(i => io.wakeUpPorts(i).bits.uop.pdest) 151 152 val srcNum = 3 153 val prfSrc = List(prfSrc1, prfSrc2, prfSrc3) 154 val srcRdy = List(src1Rdy, src2Rdy, src3Rdy) 155 val srcData = List(src1Data, src2Data, src3Data) 156 val srcHitVec = List.tabulate(srcNum)(k => 157 List.tabulate(iqSize)(i => 158 List.tabulate(wakeupCnt)(j => 159 (prfSrc(k)(i) === cdbPdest(j)) && cdbValid(j)))) 160 val srcHit = List.tabulate(srcNum)(k => 161 List.tabulate(iqSize)(i => 162 ParallelOR(srcHitVec(k)(i)).asBool())) 163 // VecInit(srcHitVec(k)(i)).asUInt.orR)) 164 for(k <- 0 until srcNum){ 165 for(i <- 0 until iqSize)( when (valid(i)) { 166 when(!srcRdy(k)(i) && srcHit(k)(i)) { 167 srcRdy(k)(i) := true.B 168 // srcData(k)(i) := Mux1H(srcHitVec(k)(i), cdbData) 169 srcData(k)(i) := ParallelMux(srcHitVec(k)(i) zip cdbData) 170 } 171 }) 172 } 173 // From byPass [speculative] (just for ALU to listen to other ALU's res, include itself) 174 // just need Tag(Ctrl). send out Tag when Tag is decided. other ALUIQ listen to them and decide Tag 175 // byPassUops is one cycle before byPassDatas 176 if (bypassCnt > 0) { 177 val bypassPdest = List.tabulate(bypassCnt)(i => io.bypassUops(i).bits.pdest) 178 val bypassValid = List.tabulate(bypassCnt)(i => io.bypassUops(i).valid) // may only need valid not fire() 179 val bypassData = List.tabulate(bypassCnt)(i => io.bypassData(i).bits.data) 180 val srcBpHitVec = List.tabulate(srcNum)(k => 181 List.tabulate(iqSize)(i => 182 List.tabulate(bypassCnt)(j => 183 (prfSrc(k)(i) === bypassPdest(j)) && bypassValid(j)))) 184 val srcBpHit = List.tabulate(srcNum)(k => 185 List.tabulate(iqSize)(i => 186 ParallelOR(srcBpHitVec(k)(i)).asBool())) 187 // VecInit(srcBpHitVec(k)(i)).asUInt.orR)) 188 val srcBpHitVecNext = List.tabulate(srcNum)(k => 189 List.tabulate(iqSize)(i => 190 List.tabulate(bypassCnt)(j => RegNext(srcBpHitVec(k)(i)(j))))) 191 val srcBpHitNext = List.tabulate(srcNum)(k => 192 List.tabulate(iqSize)(i => 193 RegNext(srcBpHit(k)(i)))) 194 val srcBpData = List.tabulate(srcNum)(k => 195 List.tabulate(iqSize)(i => 196 ParallelMux(srcBpHitVecNext(k)(i) zip bypassData))) 197 // Mux1H(srcBpHitVecNext(k)(i), bypassData))) 198 for(k <- 0 until srcNum){ 199 for(i <- 0 until iqSize){ when (valid(i)) { 200 when(valid(i) && !srcRdy(k)(i) && srcBpHit(k)(i)) { srcRdy(k)(i) := true.B } 201 when(srcBpHitNext(k)(i)) { srcData(k)(i) := srcBpData(k)(i)} 202 }} 203 } 204 } 205 } 206 207 208 //--------------------------------------------------------- 209 // Select Circuit 210 //--------------------------------------------------------- 211 //layer 1 212 val layer1CCUs = (0 until layer1Size by 2) map { i => 213 val CCU_1 = Module(new CompareCircuitUnit(layer = 1, id = i/2)) 214 CCU_1.io.in1.instRdy := instRdy(i) && valid(i) 215 CCU_1.io.in1.roqIdx := roqIdx(i) 216 CCU_1.io.in1.iqIdx := i.U 217 218 CCU_1.io.in2.instRdy := instRdy(i+1) && valid(i+1) 219 CCU_1.io.in2.roqIdx := roqIdx(i+1) 220 CCU_1.io.in2.iqIdx := (i+1).U 221 222 CCU_1 223 } 224 225 //layer 2 226 val layer2CCUs = (0 until layer2Size by 2) map { i => 227 val CCU_2 = Module(new CompareCircuitUnit(layer = 2, id = i/2)) 228 CCU_2.io.in1.instRdy := layer1CCUs(i).io.out.instRdy 229 CCU_2.io.in1.roqIdx := layer1CCUs(i).io.out.roqIdx 230 CCU_2.io.in1.iqIdx := layer1CCUs(i).io.out.iqIdx 231 232 CCU_2.io.in2.instRdy := layer1CCUs(i+1).io.out.instRdy 233 CCU_2.io.in2.roqIdx := layer1CCUs(i+1).io.out.roqIdx 234 CCU_2.io.in2.iqIdx := layer1CCUs(i+1).io.out.iqIdx 235 236 CCU_2 237 } 238 239 //layer 3 240 val CCU_3 = Module(new CompareCircuitUnit(layer = 3, id = 0)) 241 CCU_3.io.in1.instRdy := layer2CCUs(0).io.out.instRdy 242 CCU_3.io.in1.roqIdx := layer2CCUs(0).io.out.roqIdx 243 CCU_3.io.in1.iqIdx := layer2CCUs(0).io.out.iqIdx 244 245 CCU_3.io.in2.instRdy := layer2CCUs(1).io.out.instRdy 246 CCU_3.io.in2.roqIdx := layer2CCUs(1).io.out.roqIdx 247 CCU_3.io.in2.iqIdx := layer2CCUs(1).io.out.iqIdx 248 249 250 //--------------------------------------------------------- 251 // Redirect Logic 252 //--------------------------------------------------------- 253 val expRedirect = io.redirect.valid && io.redirect.bits.isException 254 val brRedirect = io.redirect.valid && !io.redirect.bits.isException 255 256 List.tabulate(iqSize)( i => 257 when(brRedirect && (UIntToOH(io.redirect.bits.brTag) & brMask(i)).orR && valid(i) ){ 258 valid(i) := false.B 259 } .elsewhen(expRedirect) { 260 valid(i) := false.B 261 } 262 ) 263 264 //Dequeue Logic 265 //hold the sel-index to wait for data 266 val selInstIdx = RegInit(0.U(iqIdxWidth.W)) 267 val selInstRdy = RegInit(false.B) 268 269 //issue the select instruction 270 val dequeueSelect = Wire(UInt(iqIdxWidth.W)) 271 dequeueSelect := selInstIdx 272 273 val brRedirectMaskMatch = (UIntToOH(io.redirect.bits.brTag) & brMask(dequeueSelect)).orR 274 val IQreadyGo = selInstRdy && !expRedirect && (!brRedirect || !brRedirectMaskMatch) 275 276 io.deq.valid := IQreadyGo 277 278 io.deq.bits.uop.psrc1 := prfSrc1(dequeueSelect) 279 io.deq.bits.uop.psrc2 := prfSrc2(dequeueSelect) 280 io.deq.bits.uop.psrc3 := prfSrc3(dequeueSelect) 281 io.deq.bits.uop.pdest := prfDest(dequeueSelect) 282 io.deq.bits.uop.old_pdest := oldPDest(dequeueSelect) 283 io.deq.bits.uop.src1State := SrcState.rdy 284 io.deq.bits.uop.src2State := SrcState.rdy 285 io.deq.bits.uop.src3State := SrcState.rdy 286 io.deq.bits.uop.freelistAllocPtr := freelistAllocPtr(dequeueSelect) 287 io.deq.bits.uop.roqIdx := roqIdx(dequeueSelect) 288 289 //TODO 290 io.deq.bits.redirect := DontCare 291 292 io.deq.bits.src1 := src1Data(dequeueSelect) 293 io.deq.bits.src2 := src2Data(dequeueSelect) 294 io.deq.bits.src3 := src3Data(dequeueSelect) 295 296 //update the index register of instruction that can be issue, unless function unit not allow in 297 //then the issue will be stopped to wait the function unit 298 //clear the validBit of dequeued instruction in issuequeue 299 when(io.deq.fire()){ 300 selInstRdy := CCU_3.io.out.instRdy 301 selInstIdx := CCU_3.io.out.iqIdx 302 valid(dequeueSelect) := false.B 303 } 304 305 // SelectedUop (bypass / speculative) 306 if(useBypass) { 307 def DelayPipe[T <: Data](a: T, delay: Int = 0) = { 308 val storage = Wire(VecInit(Seq.fill(delay+1)(a))) 309 // storage(0) := a 310 for(i <- 1 until delay) { 311 storage(i) := RegNext(storage(i-1)) 312 } 313 storage(delay) 314 } 315 val sel = io.selectedUop 316 val selIQIdx = CCU_3.io.out.iqIdx 317 val delayPipe = DelayPipe(VecInit(CCU_3.io.out.instRdy, prfDest(selIQIdx)), fixedDelay-1) 318 sel.valid := delayPipe(fixedDelay-1)(0) 319 sel.bits := DontCare 320 sel.bits.pdest := delayPipe(fixedDelay-1)(1) 321 } 322} 323