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, numDeq: 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 = Vec(numDeq, Input(UInt(numEntries.W))) 33 val out = Vec(numDeq, 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 = { 42 if (row < col) 43 age(row)(col) 44 else if (row == col) 45 true.B 46 else 47 !age(col)(row) 48 } 49 def get_next_age(row: Int, col: Int): Bool = if (row <= col) nextAge(row)(col) else !nextAge(col)(row) 50 def isEnq(i: Int): Bool = { 51 VecInit(io.enq.map(_(i))).asUInt.orR 52 } 53 def isEnqNport(i: Int, numPorts: Int = 0): Bool = { 54 numPorts match { 55 case 0 => false.B 56 case n => VecInit(io.enq.take(n).map(_(i))).asUInt.orR 57 } 58 } 59 60 for ((row, i) <- nextAge.zipWithIndex) { 61 for ((elem, j) <- row.zipWithIndex) { 62 if (i == j) { 63 // an entry is always older than itself 64 elem := true.B 65 } 66 else if (i < j) { 67 when (isEnq(i) && isEnq(j)) { 68 // (1) when entry i enqueues from port k, 69 // (1.1) if entry j enqueues from previous ports, set to false 70 // (1.2) otherwise, set to true 71 val sel = io.enq.map(_(i)) 72 val result = (0 until numEnq).map(k => isEnqNport(j, k)) 73 elem := !ParallelMux(sel, result) 74 }.elsewhen (isEnq(i)) { 75 // (2) when entry i enqueues, set row(i) to false 76 elem := false.B 77 }.elsewhen (isEnq(j)) { 78 // (3) when entry j enqueues, set col(j) to true 79 elem := true.B 80 }.otherwise { 81 // default: unchanged 82 elem := get_age(i, j) 83 } 84 } 85 else { 86 elem := !nextAge(j)(i) 87 } 88 age(i)(j) := Mux(isEnq(i) | isEnq(j), elem, age(i)(j)) 89 } 90 } 91 92 def getOldestCanIssue(get: (Int, Int) => Bool, canIssue: UInt): UInt = { 93 VecInit((0 until numEntries).map(i => { 94 (VecInit((0 until numEntries).map(j => get(i, j))).asUInt | ~canIssue).andR & canIssue(i) 95 })).asUInt 96 } 97 98 io.out.zip(io.canIssue).foreach { case (out, canIssue) => 99 out := getOldestCanIssue(get_age, canIssue) 100 } 101 102 for (i <- 0 until numEnq) { 103 assert(PopCount(io.enq(i)) <= 1.U, s"enq port ($i) is not ont-hot\n") 104 } 105} 106 107object AgeDetector { 108 def apply(numEntries: Int, enq: Vec[UInt], canIssue: Vec[UInt])(implicit p: Parameters): Vec[Valid[UInt]] = { 109 val age = Module(new AgeDetector(numEntries, enq.length, canIssue.length)) 110 age.io.enq := enq 111 age.io.canIssue := canIssue 112 val outVec = Wire(Vec(canIssue.length, Valid(UInt(numEntries.W)))) 113 outVec.zipWithIndex.foreach { case (out, i) => 114 out.valid := canIssue(i).orR 115 out.bits := age.io.out(i) 116 when (out.valid) { 117 assert(PopCount(out.bits) === 1.U, s"out ($i) is not ont-hot when there is at least one entry can be issued\n") 118 } 119 } 120 outVec 121 } 122 def apply(numEntries: Int, enq: Vec[UInt], canIssue: UInt)(implicit p: Parameters): Valid[UInt] = { 123 val age = Module(new AgeDetector(numEntries, enq.length, 1)) 124 age.io.enq := enq 125 age.io.canIssue(0) := canIssue 126 val out = Wire(Valid(UInt(numEntries.W))) 127 out.valid := canIssue.orR 128 out.bits := age.io.out(0) 129 when (out.valid) { 130 assert(PopCount(out.bits) === 1.U, "out is not ont-hot when there is at least one entry can be issued\n") 131 } 132 out 133 } 134} 135