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***************************************************************************************/ 16package xiangshan.mem 17 18import org.chipsalliance.cde.config.Parameters 19import chisel3._ 20import chisel3.util._ 21import utils._ 22import utility._ 23import xiangshan._ 24 25class FreeList(size: Int, allocWidth: Int, freeWidth: Int, enablePreAlloc: Boolean = false, moduleName: String = "")(implicit p: Parameters) extends XSModule 26 with HasCircularQueuePtrHelper 27 with HasPerfEvents 28{ 29 val io = IO(new Bundle() { 30 val allocateReq = Input(Vec(allocWidth, Bool())) 31 val allocateSlot = Output(Vec(allocWidth, UInt())) 32 val canAllocate = Output(Vec(allocWidth, Bool())) 33 val doAllocate = Input(Vec(allocWidth, Bool())) 34 35 val free = Input(UInt(size.W)) 36 37 val validCount = Output(UInt()) 38 val empty = Output(Bool()) 39 }) 40 41 println(s"FreeList: $moduleName, size " + size) 42 43 val freeList = RegInit(VecInit( 44 // originally {0, 1, ..., size - 1} are free. 45 Seq.tabulate(size)(i => i.U(log2Up(size).W)) 46 )) 47 48 class FreeListPtr extends CircularQueuePtr[FreeListPtr](size) 49 object FreeListPtr { 50 def apply(f: Boolean, v: Int): FreeListPtr = { 51 val ptr = Wire(new FreeListPtr) 52 ptr.flag := f.B 53 ptr.value := v.U 54 ptr 55 } 56 } 57 58 val headPtr = RegInit(FreeListPtr(false, 0)) 59 val headPtrNext = Wire(new FreeListPtr) 60 val tailPtr = RegInit(FreeListPtr(true, 0)) 61 val tailPtrNext = Wire(new FreeListPtr) 62 63 // legality check 64 def getRemBits(input: UInt)(rem: Int): UInt = { 65 VecInit((0 until size / freeWidth).map(i => { input(freeWidth * i + rem) })).asUInt 66 } 67 68 // free logic 69 val freeMask = RegInit(0.U(size.W)) 70 val freeSelMask = Wire(UInt(size.W)) 71 val freeSelMaskVec = Wire(Vec(freeWidth, UInt(size.W))) 72 73 // update freeMask 74 require((size % freeWidth) == 0) 75 freeSelMask := freeSelMaskVec.reduce(_|_) 76 freeMask := (io.free | freeMask) & ~freeSelMask 77 78 val remFreeSelMaskVec = VecInit(Seq.tabulate(freeWidth)(rem => getRemBits((freeMask & ~freeSelMask))(rem))) 79 val remFreeSelIndexOHVec = VecInit(Seq.tabulate(freeWidth)(fport => { 80 val highIndexOH = PriorityEncoderOH(remFreeSelMaskVec(fport)) 81 val freeIndexOHVec = Wire(Vec(size, Bool())) 82 freeIndexOHVec.foreach(e => e := false.B) 83 for (i <- 0 until size / freeWidth) { 84 freeIndexOHVec(i * freeWidth + fport) := highIndexOH(i) 85 } 86 freeIndexOHVec.asUInt 87 })) 88 89 val freeReq = GatedRegNext(VecInit(remFreeSelMaskVec.map(_.asUInt.orR))) 90 val freeSlotOH = GatedRegNext(remFreeSelIndexOHVec) 91 val doFree = freeReq.asUInt.orR 92 93 for (i <- 0 until freeWidth) { 94 val offset = PopCount(freeReq.take(i)) 95 val enqPtr = tailPtr + offset 96 97 when (freeReq(i)) { 98 freeList(enqPtr.value) := OHToUInt(freeSlotOH(i)) 99 } 100 101 freeSelMaskVec(i) := Mux(freeReq(i), freeSlotOH(i), 0.U) 102 } 103 104 tailPtrNext := tailPtr + PopCount(freeReq) 105 tailPtr := Mux(doFree, tailPtrNext, tailPtr) 106 107 // allocate 108 val doAllocate = io.doAllocate.asUInt.orR 109 val numAllocate = PopCount(io.doAllocate) 110 val freeSlotCnt = RegInit(size.U(log2Up(size + 1).W)) 111 112 for (i <- 0 until allocWidth) { 113 val offset = PopCount(io.allocateReq.take(i)) 114 115 if (enablePreAlloc) { 116 val deqPtr = headPtr + numAllocate + offset 117 io.canAllocate(i) := RegEnable(isBefore(deqPtr, tailPtr), enablePreAlloc.B) 118 io.allocateSlot(i) := RegEnable(freeList(deqPtr.value), enablePreAlloc.B) 119 } else { 120 val deqPtr = headPtr + offset 121 io.canAllocate(i) := isBefore(deqPtr, tailPtr) 122 io.allocateSlot(i) := freeList(deqPtr.value) 123 } 124 125 } 126 127 headPtrNext := headPtr + numAllocate 128 headPtr := Mux(doAllocate, headPtrNext, headPtr) 129 freeSlotCnt := distanceBetween(tailPtrNext, headPtrNext) 130 131 io.empty := freeSlotCnt === 0.U 132 io.validCount := size.U - freeSlotCnt 133 134 XSPerfAccumulate("empty", io.empty) 135 val perfEvents: Seq[(String, UInt)] = Seq( 136 ("empty", io.empty) 137 ) 138 generatePerfEvent() 139 140 // unique check 141 val enableFreeListCheck = false 142 if (enableFreeListCheck) { 143 val differentFlag = tailPtr.flag ^ headPtr.flag 144 val headMask = UIntToMask(headPtr.value, size) 145 val tailMask = UIntToMask(tailPtr.value, size) 146 val validMask1 = Mux(differentFlag, ~tailMask, tailMask ^ headMask) 147 val validMask2 = Mux(differentFlag, headMask, 0.U(size.W)) 148 val validMask = ~(validMask1 | validMask2) 149 for (i <- 0 until size) { 150 for (j <- i+1 until size) { 151 if (i != j) { 152 XSError(validMask(i) && validMask(j) && freeList(i) === freeList(j),s"Found same entry in free list! (i=$i j=$j)\n") 153 } 154 } 155 } 156 } 157 158 // end 159}