xref: /XiangShan/src/main/scala/xiangshan/mem/lsqueue/FreeList.scala (revision 92b88f30156d46e844042eea94f7121557fd09a1)
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}