xref: /XiangShan/src/main/scala/xiangshan/backend/rename/freelist/MEFreeList.scala (revision 6112d99478b9144e0e9dde27ffc43993cdaee5d4)
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 utils._
24import utility._
25
26
27class MEFreeList(size: Int)(implicit p: Parameters) extends BaseFreeList(size) with HasPerfEvents {
28  val freeList = RegInit(VecInit(
29    // originally {1, 2, ..., size - 1} are free. Register 0-31 are mapped to x0.
30    Seq.tabulate(size - 1)(i => (i + 1).U(PhyRegIdxWidth.W)) :+ 0.U(PhyRegIdxWidth.W)))
31
32  val tailPtr = RegInit(FreeListPtr(false, size - 1))
33
34  val doWalkRename = io.walk && io.doAllocate && !io.redirect
35  val doNormalRename = io.canAllocate && io.doAllocate && !io.redirect
36  val doRename = doWalkRename || doNormalRename
37  val doCommit = io.commit.isCommit
38
39  /**
40    * Allocation: from freelist (same as StdFreelist)
41    */
42  val phyRegCandidates = VecInit(headPtrOHVec.map(sel => Mux1H(sel, freeList)))
43  for (i <- 0 until RenameWidth) {
44    // enqueue instr, is move elimination
45    io.allocatePhyReg(i) := phyRegCandidates(PopCount(io.allocateReq.take(i)))
46  }
47  // update arch head pointer
48  val archAlloc = io.commit.commitValid zip io.commit.info map {
49    case (valid, info) => valid && info.rfWen && !info.isMove
50  }
51  val numArchAllocate = PopCount(archAlloc)
52  val archHeadPtrNew  = archHeadPtr + numArchAllocate
53  val archHeadPtrNext = Mux(doCommit, archHeadPtrNew, archHeadPtr)
54  archHeadPtr := archHeadPtrNext
55
56  // update head pointer
57  val numAllocate = Mux(io.walk, PopCount(io.walkReq), PopCount(io.allocateReq))
58  val headPtrNew   = Mux(lastCycleRedirect, redirectedHeadPtr, headPtr + numAllocate)
59  val headPtrOHNew = Mux(lastCycleRedirect, redirectedHeadPtrOH, headPtrOHVec(numAllocate))
60  val headPtrNext   = Mux(doRename, headPtrNew, headPtr)
61  val headPtrOHNext = Mux(doRename, headPtrOHNew, headPtrOH)
62  headPtr   := headPtrNext
63  headPtrOH := headPtrOHNext
64
65  /**
66    * Deallocation: when refCounter becomes zero, the register can be released to freelist
67    */
68  for (i <- 0 until RabCommitWidth) {
69    when (io.freeReq(i)) {
70      val freePtr = tailPtr + PopCount(io.freeReq.take(i))
71      freeList(freePtr.value) := io.freePhyReg(i)
72    }
73  }
74
75  // update tail pointer
76  val tailPtrNext = tailPtr + PopCount(io.freeReq)
77  tailPtr := tailPtrNext
78
79  val freeRegCnt = Mux(doWalkRename && !lastCycleRedirect, distanceBetween(tailPtrNext, headPtr) - PopCount(io.walkReq),
80                   Mux(doNormalRename,                     distanceBetween(tailPtrNext, headPtr) - PopCount(io.allocateReq),
81                                                           distanceBetween(tailPtrNext, headPtr)))
82  val freeRegCntReg = RegNext(freeRegCnt)
83  io.canAllocate := freeRegCntReg >= RenameWidth.U
84
85  if(backendParams.debugEn){
86    val debugArchHeadPtr = RegNext(RegNext(archHeadPtr, FreeListPtr(false, 0)), FreeListPtr(false, 0)) // two-cycle delay from refCounter
87    val debugArchRAT = RegNext(RegNext(io.debug_rat.get, VecInit(Seq.fill(32)(0.U(PhyRegIdxWidth.W)))), VecInit(Seq.fill(32)(0.U(PhyRegIdxWidth.W))))
88    val debugUniqPR = Seq.tabulate(32)(i => i match {
89      case 0 => true.B
90      case _ => !debugArchRAT.take(i).map(_ === debugArchRAT(i)).reduce(_ || _)
91    })
92    XSError(distanceBetween(tailPtr, debugArchHeadPtr) +& PopCount(debugUniqPR) =/= size.U, "Integer physical register should be in either arch RAT or arch free list\n")
93  }
94
95  QueuePerf(size = size, utilization = freeRegCntReg, full = freeRegCntReg === 0.U)
96
97  XSPerfAccumulate("allocation_blocked_cycle", !io.canAllocate)
98  XSPerfAccumulate("can_alloc_wrong", !io.canAllocate && freeRegCnt >= RenameWidth.U)
99
100  val perfEvents = Seq(
101    ("me_freelist_1_4_valid", freeRegCntReg <  (size / 4).U                                     ),
102    ("me_freelist_2_4_valid", freeRegCntReg >= (size / 4).U && freeRegCntReg <= (size / 2).U    ),
103    ("me_freelist_3_4_valid", freeRegCntReg >= (size / 2).U && freeRegCntReg <= (size * 3 / 4).U),
104    ("me_freelist_4_4_valid", freeRegCntReg >= (size * 3 / 4).U                                 ),
105  )
106  generatePerfEvent()
107}
108