xref: /XiangShan/src/main/scala/xiangshan/backend/issue/AgeDetector.scala (revision cf4a131aa362d39ddbdcf8ce093ababa522d8192)
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 AgeDetector(numEntries: Int, numEnq: Int)(implicit p: Parameters) extends XSModule {
27  val io = IO(new Bundle {
28    // NOTE: now we do not consider deq.
29    //       keeping these old invalid entries
30    //       does not affect the selection of the oldest entry that can be issued.
31    val enq = Vec(numEnq, Input(UInt(numEntries.W)))
32    val canIssue = Input(UInt(numEntries.W))
33    val out = Output(UInt(numEntries.W))
34  })
35
36  // age(i)(j): entry i enters queue before entry j
37  val age = Seq.fill(numEntries)(Seq.fill(numEntries)(RegInit(false.B)))
38  val nextAge = Seq.fill(numEntries)(Seq.fill(numEntries)(Wire(Bool())))
39
40  // to reduce reg usage, only use upper matrix
41  def get_age(row: Int, col: Int): Bool = if (row <= col) age(row)(col) else !age(col)(row)
42  def get_next_age(row: Int, col: Int): Bool = if (row <= col) nextAge(row)(col) else !nextAge(col)(row)
43  def isEnq(i: Int): Bool = {
44    VecInit(io.enq.map(_(i))).asUInt.orR
45  }
46  def isEnqNport(i: Int, numPorts: Int = 0): Bool = {
47    numPorts match {
48      case 0 => false.B
49      case n => VecInit(io.enq.take(n).map(_(i))).asUInt.orR
50    }
51  }
52
53  for ((row, i) <- nextAge.zipWithIndex) {
54    for ((elem, j) <- row.zipWithIndex) {
55      if (i == j) {
56        // an entry is always older than itself
57        elem := true.B
58      }
59      else if (i < j) {
60        when (isEnq(i) && isEnq(j)) {
61          // (1) when entry i enqueues from port k,
62          // (1.1) if entry j enqueues from previous ports, set to false
63          // (1.2) otherwise, set to true
64          val sel = io.enq.map(_(i))
65          val result = (0 until numEnq).map(k => isEnqNport(j, k))
66          elem := !ParallelMux(sel, result)
67        }.elsewhen (isEnq(i)) {
68          // (2) when entry i enqueues, set row(i) to false
69          elem := false.B
70        }.elsewhen (isEnq(j)) {
71          // (3) when entry j enqueues, set col(j) to true
72          elem := true.B
73        }.otherwise {
74          // default: unchanged
75          elem := get_age(i, j)
76        }
77      }
78      else {
79        elem := !nextAge(j)(i)
80      }
81      age(i)(j) := elem
82    }
83  }
84
85  def getOldestCanIssue(get: (Int, Int) => Bool, canIssue: UInt): UInt = {
86    VecInit((0 until numEntries).map(i => {
87      (VecInit((0 until numEntries).map(j => get(i, j))).asUInt | ~canIssue).andR & canIssue(i)
88    })).asUInt
89  }
90
91  io.out := getOldestCanIssue(get_age, io.canIssue)
92
93  for (i <- 0 until numEnq) {
94    assert(PopCount(io.enq(i)) <= 1.U, s"enq port ($i) is not ont-hot\n")
95  }
96}
97
98object AgeDetector {
99  def apply(numEntries: Int, enq: Vec[UInt], canIssue: UInt)(implicit p: Parameters): Valid[UInt] = {
100    val age = Module(new AgeDetector(numEntries, enq.length))
101    age.io.enq := enq
102    age.io.canIssue := canIssue
103    val out = Wire(Valid(UInt(numEntries.W)))
104    out.valid := canIssue.orR
105    out.bits := age.io.out
106    when (out.valid) {
107      assert(PopCount(out.bits) === 1.U, "out is not ont-hot when there is at least one entry can be issued\n")
108    }
109    out
110  }
111}
112