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