summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/Chisel/Bits.scala
diff options
context:
space:
mode:
authorducky2016-05-05 11:50:39 -0700
committerducky2016-05-05 11:50:39 -0700
commit9036d96bb032c19de31131f2296120e708cbc3dc (patch)
treecf17173fab309b09670ca7529680e09d61341451 /chiselFrontend/src/main/scala/Chisel/Bits.scala
parent623a301df1f5a1954f8e4a64ef97c99c3900da28 (diff)
Move Chisel API into separate chiselFrontend compilation unit in preparation for source locator macros
Diffstat (limited to 'chiselFrontend/src/main/scala/Chisel/Bits.scala')
-rw-r--r--chiselFrontend/src/main/scala/Chisel/Bits.scala571
1 files changed, 571 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/Chisel/Bits.scala b/chiselFrontend/src/main/scala/Chisel/Bits.scala
new file mode 100644
index 00000000..44d9b660
--- /dev/null
+++ b/chiselFrontend/src/main/scala/Chisel/Bits.scala
@@ -0,0 +1,571 @@
+// See LICENSE for license details.
+
+package Chisel
+
+import internal._
+import internal.Builder.pushOp
+import internal.firrtl._
+import firrtl.PrimOp._
+
+/** Element is a leaf data type: it cannot contain other Data objects. Example
+ * uses are for representing primitive data types, like integers and bits.
+ */
+abstract class Element(dirArg: Direction, val width: Width) extends Data(dirArg)
+
+/** A data type for values represented by a single bitvector. Provides basic
+ * bitwise operations.
+ */
+sealed abstract class Bits(dirArg: Direction, width: Width, override val litArg: Option[LitArg])
+ extends Element(dirArg, width) {
+ // TODO: perhaps make this concrete?
+ // Arguments for: self-checking code (can't do arithmetic on bits)
+ // Arguments against: generates down to a FIRRTL UInt anyways
+
+ private[Chisel] def fromInt(x: BigInt): this.type
+
+ private[Chisel] def flatten: IndexedSeq[Bits] = IndexedSeq(this)
+
+ def cloneType: this.type = cloneTypeWidth(width)
+
+ override def <> (that: Data): Unit = this := that
+
+ def tail(n: Int): UInt = {
+ val w = width match {
+ case KnownWidth(x) =>
+ require(x >= n, s"Can't tail($n) for width $x < $n")
+ Width(x - n)
+ case UnknownWidth() => Width()
+ }
+ binop(UInt(width = w), TailOp, n)
+ }
+
+ def head(n: Int): UInt = {
+ width match {
+ case KnownWidth(x) => require(x >= n, s"Can't head($n) for width $x < $n")
+ case UnknownWidth() =>
+ }
+ binop(UInt(width = n), HeadOp, n)
+ }
+
+ /** Returns the specified bit on this wire as a [[Bool]], statically
+ * addressed.
+ */
+ final def apply(x: BigInt): Bool = {
+ if (x < 0) {
+ Builder.error(s"Negative bit indices are illegal (got $x)")
+ }
+ if (isLit()) {
+ Bool(((litValue() >> x.toInt) & 1) == 1)
+ } else {
+ pushOp(DefPrim(Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x)))
+ }
+ }
+
+ /** Returns the specified bit on this wire as a [[Bool]], statically
+ * addressed.
+ *
+ * @note convenience method allowing direct use of Ints without implicits
+ */
+ final def apply(x: Int): Bool =
+ apply(BigInt(x))
+
+ /** Returns the specified bit on this wire as a [[Bool]], dynamically
+ * addressed.
+ */
+ final def apply(x: UInt): Bool =
+ (this >> x)(0)
+
+ /** Returns a subset of bits on this wire from `hi` to `lo` (inclusive),
+ * statically addressed.
+ *
+ * @example
+ * {{{
+ * myBits = 0x5 = 0b101
+ * myBits(1,0) => 0b01 // extracts the two least significant bits
+ * }}}
+ */
+ final def apply(x: Int, y: Int): UInt = {
+ if (x < y || y < 0) {
+ Builder.error(s"Invalid bit range ($x,$y)")
+ }
+ val w = x - y + 1
+ if (isLit()) {
+ UInt((litValue >> y) & ((BigInt(1) << w) - 1), w)
+ } else {
+ pushOp(DefPrim(UInt(width = w), BitsExtractOp, this.ref, ILit(x), ILit(y)))
+ }
+ }
+
+ // REVIEW TODO: again, is this necessary? Or just have this and use implicits?
+ final def apply(x: BigInt, y: BigInt): UInt = apply(x.toInt, y.toInt)
+
+ private[Chisel] def unop[T <: Data](dest: T, op: PrimOp): T =
+ pushOp(DefPrim(dest, op, this.ref))
+ private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: BigInt): T =
+ pushOp(DefPrim(dest, op, this.ref, ILit(other)))
+ private[Chisel] def binop[T <: Data](dest: T, op: PrimOp, other: Bits): T =
+ pushOp(DefPrim(dest, op, this.ref, other.ref))
+ private[Chisel] def compop(op: PrimOp, other: Bits): Bool =
+ pushOp(DefPrim(Bool(), op, this.ref, other.ref))
+ private[Chisel] def redop(op: PrimOp): Bool =
+ pushOp(DefPrim(Bool(), op, this.ref))
+
+ /** Returns this wire zero padded up to the specified width.
+ *
+ * @note for SInts only, this does sign extension
+ */
+ def pad (other: Int): this.type = binop(cloneTypeWidth(this.width max Width(other)), PadOp, other)
+
+ /** Shift left operation */
+ // REVIEW TODO: redundant
+ // REVIEW TODO: should these return this.type or Bits?
+ def << (other: BigInt): Bits
+
+ /** Returns this wire statically left shifted by the specified amount,
+ * inserting zeros into the least significant bits.
+ *
+ * The width of the output is `other` larger than the input.
+ */
+ def << (other: Int): Bits
+
+ /** Returns this wire dynamically left shifted by the specified amount,
+ * inserting zeros into the least significant bits.
+ *
+ * The width of the output is `pow(2, width(other))` larger than the input.
+ */
+ def << (other: UInt): Bits
+
+ /** Shift right operation */
+ // REVIEW TODO: redundant
+ def >> (other: BigInt): Bits
+
+ /** Returns this wire statically right shifted by the specified amount,
+ * inserting zeros into the most significant bits.
+ *
+ * The width of the output is the same as the input.
+ */
+ def >> (other: Int): Bits
+
+ /** Returns this wire dynamically right shifted by the specified amount,
+ * inserting zeros into the most significant bits.
+ *
+ * The width of the output is the same as the input.
+ */
+ def >> (other: UInt): Bits
+
+ /** Returns the contents of this wire as a [[Vec]] of [[Bool]]s.
+ */
+ def toBools: Vec[Bool] = Vec.tabulate(this.getWidth)(i => this(i))
+
+ /** Reinterpret cast to a SInt.
+ *
+ * @note value not guaranteed to be preserved: for example, an UInt of width
+ * 3 and value 7 (0b111) would become a SInt with value -1
+ */
+ def asSInt(): SInt
+
+ /** Reinterpret cast to an UInt.
+ *
+ * @note value not guaranteed to be preserved: for example, a SInt of width
+ * 3 and value -1 (0b111) would become an UInt with value 7
+ */
+ def asUInt(): UInt
+
+ /** Reinterpret cast to Bits. */
+ def asBits(): Bits = asUInt
+
+ @deprecated("Use asSInt, which makes the reinterpret cast more explicit", "chisel3")
+ final def toSInt(): SInt = asSInt
+ @deprecated("Use asUInt, which makes the reinterpret cast more explicit", "chisel3")
+ final def toUInt(): UInt = asUInt
+
+ def toBool(): Bool = width match {
+ case KnownWidth(1) => this(0)
+ case _ => throwException(s"can't covert UInt<$width> to Bool")
+ }
+
+ /** Returns this wire concatenated with `other`, where this wire forms the
+ * most significant part and `other` forms the least significant part.
+ *
+ * The width of the output is sum of the inputs.
+ */
+ def ## (other: Bits): UInt = {
+ val w = this.width + other.width
+ pushOp(DefPrim(UInt(w), ConcatOp, this.ref, other.ref))
+ }
+
+ @deprecated("Use asBits, which makes the reinterpret cast more explicit and actually returns Bits", "chisel3")
+ override def toBits: UInt = asUInt
+
+ override def fromBits(n: Bits): this.type = {
+ val res = Wire(this).asInstanceOf[this.type]
+ res := n
+ res
+ }
+}
+
+/** Provides a set of operations to create UInt types and literals.
+ * Identical in functionality to the UInt companion object.
+ */
+object Bits extends UIntFactory
+
+// REVIEW TODO: Further discussion needed on what Num actually is.
+/** Abstract trait defining operations available on numeric-like wire data
+ * types.
+ */
+abstract trait Num[T <: Data] {
+ // def << (b: T): T
+ // def >> (b: T): T
+ //def unary_-(): T
+
+ // REVIEW TODO: double check ops conventions against FIRRTL
+
+ /** Outputs the sum of `this` and `b`. The resulting width is the max of the
+ * operands plus 1 (should not overflow).
+ */
+ def + (b: T): T
+
+ /** Outputs the product of `this` and `b`. The resulting width is the sum of
+ * the operands.
+ *
+ * @note can generate a single-cycle multiplier, which can result in
+ * significant cycle time and area costs
+ */
+ def * (b: T): T
+
+ /** Outputs the quotient of `this` and `b`.
+ *
+ * TODO: full rules
+ */
+ def / (b: T): T
+
+ def % (b: T): T
+
+ /** Outputs the difference of `this` and `b`. The resulting width is the max
+ * of the operands plus 1 (should not overflow).
+ */
+ def - (b: T): T
+
+ /** Outputs true if `this` < `b`.
+ */
+ def < (b: T): Bool
+
+ /** Outputs true if `this` <= `b`.
+ */
+ def <= (b: T): Bool
+
+ /** Outputs true if `this` > `b`.
+ */
+ def > (b: T): Bool
+
+ /** Outputs true if `this` >= `b`.
+ */
+ def >= (b: T): Bool
+
+ /** Outputs the minimum of `this` and `b`. The resulting width is the max of
+ * the operands.
+ */
+ def min(b: T): T = Mux(this < b, this.asInstanceOf[T], b)
+
+ /** Outputs the maximum of `this` and `b`. The resulting width is the max of
+ * the operands.
+ */
+ def max(b: T): T = Mux(this < b, b, this.asInstanceOf[T])
+}
+
+/** A data type for unsigned integers, represented as a binary bitvector.
+ * Defines arithmetic operations between other integer types.
+ */
+sealed class UInt private[Chisel] (dir: Direction, width: Width, lit: Option[ULit] = None)
+ extends Bits(dir, width, lit) with Num[UInt] {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type =
+ new UInt(dir, w).asInstanceOf[this.type]
+ private[Chisel] def toType = s"UInt$width"
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = UInt(value).asInstanceOf[this.type]
+
+ override def := (that: Data): Unit = that match {
+ case _: UInt => this connect that
+ case _ => this badConnect that
+ }
+
+ // TODO: refactor to share documentation with Num or add independent scaladoc
+ def unary_- : UInt = UInt(0) - this
+ def unary_-% : UInt = UInt(0) -% this
+ def +& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), AddOp, other)
+ def + (other: UInt): UInt = this +% other
+ def +% (other: UInt): UInt = (this +& other) tail 1
+ def -& (other: UInt): UInt = binop(UInt((this.width max other.width) + 1), SubOp, other)
+ def - (other: UInt): UInt = this -% other
+ def -% (other: UInt): UInt = (this -& other) tail 1
+ def * (other: UInt): UInt = binop(UInt(this.width + other.width), TimesOp, other)
+ def * (other: SInt): SInt = other * this
+ def / (other: UInt): UInt = binop(UInt(this.width), DivideOp, other)
+ def % (other: UInt): UInt = binop(UInt(this.width), RemOp, other)
+
+ def & (other: UInt): UInt = binop(UInt(this.width max other.width), BitAndOp, other)
+ def | (other: UInt): UInt = binop(UInt(this.width max other.width), BitOrOp, other)
+ def ^ (other: UInt): UInt = binop(UInt(this.width max other.width), BitXorOp, other)
+
+ /** Returns this wire bitwise-inverted. */
+ def unary_~ : UInt = unop(UInt(width = width), BitNotOp)
+
+ // REVIEW TODO: Can this be defined on Bits?
+ def orR: Bool = this != UInt(0)
+ def andR: Bool = ~this === UInt(0)
+ def xorR: Bool = redop(XorReduceOp)
+
+ def < (other: UInt): Bool = compop(LessOp, other)
+ def > (other: UInt): Bool = compop(GreaterOp, other)
+ def <= (other: UInt): Bool = compop(LessEqOp, other)
+ def >= (other: UInt): Bool = compop(GreaterEqOp, other)
+ def != (other: UInt): Bool = compop(NotEqualOp, other)
+ def =/= (other: UInt): Bool = compop(NotEqualOp, other)
+ def === (other: UInt): Bool = compop(EqualOp, other)
+ def unary_! : Bool = this === Bits(0)
+
+ // REVIEW TODO: Can these also not be defined on Bits?
+ def << (other: Int): UInt = binop(UInt(this.width + other), ShiftLeftOp, other)
+ def << (other: BigInt): UInt = this << other.toInt
+ def << (other: UInt): UInt = binop(UInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other)
+ def >> (other: Int): UInt = binop(UInt(this.width.shiftRight(other)), ShiftRightOp, other)
+ def >> (other: BigInt): UInt = this >> other.toInt
+ def >> (other: UInt): UInt = binop(UInt(this.width), DynamicShiftRightOp, other)
+
+ def bitSet(off: UInt, dat: Bool): UInt = {
+ val bit = UInt(1, 1) << off
+ Mux(dat, this | bit, ~(~this | bit))
+ }
+
+ def === (that: BitPat): Bool = that === this
+ def != (that: BitPat): Bool = that != this
+ def =/= (that: BitPat): Bool = that =/= this
+
+ /** Returns this UInt as a [[SInt]] with an additional zero in the MSB.
+ */
+ // TODO: this eventually will be renamed as toSInt, once the existing toSInt
+ // completes its deprecation phase.
+ def zext(): SInt = pushOp(DefPrim(SInt(width + 1), ConvertOp, ref))
+
+ /** Returns this UInt as a [[SInt]], without changing width or bit value. The
+ * SInt is not guaranteed to have the same value (for example, if the MSB is
+ * high, it will be interpreted as a negative value).
+ */
+ def asSInt(): SInt = pushOp(DefPrim(SInt(width), AsSIntOp, ref))
+
+ def asUInt(): UInt = this
+}
+
+// This is currently a factory because both Bits and UInt inherit it.
+private[Chisel] sealed trait UIntFactory {
+ /** Create a UInt type with inferred width. */
+ def apply(): UInt = apply(NO_DIR, Width())
+ /** Create a UInt type or port with fixed width. */
+ def apply(dir: Direction = NO_DIR, width: Int): UInt = apply(dir, Width(width))
+ /** Create a UInt port with inferred width. */
+ def apply(dir: Direction): UInt = apply(dir, Width())
+
+ /** Create a UInt literal with inferred width. */
+ def apply(value: BigInt): UInt = apply(value, Width())
+ /** Create a UInt literal with fixed width. */
+ def apply(value: BigInt, width: Int): UInt = apply(value, Width(width))
+ /** Create a UInt literal with inferred width. */
+ def apply(n: String): UInt = apply(parse(n), parsedWidth(n))
+ /** Create a UInt literal with fixed width. */
+ def apply(n: String, width: Int): UInt = apply(parse(n), width)
+
+ /** Create a UInt type with specified width. */
+ def apply(width: Width): UInt = apply(NO_DIR, width)
+ /** Create a UInt port with specified width. */
+ def apply(dir: Direction, width: Width): UInt = new UInt(dir, width)
+ /** Create a UInt literal with specified width. */
+ def apply(value: BigInt, width: Width): UInt = {
+ val lit = ULit(value, width)
+ new UInt(NO_DIR, lit.width, Some(lit))
+ }
+
+ private def parse(n: String) = {
+ val (base, num) = n.splitAt(1)
+ val radix = base match {
+ case "x" | "h" => 16
+ case "d" => 10
+ case "o" => 8
+ case "b" => 2
+ case _ => Builder.error(s"Invalid base $base"); 2
+ }
+ BigInt(num.filterNot(_ == '_'), radix)
+ }
+
+ private def parsedWidth(n: String) =
+ if (n(0) == 'b') {
+ Width(n.length-1)
+ } else if (n(0) == 'h') {
+ Width((n.length-1) * 4)
+ } else {
+ Width()
+ }
+}
+
+object UInt extends UIntFactory
+
+sealed class SInt private (dir: Direction, width: Width, lit: Option[SLit] = None)
+ extends Bits(dir, width, lit) with Num[SInt] {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type =
+ new SInt(dir, w).asInstanceOf[this.type]
+ private[Chisel] def toType = s"SInt$width"
+
+ override def := (that: Data): Unit = that match {
+ case _: SInt => this connect that
+ case _ => this badConnect that
+ }
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = SInt(value).asInstanceOf[this.type]
+
+ def unary_- : SInt = SInt(0) - this
+ def unary_-% : SInt = SInt(0) -% this
+ /** add (width +1) operator */
+ def +& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), AddOp, other)
+ /** add (default - no growth) operator */
+ def + (other: SInt): SInt = this +% other
+ /** add (no growth) operator */
+ def +% (other: SInt): SInt = (this +& other).tail(1).asSInt
+ /** subtract (width +1) operator */
+ def -& (other: SInt): SInt = binop(SInt((this.width max other.width) + 1), SubOp, other)
+ /** subtract (default - no growth) operator */
+ def - (other: SInt): SInt = this -% other
+ /** subtract (no growth) operator */
+ def -% (other: SInt): SInt = (this -& other).tail(1).asSInt
+ def * (other: SInt): SInt = binop(SInt(this.width + other.width), TimesOp, other)
+ def * (other: UInt): SInt = binop(SInt(this.width + other.width), TimesOp, other)
+ def / (other: SInt): SInt = binop(SInt(this.width), DivideOp, other)
+ def % (other: SInt): SInt = binop(SInt(this.width), RemOp, other)
+
+ def & (other: SInt): SInt = binop(UInt(this.width max other.width), BitAndOp, other).asSInt
+ def | (other: SInt): SInt = binop(UInt(this.width max other.width), BitOrOp, other).asSInt
+ def ^ (other: SInt): SInt = binop(UInt(this.width max other.width), BitXorOp, other).asSInt
+
+ /** Returns this wire bitwise-inverted. */
+ def unary_~ : SInt = unop(UInt(width = width), BitNotOp).asSInt
+
+ def < (other: SInt): Bool = compop(LessOp, other)
+ def > (other: SInt): Bool = compop(GreaterOp, other)
+ def <= (other: SInt): Bool = compop(LessEqOp, other)
+ def >= (other: SInt): Bool = compop(GreaterEqOp, other)
+ def != (other: SInt): Bool = compop(NotEqualOp, other)
+ def =/= (other: SInt): Bool = compop(NotEqualOp, other)
+ def === (other: SInt): Bool = compop(EqualOp, other)
+ def abs(): UInt = Mux(this < SInt(0), (-this).asUInt, this.asUInt)
+
+ def << (other: Int): SInt = binop(SInt(this.width + other), ShiftLeftOp, other)
+ def << (other: BigInt): SInt = this << other.toInt
+ def << (other: UInt): SInt = binop(SInt(this.width.dynamicShiftLeft(other.width)), DynamicShiftLeftOp, other)
+ def >> (other: Int): SInt = binop(SInt(this.width.shiftRight(other)), ShiftRightOp, other)
+ def >> (other: BigInt): SInt = this >> other.toInt
+ def >> (other: UInt): SInt = binop(SInt(this.width), DynamicShiftRightOp, other)
+
+ def asUInt(): UInt = pushOp(DefPrim(UInt(this.width), AsUIntOp, ref))
+ def asSInt(): SInt = this
+}
+
+object SInt {
+ /** Create an SInt type with inferred width. */
+ def apply(): SInt = apply(NO_DIR, Width())
+ /** Create an SInt type or port with fixed width. */
+ def apply(dir: Direction = NO_DIR, width: Int): SInt = apply(dir, Width(width))
+ /** Create an SInt port with inferred width. */
+ def apply(dir: Direction): SInt = apply(dir, Width())
+
+ /** Create an SInt literal with inferred width. */
+ def apply(value: BigInt): SInt = apply(value, Width())
+ /** Create an SInt literal with fixed width. */
+ def apply(value: BigInt, width: Int): SInt = apply(value, Width(width))
+
+ /** Create an SInt type with specified width. */
+ def apply(width: Width): SInt = new SInt(NO_DIR, width)
+ /** Create an SInt port with specified width. */
+ def apply(dir: Direction, width: Width): SInt = new SInt(dir, width)
+ /** Create an SInt literal with specified width. */
+ def apply(value: BigInt, width: Width): SInt = {
+ val lit = SLit(value, width)
+ new SInt(NO_DIR, lit.width, Some(lit))
+ }
+}
+
+// REVIEW TODO: Why does this extend UInt and not Bits? Does defining airth
+// operations on a Bool make sense?
+/** A data type for booleans, defined as a single bit indicating true or false.
+ */
+sealed class Bool(dir: Direction, lit: Option[ULit] = None) extends UInt(dir, Width(1), lit) {
+ private[Chisel] override def cloneTypeWidth(w: Width): this.type = {
+ require(!w.known || w.get == 1)
+ new Bool(dir).asInstanceOf[this.type]
+ }
+
+ override private[Chisel] def fromInt(value: BigInt): this.type = {
+ require(value == 0 || value == 1)
+ Bool(value == 1).asInstanceOf[this.type]
+ }
+
+ // REVIEW TODO: Why does this need to exist and have different conventions
+ // than Bits?
+ def & (other: Bool): Bool = binop(Bool(), BitAndOp, other)
+ def | (other: Bool): Bool = binop(Bool(), BitOrOp, other)
+ def ^ (other: Bool): Bool = binop(Bool(), BitXorOp, other)
+
+ /** Returns this wire bitwise-inverted. */
+ override def unary_~ : Bool = unop(Bool(), BitNotOp)
+
+ /** Outputs the logical OR of two Bools.
+ */
+ def || (that: Bool): Bool = this | that
+
+ /** Outputs the logical AND of two Bools.
+ */
+ def && (that: Bool): Bool = this & that
+}
+
+object Bool {
+ /** Creates an empty Bool.
+ */
+ def apply(dir: Direction = NO_DIR): Bool = new Bool(dir)
+
+ /** Creates Bool literal.
+ */
+ def apply(x: Boolean): Bool = new Bool(NO_DIR, Some(ULit(if (x) 1 else 0, Width(1))))
+}
+
+object Mux {
+ /** Creates a mux, whose output is one of the inputs depending on the
+ * value of the condition.
+ *
+ * @param cond condition determining the input to choose
+ * @param con the value chosen when `cond` is true
+ * @param alt the value chosen when `cond` is false
+ * @example
+ * {{{
+ * val muxOut = Mux(data_in === UInt(3), UInt(3, 4), UInt(0, 4))
+ * }}}
+ */
+ def apply[T <: Data](cond: Bool, con: T, alt: T): T = (con, alt) match {
+ // Handle Mux(cond, UInt, Bool) carefully so that the concrete type is UInt
+ case (c: Bool, a: Bool) => doMux(cond, c, a).asInstanceOf[T]
+ case (c: UInt, a: Bool) => doMux(cond, c, a << 0).asInstanceOf[T]
+ case (c: Bool, a: UInt) => doMux(cond, c << 0, a).asInstanceOf[T]
+ case (c: Bits, a: Bits) => doMux(cond, c, a).asInstanceOf[T]
+ case _ => doAggregateMux(cond, con, alt)
+ }
+
+ private def doMux[T <: Data](cond: Bool, con: T, alt: T): T = {
+ require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}")
+ val d = alt.cloneTypeWidth(con.width max alt.width)
+ pushOp(DefPrim(d, MultiplexOp, cond.ref, con.ref, alt.ref))
+ }
+
+ private def doAggregateMux[T <: Data](cond: Bool, con: T, alt: T): T = {
+ require(con.getClass == alt.getClass, s"can't Mux between ${con.getClass} and ${alt.getClass}")
+ for ((c, a) <- con.flatten zip alt.flatten)
+ require(c.width == a.width, "can't Mux between aggregates of different width")
+ doMux(cond, con, alt)
+ }
+}
+