xref: /XiangShan/src/main/scala/xiangshan/backend/issue/NewAgeDetector.scala (revision 4243aa09225ffb7b71ce68fd9a01299dce92729c)
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.issue
18
19import org.chipsalliance.cde.config.Parameters
20import chisel3._
21import chisel3.util._
22import xiangshan._
23import utils._
24import utility._
25
26class NewAgeDetector(numEntries: Int, numEnq: Int, numDeq: Int)(implicit p: Parameters) extends XSModule {
27  val io = IO(new Bundle {
28    val enq = Vec(numEnq, Input(Bool()))
29    val canIssue = Vec(numDeq, Input(UInt(numEntries.W)))
30    val out = Vec(numDeq, Output(UInt(numEntries.W)))
31  })
32
33  // age(i)(j): entry i enters queue before entry j
34  val age = Seq.fill(numEntries)(Seq.fill(numEntries)(RegInit(false.B)))
35  val nextAge = Seq.fill(numEntries)(Seq.fill(numEntries)(Wire(Bool())))
36
37  // to reduce reg usage, only use upper matrix
38  def get_age(row: Int, col: Int): Bool = {
39    if (row < col)
40      age(row)(col)
41    else if (row == col)
42      true.B
43    else
44      !age(col)(row)
45  }
46  def get_next_age(row: Int, col: Int): Bool = if (row <= col) nextAge(row)(col) else !nextAge(col)(row)
47
48  //only for row <= col
49  for((row, i) <- nextAge.zipWithIndex) {
50    for((elem, j) <- row.zipWithIndex) {
51      if (i == j) {
52        // an entry is always older than itself
53        elem := true.B
54      }
55      else if (i < j) {
56        when (io.enq(j)) {
57          // (1) when entry j enqueues from port k,
58          // (1.1) if entry i (<j) enqueues from previous ports, it is older than entry j
59          // (1.2) if entry i does not enqueue, set col(j) older than entry j
60          elem := true.B
61        }.elsewhen (io.enq(i)) {
62          // (2) when entry i enqueues, set row(i) to false
63          elem := false.B
64        }.otherwise {
65          // default: unchanged
66          elem := get_age(i, j)
67        }
68      }
69      else {
70        elem := !nextAge(j)(i)
71      }
72      age(i)(j) := Mux(io.enq(i) | io.enq(j), elem, age(i)(j))
73    }
74  }
75
76  def getOldestCanIssue(get: (Int, Int) => Bool, canIssue: UInt): UInt = {
77    VecInit((0 until numEntries).map(i => {
78      (VecInit((0 until numEntries).map(j => get(i, j))).asUInt | ~canIssue).andR & canIssue(i)
79    })).asUInt
80  }
81
82  io.out.zip(io.canIssue).foreach { case (out, canIssue) =>
83    out := getOldestCanIssue(get_age, canIssue)
84  }
85}
86
87object NewAgeDetector {
88  def apply(numEntries: Int, enq: Vec[Bool], canIssue: Vec[UInt])(implicit p: Parameters): Vec[Valid[UInt]] = {
89    val age = Module(new NewAgeDetector(numEntries, enq.length, canIssue.length))
90    age.io.enq := enq
91    age.io.canIssue := canIssue
92    val outVec = Wire(Vec(canIssue.length, Valid(UInt(numEntries.W))))
93    outVec.zipWithIndex.foreach { case (out, i) =>
94      out.valid := canIssue(i).orR
95      out.bits := age.io.out(i)
96      when (out.valid) {
97        assert(PopCount(out.bits) === 1.U, s"out ($i) is not ont-hot when there is at least one entry can be issued\n")
98      }
99    }
100    outVec
101  }
102}