1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package xiangshan.backend.rename.freelist 18 19import org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import xiangshan._ 23import xiangshan.backend.rename._ 24import utils._ 25import utility._ 26 27 28class StdFreeList(freeListSize: Int, numLogicRegs: Int, regType: RegType, realNumLogicRegs: Int = 32)(implicit p: Parameters) extends BaseFreeList(freeListSize, realNumLogicRegs) with HasPerfEvents { 29 30 val freeList = RegInit(VecInit(Seq.tabulate(freeListSize)( i => (i + numLogicRegs).U(PhyRegIdxWidth.W) ))) 31 val lastTailPtr = RegInit(FreeListPtr(true, 0)) // tailPtr in the last cycle (need to add freeReqReg) 32 val tailPtr = Wire(new FreeListPtr) // this is the real tailPtr 33 val tailPtrOHReg = RegInit(0.U(freeListSize.W)) 34 35 // 36 // free committed instructions' `old_pdest` reg 37 // 38 val freeReqReg = io.freeReq 39 for (i <- 0 until RabCommitWidth) { 40 val offset = if (i == 0) 0.U else PopCount(freeReqReg.take(i)) 41 val enqPtr = lastTailPtr + offset 42 43 // Why RegNext (from RAT and Rename): for better timing 44 // Why we can RegNext: these free registers won't be used in the next cycle, 45 // since we set canAllocate only when the current free regs > RenameWidth. 46 when (freeReqReg(i)) { 47 freeList(enqPtr.value) := io.freePhyReg(i) 48 } 49 XSDebug(io.freeReq(i), p"req#$i free physical reg: ${io.freePhyReg(i)}\n") 50 } 51 52 tailPtr := lastTailPtr + PopCount(freeReqReg) 53 lastTailPtr := tailPtr 54 55 // 56 // allocate new physical registers for instructions at rename stage 57 // 58 val freeRegCnt = Wire(UInt()) // number of free registers in free list 59 io.canAllocate := GatedValidRegNext(freeRegCnt >= RenameWidth.U) // use RegNext for better timing 60 XSDebug(p"freeRegCnt: $freeRegCnt\n") 61 62 val phyRegCandidates = VecInit(headPtrOHVec.map(sel => Mux1H(sel, freeList))) 63 64 for(i <- 0 until RenameWidth) { 65 io.allocatePhyReg(i) := phyRegCandidates(PopCount(io.allocateReq.take(i))) 66 XSDebug(p"req:${io.allocateReq(i)} canAllocate:${io.canAllocate} pdest:${io.allocatePhyReg(i)}\n") 67 } 68 val doCommit = io.commit.isCommit 69 val archAlloc = io.commit.commitValid zip io.commit.info map { case (valid, info) => 70 valid && (regType match { 71 case Reg_F => info.fpWen 72 case Reg_V => info.vecWen 73 case Reg_V0 => info.v0Wen 74 case Reg_Vl => info.vlWen 75 }) 76 } 77 val numArchAllocate = PopCount(archAlloc) 78 val archHeadPtrNew = archHeadPtr + numArchAllocate 79 val archHeadPtrNext = Mux(doCommit, archHeadPtrNew, archHeadPtr) 80 archHeadPtr := archHeadPtrNext 81 82 val isWalkAlloc = io.walk && io.doAllocate 83 val isNormalAlloc = io.canAllocate && io.doAllocate 84 val isAllocate = isWalkAlloc || isNormalAlloc 85 val numAllocate = Mux(io.walk, PopCount(io.walkReq), PopCount(io.allocateReq)) 86 val headPtrAllocate = Mux(lastCycleRedirect, redirectedHeadPtr, headPtr + numAllocate) 87 val headPtrOHAllocate = Mux(lastCycleRedirect, redirectedHeadPtrOH, headPtrOHVec(numAllocate)) 88 val headPtrNext = Mux(isAllocate, headPtrAllocate, headPtr) 89 freeRegCnt := Mux(isWalkAlloc && !lastCycleRedirect, distanceBetween(tailPtr, headPtr) - PopCount(io.walkReq), 90 Mux(isNormalAlloc, distanceBetween(tailPtr, headPtr) - PopCount(io.allocateReq), 91 distanceBetween(tailPtr, headPtr))) 92 93 // priority: (1) exception and flushPipe; (2) walking; (3) mis-prediction; (4) normal dequeue 94 val realDoAllocate = !io.redirect && isAllocate 95 headPtr := Mux(realDoAllocate, headPtrAllocate, headPtr) 96 headPtrOH := Mux(realDoAllocate, headPtrOHAllocate, headPtrOH) 97 98 XSDebug(p"head:$headPtr tail:$tailPtr\n") 99 100 XSError(!isFull(tailPtr, archHeadPtr), s"${regType}ArchFreeList should always be full\n") 101 102 val enableFreeListCheck = false 103 if (enableFreeListCheck) { 104 for (i <- 0 until freeListSize) { 105 for (j <- i+1 until freeListSize) { 106 XSError(freeList(i) === freeList(j), s"Found same entry in free list! (i=$i j=$j)\n") 107 } 108 } 109 } 110 111 XSPerfAccumulate("utilization", PopCount(io.allocateReq)) 112 XSPerfAccumulate("allocation_blocked_cycle", !io.canAllocate) 113 XSPerfAccumulate("can_alloc_wrong", !io.canAllocate && freeRegCnt >= RenameWidth.U) 114 115 val freeRegCntReg = RegNext(freeRegCnt) 116 val perfEvents = Seq( 117 ("std_freelist_1_4_valid", freeRegCntReg < (freeListSize / 4).U ), 118 ("std_freelist_2_4_valid", freeRegCntReg >= (freeListSize / 4).U && freeRegCntReg < (freeListSize / 2).U ), 119 ("std_freelist_3_4_valid", freeRegCntReg >= (freeListSize / 2).U && freeRegCntReg < (freeListSize * 3 / 4).U), 120 ("std_freelist_4_4_valid", freeRegCntReg >= (freeListSize * 3 / 4).U ) 121 ) 122 123 QueuePerf(size = freeListSize, utilization = freeRegCntReg, full = freeRegCntReg === 0.U) 124 125 generatePerfEvent() 126} 127