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 chipsalliance.rocketchip.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 require(isPow2(freeWidth)) 65 require((size % freeWidth) == 0) 66 def getRemBits(input: UInt)(rem: Int): UInt = { 67 VecInit((0 until size / freeWidth).map(i => { input(freeWidth * i + rem) })).asUInt 68 } 69 70 // free logic 71 val freeMask = RegInit(0.U(size.W)) 72 val freeSelMask = Wire(UInt(size.W)) 73 val freeSelMaskVec = Wire(Vec(freeWidth, UInt(size.W))) 74 75 // update freeMask 76 freeSelMask := freeSelMaskVec.reduce(_|_) 77 freeMask := (io.free | freeMask) & ~freeSelMask 78 79 val remFreeSelMaskVec = VecInit(Seq.tabulate(freeWidth)(rem => getRemBits((freeMask & ~freeSelMask))(rem))) 80 val remFreeSelIndexVec = VecInit(Seq.tabulate(freeWidth)(fport => { 81 val highIndex = PriorityEncoder(remFreeSelMaskVec(fport)) 82 Cat(highIndex, fport.U(log2Ceil(freeWidth).W)) 83 })) 84 85 val freeReq = RegNext(VecInit(remFreeSelMaskVec.map(_.asUInt.orR))) 86 val freeSlot = RegNext(remFreeSelIndexVec) 87 val doFree = freeReq.asUInt.orR 88 89 for (i <- 0 until freeWidth) { 90 val offset = PopCount(freeReq.take(i)) 91 val enqPtr = tailPtr + offset 92 93 when (freeReq(i)) { 94 freeList(enqPtr.value) := freeSlot(i) 95 } 96 97 freeSelMaskVec(i) := Mux(freeReq(i), UIntToOH(freeSlot(i)), 0.U) 98 } 99 100 tailPtrNext := tailPtr + PopCount(freeReq) 101 tailPtr := Mux(doFree, tailPtrNext, tailPtr) 102 103 // allocate 104 val doAllocate = io.doAllocate.asUInt.orR 105 val numAllocate = PopCount(io.doAllocate) 106 val freeSlotCnt = RegInit(size.U(log2Up(size + 1).W)) 107 108 for (i <- 0 until allocWidth) { 109 val offset = PopCount(io.allocateReq.take(i)) 110 111 if (enablePreAlloc) { 112 val deqPtr = headPtr + numAllocate + offset 113 io.canAllocate(i) := RegNext(isBefore(deqPtr, tailPtrNext)) 114 io.allocateSlot(i) := RegNext(freeList(deqPtr.value)) 115 } else { 116 val deqPtr = headPtr + offset 117 io.canAllocate(i) := isBefore(deqPtr, tailPtr) 118 io.allocateSlot(i) := freeList(deqPtr.value) 119 } 120 121 } 122 123 headPtrNext := headPtr + numAllocate 124 headPtr := Mux(doAllocate, headPtrNext, headPtr) 125 freeSlotCnt := distanceBetween(tailPtrNext, headPtrNext) 126 127 io.empty := freeSlotCnt === 0.U 128 io.validCount := size.U - freeSlotCnt 129 130 XSPerfAccumulate("empty", io.empty) 131 val perfEvents: Seq[(String, UInt)] = Seq( 132 ("empty", io.empty) 133 ) 134 generatePerfEvent() 135 136 // unique check 137 val enableFreeListCheck = false 138 if (enableFreeListCheck) { 139 val differentFlag = tailPtr.flag ^ headPtr.flag 140 val headMask = UIntToMask(headPtr.value, size) 141 val tailMask = UIntToMask(tailPtr.value, size) 142 val validMask1 = Mux(differentFlag, ~tailMask, tailMask ^ headMask) 143 val validMask2 = Mux(differentFlag, headMask, 0.U(size.W)) 144 val validMask = ~(validMask1 | validMask2) 145 for (i <- 0 until size) { 146 for (j <- i+1 until size) { 147 if (i != j) { 148 XSError(validMask(i) && validMask(j) && freeList(i) === freeList(j),s"Found same entry in free list! (i=$i j=$j)\n") 149 } 150 } 151 } 152 } 153 154 // end 155}