xref: /XiangShan/src/main/scala/xiangshan/backend/issue/AgeDetector.scala (revision 83ba63b34cf09b33c0a9e1b3203138e51af4491b)
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, regOut: Boolean = true)(implicit p: Parameters) extends XSModule {
27  val io = IO(new Bundle {
28    // NOTE: deq and enq may come at the same cycle.
29    val enq = Vec(numEnq, Input(UInt(numEntries.W)))
30    val deq = Input(UInt(numEntries.W))
31    val out = Output(UInt(numEntries.W))
32  })
33
34  // age(i)(j): entry i enters queue before entry j
35  val age = Seq.fill(numEntries)(Seq.fill(numEntries)(RegInit(false.B)))
36  val nextAge = Seq.fill(numEntries)(Seq.fill(numEntries)(Wire(Bool())))
37
38  // to reduce reg usage, only use upper matrix
39  def get_age(row: Int, col: Int): Bool = if (row <= col) age(row)(col) else !age(col)(row)
40  def get_next_age(row: Int, col: Int): Bool = if (row <= col) nextAge(row)(col) else !nextAge(col)(row)
41  def isFlushed(i: Int): Bool = io.deq(i)
42  def isEnqueued(i: Int, numPorts: Int = -1): Bool = {
43    val takePorts = if (numPorts == -1) io.enq.length else numPorts
44    takePorts match {
45      case 0 => false.B
46      case 1 => io.enq.head(i) && !isFlushed(i)
47      case n => VecInit(io.enq.take(n).map(_(i))).asUInt.orR && !isFlushed(i)
48    }
49  }
50
51  for ((row, i) <- nextAge.zipWithIndex) {
52    val thisValid = get_age(i, i) || isEnqueued(i)
53    for ((elem, j) <- row.zipWithIndex) {
54      when (isFlushed(i)) {
55        // (1) when entry i is flushed or dequeues, set row(i) to false.B
56        elem := false.B
57      }.elsewhen (isFlushed(j)) {
58        // (2) when entry j is flushed or dequeues, set column(j) to validVec
59        elem := thisValid
60      }.elsewhen (isEnqueued(i)) {
61        // (3) when entry i enqueues from port k,
62        // (3.1) if entry j enqueues from previous ports, set to false
63        // (3.2) otherwise, set to true if and only of entry j is invalid
64        // overall: !jEnqFromPreviousPorts && !jIsValid
65        val sel = io.enq.map(_(i))
66        val result = (0 until numEnq).map(k => isEnqueued(j, k))
67        // why ParallelMux: sel must be one-hot since enq is one-hot
68        elem := !get_age(j, j) && !ParallelMux(sel, result)
69      }.otherwise {
70        // default: unchanged
71        elem := get_age(i, j)
72      }
73      age(i)(j) := elem
74    }
75  }
76
77  def getOldest(get: (Int, Int) => Bool): UInt = {
78    VecInit((0 until numEntries).map(i => {
79      VecInit((0 until numEntries).map(j => get(i, j))).asUInt.andR
80    })).asUInt
81  }
82  val best = getOldest(get_age)
83  val nextBest = getOldest(get_next_age)
84
85  io.out := (if (regOut) best else nextBest)
86
87  val ageMatrix = VecInit(age.map(v => VecInit(v).asUInt.andR)).asUInt
88  val symmetricAge = RegNext(nextBest)
89  XSError(ageMatrix =/= symmetricAge, p"age error between ${Hexadecimal(ageMatrix)} and ${Hexadecimal(symmetricAge)}\n")
90}
91
92object AgeDetector {
93  def apply(numEntries: Int, enq: Vec[UInt], deq: UInt, canIssue: UInt)(implicit p: Parameters): Valid[UInt] = {
94    val age = Module(new AgeDetector(numEntries, enq.length, regOut = true))
95    age.io.enq := enq
96    age.io.deq := deq
97    val out = Wire(Valid(UInt(deq.getWidth.W)))
98    out.valid := (canIssue & age.io.out).orR
99    out.bits := age.io.out
100    out
101  }
102}
103