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