// See LICENSE.Berkeley for license details. // See LICENSE.SiFive for license details. package freechips.rocketchip.util import Chisel._ import chisel3.experimental.{dontTouch, RawModule} import freechips.rocketchip.config.Parameters import scala.math._ class ParameterizedBundle(implicit p: Parameters) extends Bundle // TODO: replace this with an implicit class when @chisel unprotects dontTouchPorts trait DontTouch { self: RawModule => /** Marks every port as don't touch * * @note This method can only be called after the Module has been fully constructed * (after Module(...)) */ def dontTouchPorts(): this.type = { self.getModulePorts.foreach(dontTouch(_)) self } def dontTouchPortsExcept(f: Data => Boolean): this.type = { self.getModulePorts.filterNot(f).foreach(dontTouch(_)) self } } trait Clocked extends Bundle { val clock = Clock() val reset = Bool() } trait CanHaltAndCatchFire extends Bundle { val halt_and_catch_fire: Option[Bool] } object DecoupledHelper { def apply(rvs: Bool*) = new DecoupledHelper(rvs) } class DecoupledHelper(val rvs: Seq[Bool]) { def fire(exclude: Bool, includes: Bool*) = { (rvs.filter(_ ne exclude) ++ includes).reduce(_ && _) } } object MuxT { def apply[T <: Data, U <: Data](cond: Bool, con: (T, U), alt: (T, U)): (T, U) = (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2)) def apply[T <: Data, U <: Data, W <: Data](cond: Bool, con: (T, U, W), alt: (T, U, W)): (T, U, W) = (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2), Mux(cond, con._3, alt._3)) def apply[T <: Data, U <: Data, W <: Data, X <: Data](cond: Bool, con: (T, U, W, X), alt: (T, U, W, X)): (T, U, W, X) = (Mux(cond, con._1, alt._1), Mux(cond, con._2, alt._2), Mux(cond, con._3, alt._3), Mux(cond, con._4, alt._4)) } /** Creates a cascade of n MuxTs to search for a key value. */ object MuxTLookup { def apply[S <: UInt, T <: Data, U <: Data](key: S, default: (T, U), mapping: Seq[(S, (T, U))]): (T, U) = { var res = default for ((k, v) <- mapping.reverse) res = MuxT(k === key, v, res) res } def apply[S <: UInt, T <: Data, U <: Data, W <: Data](key: S, default: (T, U, W), mapping: Seq[(S, (T, U, W))]): (T, U, W) = { var res = default for ((k, v) <- mapping.reverse) res = MuxT(k === key, v, res) res } } object ValidMux { def apply[T <: Data](v1: ValidIO[T], v2: ValidIO[T]*): ValidIO[T] = { apply(v1 +: v2.toSeq) } def apply[T <: Data](valids: Seq[ValidIO[T]]): ValidIO[T] = { val out = Wire(Valid(valids.head.bits.cloneType)) out.valid := valids.map(_.valid).reduce(_ || _) out.bits := MuxCase(valids.head.bits, valids.map(v => (v.valid -> v.bits))) out } } object Str { def apply(s: String): UInt = { var i = BigInt(0) require(s.forall(validChar _)) for (c <- s) i = (i << 8) | c UInt(i, s.length*8) } def apply(x: Char): UInt = { require(validChar(x)) UInt(x.toInt, 8) } def apply(x: UInt): UInt = apply(x, 10) def apply(x: UInt, radix: Int): UInt = { val rad = UInt(radix) val w = x.getWidth require(w > 0) var q = x var s = digit(q % rad) for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) { q = q / rad s = Cat(Mux(Bool(radix == 10) && q === UInt(0), Str(' '), digit(q % rad)), s) } s } def apply(x: SInt): UInt = apply(x, 10) def apply(x: SInt, radix: Int): UInt = { val neg = x < SInt(0) val abs = x.abs.asUInt if (radix != 10) { Cat(Mux(neg, Str('-'), Str(' ')), Str(abs, radix)) } else { val rad = UInt(radix) val w = abs.getWidth require(w > 0) var q = abs var s = digit(q % rad) var needSign = neg for (i <- 1 until ceil(log(2)/log(radix)*w).toInt) { q = q / rad val placeSpace = q === UInt(0) val space = Mux(needSign, Str('-'), Str(' ')) needSign = needSign && !placeSpace s = Cat(Mux(placeSpace, space, digit(q % rad)), s) } Cat(Mux(needSign, Str('-'), Str(' ')), s) } } private def digit(d: UInt): UInt = Mux(d < UInt(10), Str('0')+d, Str(('a'-10).toChar)+d)(7,0) private def validChar(x: Char) = x == (x & 0xFF) } object Split { // is there a better way to do do this? def apply(x: Bits, n0: Int) = { val w = checkWidth(x, n0) (x(w-1,n0), x(n0-1,0)) } def apply(x: Bits, n1: Int, n0: Int) = { val w = checkWidth(x, n1, n0) (x(w-1,n1), x(n1-1,n0), x(n0-1,0)) } def apply(x: Bits, n2: Int, n1: Int, n0: Int) = { val w = checkWidth(x, n2, n1, n0) (x(w-1,n2), x(n2-1,n1), x(n1-1,n0), x(n0-1,0)) } private def checkWidth(x: Bits, n: Int*) = { val w = x.getWidth def decreasing(x: Seq[Int]): Boolean = if (x.tail.isEmpty) true else x.head >= x.tail.head && decreasing(x.tail) require(decreasing(w :: n.toList)) w } } object Random { def apply(mod: Int, random: UInt): UInt = { if (isPow2(mod)) random(log2Up(mod)-1,0) else PriorityEncoder(partition(apply(1 << log2Up(mod*8), random), mod)) } def apply(mod: Int): UInt = apply(mod, randomizer) def oneHot(mod: Int, random: UInt): UInt = { if (isPow2(mod)) UIntToOH(random(log2Up(mod)-1,0)) else PriorityEncoderOH(partition(apply(1 << log2Up(mod*8), random), mod)).asUInt } def oneHot(mod: Int): UInt = oneHot(mod, randomizer) private def randomizer = LFSR16() private def round(x: Double): Int = if (x.toInt.toDouble == x) x.toInt else (x.toInt + 1) & -2 private def partition(value: UInt, slices: Int) = Seq.tabulate(slices)(i => value < UInt(round((i << value.getWidth).toDouble / slices))) } object Majority { def apply(in: Set[Bool]): Bool = { val n = (in.size >> 1) + 1 val clauses = in.subsets(n).map(_.reduce(_ && _)) clauses.reduce(_ || _) } def apply(in: Seq[Bool]): Bool = apply(in.toSet) def apply(in: UInt): Bool = apply(in.toBools.toSet) } object PopCountAtLeast { private def two(x: UInt): (Bool, Bool) = x.getWidth match { case 1 => (x.toBool, Bool(false)) case n => val half = x.getWidth / 2 val (leftOne, leftTwo) = two(x(half - 1, 0)) val (rightOne, rightTwo) = two(x(x.getWidth - 1, half)) (leftOne || rightOne, leftTwo || rightTwo || (leftOne && rightOne)) } def apply(x: UInt, n: Int): Bool = n match { case 0 => Bool(true) case 1 => x.orR case 2 => two(x)._2 case 3 => PopCount(x) >= UInt(n) } } // This gets used everywhere, so make the smallest circuit possible ... // Given an address and size, create a mask of beatBytes size // eg: (0x3, 0, 4) => 0001, (0x3, 1, 4) => 0011, (0x3, 2, 4) => 1111 // groupBy applies an interleaved OR reduction; groupBy=2 take 0010 => 01 object MaskGen { def apply(addr_lo: UInt, lgSize: UInt, beatBytes: Int, groupBy: Int = 1): UInt = { require (groupBy >= 1 && beatBytes >= groupBy) require (isPow2(beatBytes) && isPow2(groupBy)) val lgBytes = log2Ceil(beatBytes) val sizeOH = UIntToOH(lgSize, log2Up(beatBytes)) | UInt(groupBy*2 - 1) def helper(i: Int): Seq[(Bool, Bool)] = { if (i == 0) { Seq((lgSize >= UInt(lgBytes), Bool(true))) } else { val sub = helper(i-1) val size = sizeOH(lgBytes - i) val bit = addr_lo(lgBytes - i) val nbit = !bit Seq.tabulate (1 << i) { j => val (sub_acc, sub_eq) = sub(j/2) val eq = sub_eq && (if (j % 2 == 1) bit else nbit) val acc = sub_acc || (size && eq) (acc, eq) } } } if (groupBy == beatBytes) UInt(1) else Cat(helper(lgBytes-log2Ceil(groupBy)).map(_._1).reverse) } }