diff options
| author | Aditya Naik | 2024-05-03 10:59:45 -0700 |
|---|---|---|
| committer | Aditya Naik | 2024-05-03 10:59:45 -0700 |
| commit | 878d488a7c8e0d6973de58b3164022c6a102e449 (patch) | |
| tree | cd081bbcbe3f797f80b10c2d8153da0069750e51 /core | |
| parent | 8200c0cdf1d471453946d5ae24bc99757b2ef02d (diff) | |
Get cleanup to compile
Diffstat (limited to 'core')
35 files changed, 69 insertions, 5347 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala index dbf6969f..5d460c2d 100644 --- a/core/src/main/scala/chisel3/Aggregate.scala +++ b/core/src/main/scala/chisel3/Aggregate.scala @@ -3,7 +3,6 @@ package chisel3 import chisel3.experimental.VecLiterals.AddVecLiteralConstructor -import chisel3.experimental.dataview.{isView, reifySingleData, InvalidViewException} import scala.collection.immutable.{SeqMap, VectorMap} import scala.collection.mutable.{HashSet, LinkedHashMap} @@ -254,20 +253,6 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) extend requireIsHardware(this, "vec") requireIsHardware(p, "vec index") - // Special handling for views - if (isView(this)) { - reifySingleData(this) match { - // Views complicate things a bit, but views that correspond exactly to an identical Vec can just forward the - // dynamic indexing to the target Vec - // In theory, we could still do this forwarding if the sample element were different by deriving a DataView - case Some(target: Vec[T @unchecked]) - if this.length == target.length && - this.sample_element.typeEquivalent(target.sample_element) => - return target.do_apply(p) - case _ => throw InvalidViewException("Dynamic indexing of Views is not yet supported") - } - } - val port = gen // Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored. diff --git a/core/src/main/scala/chisel3/Annotation.scala b/core/src/main/scala/chisel3/Annotation.scala index c350fb30..d133ab8a 100644 --- a/core/src/main/scala/chisel3/Annotation.scala +++ b/core/src/main/scala/chisel3/Annotation.scala @@ -3,7 +3,7 @@ package chisel3.experimental import scala.language.existentials -import chisel3.internal.{Builder, InstanceId, LegacyModule} +import chisel3.internal.{Builder, InstanceId} import chisel3.{CompileOptions, Data, RawModule} import firrtl.Transform import firrtl.annotations._ diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala index 70704e01..2811f30d 100644 --- a/core/src/main/scala/chisel3/Bits.scala +++ b/core/src/main/scala/chisel3/Bits.scala @@ -4,7 +4,6 @@ package chisel3 import scala.language.experimental.macros -import chisel3.experimental.{FixedPoint, Interval} import chisel3.internal._ import chisel3.internal.Builder.pushOp import chisel3.internal.firrtl._ @@ -383,36 +382,6 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi /** @group SourceInfoTransformMacro */ def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt - /** Reinterpret this $coll as a [[FixedPoint]]. - * - * @note The value is not guaranteed to be preserved. For example, a [[UInt]] of width 3 and value 7 (0b111) would - * become a [[FixedPoint]] with value -1. The interpretation of the number is also affected by the specified binary - * point. '''Caution is advised!''' - */ - final def asFixedPoint(that: BinaryPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_asFixedPoint( - that: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): FixedPoint = { - throwException(s"Cannot call .asFixedPoint on $this") - } - - /** Reinterpret cast as a Interval. - * - * @note value not guaranteed to be preserved: for example, an UInt of width - * 3 and value 7 (0b111) would become a FixedInt with value -1, the interpretation - * of the number is also affected by the specified binary point. Caution advised - */ - final def asInterval(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg - - def do_asInterval(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - throwException(s"Cannot call .asInterval on $this") - } - final def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = { width match { case KnownWidth(1) => this(0) @@ -820,47 +789,7 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = pushOp(DefPrim(sourceInfo, SInt(width), AsSIntOp, ref)) override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this - override def do_asFixedPoint( - binaryPoint: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): FixedPoint = { - binaryPoint match { - case KnownBinaryPoint(value) => - val iLit = ILit(value) - pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit)) - case _ => - throwException( - s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint" - ) - } - } - override def do_asInterval( - range: IntervalRange = IntervalRange.Unknown - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Interval = { - (range.lower, range.upper, range.binaryPoint) match { - case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) => - // No mechanism to pass open/close to firrtl so need to handle directly - val l = lx match { - case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - val u = ux match { - case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp))) - case _ => - throwException(s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range") - } - } private[chisel3] override def connectFromBits( that: Bits )( @@ -1112,49 +1041,6 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref) ) override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = this - override def do_asFixedPoint( - binaryPoint: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): FixedPoint = { - binaryPoint match { - case KnownBinaryPoint(value) => - val iLit = ILit(value) - pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit)) - case _ => - throwException( - s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint" - ) - } - } - - override def do_asInterval( - range: IntervalRange = IntervalRange.Unknown - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Interval = { - (range.lower, range.upper, range.binaryPoint) match { - case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) => - // No mechanism to pass open/close to firrtl so need to handle directly - val l = lx match { - case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - val u = ux match { - case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - //TODO: (chick) Need to determine, what asInterval needs, and why it might need min and max as args -- CAN IT BE UNKNOWN? - // Angie's operation: Decimal -> Int -> Decimal loses information. Need to be conservative here? - val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp))) - case _ => - throwException(s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range") - } - } private[chisel3] override def connectFromBits( that: Bits @@ -1395,7 +1281,6 @@ sealed class Bool() extends UInt(1.W) with Reset { package experimental { import chisel3.internal.firrtl.BinaryPoint - import chisel3.internal.requireIsHardware // Fix ambiguous import /** Chisel types that have binary points support retrieving * literal values as `Double` or `BigDecimal` @@ -1434,1188 +1319,4 @@ package experimental { */ def litToBigDecimal: BigDecimal = litToBigDecimalOption.get } - - /** A sealed class representing a fixed point number that has a bit width and a binary point The width and binary point - * may be inferred. - * - * IMPORTANT: The API provided here is experimental and may change in the future. - * - * @param width bit width of the fixed point number - * @param binaryPoint the position of the binary point with respect to the right most bit of the width currently this - * should be positive but it is hoped to soon support negative points and thus use this field as a - * simple exponent - * @define coll [[FixedPoint]] - * @define numType $coll - * @define expandingWidth @note The width of the returned $coll is `width of this` + `1`. - * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`. - */ - sealed class FixedPoint private (width: Width, val binaryPoint: BinaryPoint) - extends Bits(width) - with Num[FixedPoint] - with HasBinaryPoint { - - override def toString: String = { - litToDoubleOption match { - case Some(value) => s"FixedPoint$width$binaryPoint($value)" - case _ => stringAccessor(s"FixedPoint$width$binaryPoint") - } - } - - private[chisel3] override def typeEquivalent(that: Data): Boolean = that match { - case that: FixedPoint => - this.width == that.width && this.binaryPoint == that.binaryPoint // TODO: should this be true for unspecified widths? - case _ => false - } - - private[chisel3] override def cloneTypeWidth(w: Width): this.type = - new FixedPoint(w, binaryPoint).asInstanceOf[this.type] - - override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = - that match { - case _: FixedPoint | DontCare => super.connect(that) - case _ => this.badConnect(that) - } - - /** Unary negation (expanding width) - * - * @return a hardware $coll equal to zero minus this $coll - * $expandingWidth - * @group Arithmetic - */ - final def unary_- : FixedPoint = macro SourceInfoTransform.noArg - - @deprecated( - "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", - "Chisel 3.5" - ) - final def unary_-(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy - - /** Unary negation (constant width) - * - * @return a hardware $coll equal to zero minus `this` shifted right by one - * $constantWidth - * @group Arithmetic - */ - final def unary_-% : FixedPoint = macro SourceInfoTransform.noArg - @deprecated( - "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", - "Chisel 3.5" - ) - final def unary_-%(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy - - /** @group SourceInfoTransformMacro */ - def do_unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - FixedPoint.fromBigInt(0) - this - - /** @group SourceInfoTransformMacro */ - def do_unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - FixedPoint.fromBigInt(0) -% this - - /** add (default - no growth) operator */ - override def do_+(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - this +% that - - /** subtract (default - no growth) operator */ - override def do_-(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - this -% that - override def do_*(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width + that.width, this.binaryPoint + that.binaryPoint), TimesOp, that) - override def do_/(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"division is illegal on FixedPoint types") - override def do_%(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"mod is illegal on FixedPoint types") - - /** Multiplication operator - * - * @param that a hardware [[UInt]] - * @return the product of this $coll and `that` - * $sumWidth - * $singleCycleMul - * @group Arithmetic - */ - final def *(that: UInt): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_*(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width + that.width, binaryPoint), TimesOp, that) - - /** Multiplication operator - * - * @param that a hardware [[SInt]] - * @return the product of this $coll and `that` - * $sumWidth - * $singleCycleMul - * @group Arithmetic - */ - final def *(that: SInt): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_*(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width + that.width, binaryPoint), TimesOp, that) - - /** Addition operator (expanding width) - * - * @param that a hardware $coll - * @return the sum of this $coll and `that` - * $maxWidthPlusOne - * @group Arithmetic - */ - final def +&(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** Addition operator (constant width) - * - * @param that a hardware $coll - * @return the sum of this $coll and `that` shifted right by one - * $maxWidth - * @group Arithmetic - */ - final def +%(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** Subtraction operator (increasing width) - * - * @param that a hardware $coll - * @return the difference of this $coll less `that` - * $maxWidthPlusOne - * @group Arithmetic - */ - final def -&(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** Subtraction operator (constant width) - * - * @param that a hardware $coll - * @return the difference of this $coll less `that` shifted right by one - * $maxWidth - * @group Arithmetic - */ - final def -%(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_+&(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = { - (this.width, that.width, this.binaryPoint, that.binaryPoint) match { - case (KnownWidth(thisWidth), KnownWidth(thatWidth), KnownBinaryPoint(thisBP), KnownBinaryPoint(thatBP)) => - val thisIntWidth = thisWidth - thisBP - val thatIntWidth = thatWidth - thatBP - val newBinaryPoint = thisBP.max(thatBP) - val newWidth = (thisIntWidth.max(thatIntWidth)) + newBinaryPoint + 1 - binop(sourceInfo, FixedPoint(newWidth.W, newBinaryPoint.BP), AddOp, that) - case _ => - val newBinaryPoint = this.binaryPoint.max(that.binaryPoint) - binop(sourceInfo, FixedPoint(UnknownWidth(), newBinaryPoint), AddOp, that) - } - } - - /** @group SourceInfoTransformMacro */ - def do_+%(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - (this +& that).tail(1).asFixedPoint(this.binaryPoint.max(that.binaryPoint)) - - /** @group SourceInfoTransformMacro */ - def do_-&(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = { - (this.width, that.width, this.binaryPoint, that.binaryPoint) match { - case (KnownWidth(thisWidth), KnownWidth(thatWidth), KnownBinaryPoint(thisBP), KnownBinaryPoint(thatBP)) => - val thisIntWidth = thisWidth - thisBP - val thatIntWidth = thatWidth - thatBP - val newBinaryPoint = thisBP.max(thatBP) - val newWidth = (thisIntWidth.max(thatIntWidth)) + newBinaryPoint + 1 - binop(sourceInfo, FixedPoint(newWidth.W, newBinaryPoint.BP), SubOp, that) - case _ => - val newBinaryPoint = this.binaryPoint.max(that.binaryPoint) - binop(sourceInfo, FixedPoint(UnknownWidth(), newBinaryPoint), SubOp, that) - } - } - - /** @group SourceInfoTransformMacro */ - def do_-%(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - (this -& that).tail(1).asFixedPoint(this.binaryPoint.max(that.binaryPoint)) - - /** Bitwise and operator - * - * @param that a hardware $coll - * @return the bitwise and of this $coll and `that` - * $maxWidth - * @group Bitwise - */ - final def &(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** Bitwise or operator - * - * @param that a hardware $coll - * @return the bitwise or of this $coll and `that` - * $maxWidth - * @group Bitwise - */ - final def |(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** Bitwise exclusive or (xor) operator - * - * @param that a hardware $coll - * @return the bitwise xor of this $coll and `that` - * $maxWidth - * @group Bitwise - */ - final def ^(that: FixedPoint): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_&(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"And is illegal between $this and $that") - - /** @group SourceInfoTransformMacro */ - def do_|(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"Or is illegal between $this and $that") - - /** @group SourceInfoTransformMacro */ - def do_^(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"Xor is illegal between $this and $that") - - final def setBinaryPoint(that: Int): FixedPoint = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_setBinaryPoint(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - this.binaryPoint match { - case KnownBinaryPoint(value) => - binop(sourceInfo, FixedPoint(this.width + (that - value), KnownBinaryPoint(that)), SetBinaryPoint, that) - case _ => - binop(sourceInfo, FixedPoint(UnknownWidth(), KnownBinaryPoint(that)), SetBinaryPoint, that) - } - - /** @group SourceInfoTransformMacro */ - def do_unary_~(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - throwException(s"Not is illegal on $this") - - override def do_<(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, LessOp, that) - override def do_>(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, GreaterOp, that) - override def do_<=(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, LessEqOp, that) - override def do_>=(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, GreaterEqOp, that) - - final def !=(that: FixedPoint): Bool = macro SourceInfoTransform.thatArg - - /** Dynamic not equals operator - * - * @param that a hardware $coll - * @return a hardware [[Bool]] asserted if this $coll is not equal to `that` - * @group Comparison - */ - final def =/=(that: FixedPoint): Bool = macro SourceInfoTransform.thatArg - - /** Dynamic equals operator - * - * @param that a hardware $coll - * @return a hardware [[Bool]] asserted if this $coll is equal to `that` - * @group Comparison - */ - final def ===(that: FixedPoint): Bool = macro SourceInfoTransform.thatArg - - /** @group SourceInfoTransformMacro */ - def do_!=(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, NotEqualOp, that) - - /** @group SourceInfoTransformMacro */ - def do_=/=(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, NotEqualOp, that) - - /** @group SourceInfoTransformMacro */ - def do_===(that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, EqualOp, that) - - def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = { - // TODO: remove this once we have CompileOptions threaded through the macro system. - import chisel3.ExplicitCompileOptions.NotStrict - Mux(this < 0.F(0.BP), 0.F(0.BP) - this, this) - } - - override def do_<<(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width + that, this.binaryPoint), ShiftLeftOp, validateShiftAmount(that)) - override def do_<<(that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - (this << castToInt(that, "Shift amount")).asFixedPoint(this.binaryPoint) - override def do_<<(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width.dynamicShiftLeft(that.width), this.binaryPoint), DynamicShiftLeftOp, that) - override def do_>>(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop( - sourceInfo, - FixedPoint(this.width.shiftRight(that), this.binaryPoint), - ShiftRightOp, - validateShiftAmount(that) - ) - override def do_>>(that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - (this >> castToInt(that, "Shift amount")).asFixedPoint(this.binaryPoint) - override def do_>>(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = - binop(sourceInfo, FixedPoint(this.width, this.binaryPoint), DynamicShiftRightOp, that) - - override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = pushOp( - DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref) - ) - override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = pushOp( - DefPrim(sourceInfo, SInt(this.width), AsSIntOp, ref) - ) - - override def do_asFixedPoint( - binaryPoint: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): FixedPoint = { - binaryPoint match { - case KnownBinaryPoint(value) => - val iLit = ILit(value) - pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit)) - case _ => - throwException( - s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint" - ) - } - } - - def do_asInterval( - binaryPoint: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Interval = { - throwException(s"cannot call $this.asInterval(binaryPoint=$binaryPoint), you must specify a range") - } - - override def do_asInterval( - range: IntervalRange = IntervalRange.Unknown - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Interval = { - (range.lower, range.upper, range.binaryPoint) match { - case (lx: firrtlconstraint.IsKnown, ux: firrtlconstraint.IsKnown, KnownBinaryPoint(bp)) => - // No mechanism to pass open/close to firrtl so need to handle directly - val l = lx match { - case firrtlir.Open(x) => x + BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - val u = ux match { - case firrtlir.Open(x) => x - BigDecimal(1) / BigDecimal(BigInt(1) << bp) - case firrtlir.Closed(x) => x - } - val minBI = (l * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - val maxBI = (u * BigDecimal(BigInt(1) << bp)).setScale(0, BigDecimal.RoundingMode.FLOOR).toBigIntExact.get - pushOp(DefPrim(sourceInfo, Interval(range), AsIntervalOp, ref, ILit(minBI), ILit(maxBI), ILit(bp))) - case _ => - throwException(s"cannot call $this.asInterval($range), you must specify a known binaryPoint and range") - } - } - - private[chisel3] override def connectFromBits( - that: Bits - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ) { - // TODO: redefine as just asFixedPoint on that, where FixedPoint.asFixedPoint just works. - this := (that match { - case fp: FixedPoint => fp.asSInt.asFixedPoint(this.binaryPoint) - case _ => that.asFixedPoint(this.binaryPoint) - }) - } - } - - /** Use PrivateObject to force users to specify width and binaryPoint by name - */ - sealed trait PrivateType - private case object PrivateObject extends PrivateType - - /** - * Factory and convenience methods for the FixedPoint class - * IMPORTANT: The API provided here is experimental and may change in the future. - */ - object FixedPoint extends NumObject { - - import FixedPoint.Implicits._ - - /** Create an FixedPoint type with inferred width. */ - def apply(): FixedPoint = apply(Width(), BinaryPoint()) - - /** Create an FixedPoint type or port with fixed width. */ - def apply(width: Width, binaryPoint: BinaryPoint): FixedPoint = new FixedPoint(width, binaryPoint) - - /** Create an FixedPoint literal with inferred width from BigInt. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromBigInt(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = { - apply(value, width, binaryPoint) - } - - /** Create an FixedPoint literal with inferred width from BigInt. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromBigInt(value: BigInt, binaryPoint: BinaryPoint = 0.BP): FixedPoint = { - apply(value, Width(), binaryPoint) - } - - /** Create an FixedPoint literal with inferred width from BigInt. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromBigInt(value: BigInt, width: Int, binaryPoint: Int): FixedPoint = - if (width == -1) { - apply(value, Width(), BinaryPoint(binaryPoint)) - } else { - apply(value, Width(width), BinaryPoint(binaryPoint)) - } - - /** Create an FixedPoint literal with inferred width from Double. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromDouble(value: Double, width: Width, binaryPoint: BinaryPoint): FixedPoint = { - fromBigInt( - toBigInt(value, binaryPoint.get), - width = width, - binaryPoint = binaryPoint - ) - } - - /** Create an FixedPoint literal with inferred width from BigDecimal. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromBigDecimal(value: BigDecimal, width: Width, binaryPoint: BinaryPoint): FixedPoint = { - fromBigInt( - toBigInt(value, binaryPoint.get), - width = width, - binaryPoint = binaryPoint - ) - } - - /** Create an FixedPoint port with specified width and binary position. */ - def apply(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = { - val lit = FPLit(value, width, binaryPoint) - val newLiteral = new FixedPoint(lit.width, lit.binaryPoint) - // Ensure we have something capable of generating a name. - lit.bindLitArg(newLiteral) - } - - object Implicits { - - implicit class fromDoubleToLiteral(double: Double) { - def F(binaryPoint: BinaryPoint): FixedPoint = { - FixedPoint.fromDouble(double, Width(), binaryPoint) - } - - def F(width: Width, binaryPoint: BinaryPoint): FixedPoint = { - FixedPoint.fromDouble(double, width, binaryPoint) - } - } - - implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) { - def F(binaryPoint: BinaryPoint): FixedPoint = { - FixedPoint.fromBigDecimal(bigDecimal, Width(), binaryPoint) - } - - def F(width: Width, binaryPoint: BinaryPoint): FixedPoint = { - FixedPoint.fromBigDecimal(bigDecimal, width, binaryPoint) - } - } - } - } - - /** - * A sealed class representing a fixed point number that has a range, an additional - * parameter that can determine a minimum and maximum supported value. - * The range can be used to reduce the required widths particularly in primitive - * operations with other Intervals, the canonical example being - * {{{ - * val one = 1.I - * val six = Seq.fill(6)(one).reduce(_ + _) - * }}} - * A UInt computed in this way would require a [[Width]] - * binary point - * The width and binary point may be inferred. - * - * IMPORTANT: The API provided here is experimental and may change in the future. - * - * @param range a range specifies min, max and binary point - */ - sealed class Interval private[chisel3] (val range: chisel3.internal.firrtl.IntervalRange) - extends Bits(range.getWidth) - with Num[Interval] - with HasBinaryPoint { - - override def toString: String = { - litOption match { - case Some(value) => s"Interval$width($value)" - case _ => stringAccessor(s"Interval$width") - } - } - - private[chisel3] override def cloneTypeWidth(w: Width): this.type = - new Interval(range).asInstanceOf[this.type] - - def toType: String = { - val zdec1 = """([+\-]?[0-9]\d*)(\.[0-9]*[1-9])(0*)""".r - val zdec2 = """([+\-]?[0-9]\d*)(\.0*)""".r - val dec = """([+\-]?[0-9]\d*)(\.[0-9]\d*)""".r - val int = """([+\-]?[0-9]\d*)""".r - def dec2string(v: BigDecimal): String = v.toString match { - case zdec1(x, y, z) => x + y - case zdec2(x, y) => x - case other => other - } - - val lowerString = range.lower match { - case firrtlir.Open(l) => s"(${dec2string(l)}, " - case firrtlir.Closed(l) => s"[${dec2string(l)}, " - case firrtlir.UnknownBound => s"[?, " - case _ => s"[?, " - } - val upperString = range.upper match { - case firrtlir.Open(u) => s"${dec2string(u)})" - case firrtlir.Closed(u) => s"${dec2string(u)}]" - case firrtlir.UnknownBound => s"?]" - case _ => s"?]" - } - val bounds = lowerString + upperString - - val pointString = range.binaryPoint match { - case KnownBinaryPoint(i) => "." + i.toString - case _ => "" - } - "Interval" + bounds + pointString - } - - private[chisel3] override def typeEquivalent(that: Data): Boolean = - that.isInstanceOf[Interval] && this.width == that.width - - def binaryPoint: BinaryPoint = range.binaryPoint - - override def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { - that match { - case _: Interval | DontCare => super.connect(that) - case _ => this.badConnect(that) - } - } - - final def unary_- : Interval = macro SourceInfoTransform.noArg - - @deprecated( - "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", - "Chisel 3.5" - ) - final def unary_-(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy - - final def unary_-% : Interval = macro SourceInfoTransform.noArg - - @deprecated( - "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", - "Chisel 3.5" - ) - final def unary_-%(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy - - /** @group SourceInfoTransformMacro */ - def do_unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - Interval.Zero - this - } - def do_unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - Interval.Zero -% this - } - - /** add (default - growing) operator */ - override def do_+(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - this +& that - - /** subtract (default - growing) operator */ - override def do_-(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - this -& that - override def do_*(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - binop(sourceInfo, Interval(this.range * that.range), TimesOp, that) - - override def do_/(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"division is illegal on Interval types") - override def do_%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"mod is illegal on Interval types") - - /** add (width +1) operator */ - final def +&(that: Interval): Interval = macro SourceInfoTransform.thatArg - - /** add (no growth) operator */ - final def +%(that: Interval): Interval = macro SourceInfoTransform.thatArg - - /** subtract (width +1) operator */ - final def -&(that: Interval): Interval = macro SourceInfoTransform.thatArg - - /** subtract (no growth) operator */ - final def -%(that: Interval): Interval = macro SourceInfoTransform.thatArg - - def do_+&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range +& that.range), AddOp, that) - } - - def do_+%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - throwException(s"Non-growing addition is not supported on Intervals: ${sourceInfo}") - } - - def do_-&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range -& that.range), SubOp, that) - } - - def do_-%(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - throwException(s"Non-growing subtraction is not supported on Intervals: ${sourceInfo}, try squeeze") - } - - final def &(that: Interval): Interval = macro SourceInfoTransform.thatArg - final def |(that: Interval): Interval = macro SourceInfoTransform.thatArg - final def ^(that: Interval): Interval = macro SourceInfoTransform.thatArg - - def do_&(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"And is illegal between $this and $that") - def do_|(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"Or is illegal between $this and $that") - def do_^(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"Xor is illegal between $this and $that") - - final def setPrecision(that: Int): Interval = macro SourceInfoTransform.thatArg - - // Precision change changes range -- see firrtl PrimOps (requires floor) - // aaa.bbb -> aaa.bb for sbp(2) - def do_setPrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - val newBinaryPoint = BinaryPoint(that) - val newIntervalRange = this.range.setPrecision(newBinaryPoint) - binop(sourceInfo, Interval(newIntervalRange), SetBinaryPoint, that) - } - - /** Increase the precision of this Interval, moves the binary point to the left. - * aaa.bbb -> aaa.bbb00 - * @param that how many bits to shift binary point - * @return - */ - final def increasePrecision(that: Int): Interval = macro SourceInfoTransform.thatArg - - def do_increasePrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - assert(that > 0, s"Must increase precision by an integer greater than zero.") - val newBinaryPoint = BinaryPoint(that) - val newIntervalRange = this.range.incPrecision(newBinaryPoint) - binop(sourceInfo, Interval(newIntervalRange), IncreasePrecision, that) - } - - /** Decrease the precision of this Interval, moves the binary point to the right. - * aaa.bbb -> aaa.b - * - * @param that number of bits to move binary point - * @return - */ - final def decreasePrecision(that: Int): Interval = macro SourceInfoTransform.thatArg - - def do_decreasePrecision(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - assert(that > 0, s"Must decrease precision by an integer greater than zero.") - val newBinaryPoint = BinaryPoint(that) - val newIntervalRange = this.range.decPrecision(newBinaryPoint) - binop(sourceInfo, Interval(newIntervalRange), DecreasePrecision, that) - } - - /** Returns this wire bitwise-inverted. */ - def do_unary_~(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - throwException(s"Not is illegal on $this") - - override def do_<(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, LessOp, that) - override def do_>(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, GreaterOp, that) - override def do_<=(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, LessEqOp, that) - override def do_>=(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, GreaterEqOp, that) - - final def !=(that: Interval): Bool = macro SourceInfoTransform.thatArg - final def =/=(that: Interval): Bool = macro SourceInfoTransform.thatArg - final def ===(that: Interval): Bool = macro SourceInfoTransform.thatArg - - def do_!=(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, NotEqualOp, that) - def do_=/=(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, NotEqualOp, that) - def do_===(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = - compop(sourceInfo, EqualOp, that) - - // final def abs(): UInt = macro SourceInfoTransform.noArgDummy - - def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - Mux(this < Interval.Zero, (Interval.Zero - this), this) - } - - override def do_<<(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - binop(sourceInfo, Interval(this.range << that), ShiftLeftOp, that) - - override def do_<<(that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - do_<<(that.toInt) - - override def do_<<(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range << that), DynamicShiftLeftOp, that) - } - - override def do_>>(that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range >> that), ShiftRightOp, that) - } - - override def do_>>(that: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = - do_>>(that.toInt) - - override def do_>>(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range >> that), DynamicShiftRightOp, that) - } - - /** - * Squeeze returns the intersection of the ranges this interval and that Interval - * Ignores binary point of argument - * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range - * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk - * @param that - * @return - */ - final def squeeze(that: Interval): Interval = macro SourceInfoTransform.thatArg - def do_squeeze(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - val other = that - requireIsHardware(this, s"'this' ($this)") - requireIsHardware(other, s"'other' ($other)") - pushOp(DefPrim(sourceInfo, Interval(this.range.squeeze(that.range)), SqueezeOp, this.ref, other.ref)) - } - - /** - * Squeeze returns the intersection of the ranges this interval and that UInt - * Currently, that must have a defined width - * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range - * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk - * @param that an UInt whose properties determine the squeezing - * @return - */ - final def squeeze(that: UInt): Interval = macro SourceInfoTransform.thatArg - def do_squeeze(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - that.widthOption match { - case Some(w) => - do_squeeze(Wire(Interval(IntervalRange(that.width, BinaryPoint(0))))) - case _ => - throwException(s"$this.squeeze($that) requires an UInt argument with a known width") - } - } - - /** - * Squeeze returns the intersection of the ranges this interval and that SInt - * Currently, that must have a defined width - * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range - * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk - * @param that an SInt whose properties determine the squeezing - * @return - */ - final def squeeze(that: SInt): Interval = macro SourceInfoTransform.thatArg - def do_squeeze(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - that.widthOption match { - case Some(w) => - do_squeeze(Wire(Interval(IntervalRange(that.width, BinaryPoint(0))))) - case _ => - throwException(s"$this.squeeze($that) requires an SInt argument with a known width") - } - } - - /** - * Squeeze returns the intersection of the ranges this interval and that IntervalRange - * Ignores binary point of argument - * Treat as an unsafe cast; gives undefined behavior if this signal's value is outside of the resulting range - * Adds no additional hardware; this strictly an unsafe type conversion to use at your own risk - * @param that an Interval whose properties determine the squeezing - * @return - */ - final def squeeze(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg - def do_squeeze(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - val intervalLitOpt = Interval.getSmallestLegalLit(that) - val intervalLit = intervalLitOpt.getOrElse( - throwException(s"$this.squeeze($that) requires an Interval range with known lower and upper bounds") - ) - do_squeeze(intervalLit) - } - - /** - * Wrap the value of this [[Interval]] into the range of a different Interval with a presumably smaller range. - * Ignores binary point of argument - * Errors if requires wrapping more than once - * @param that - * @return - */ - final def wrap(that: Interval): Interval = macro SourceInfoTransform.thatArg - - def do_wrap(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - val other = that - requireIsHardware(this, s"'this' ($this)") - requireIsHardware(other, s"'other' ($other)") - pushOp(DefPrim(sourceInfo, Interval(this.range.wrap(that.range)), WrapOp, this.ref, other.ref)) - } - - /** - * Wrap this interval into the range determined by that UInt - * Errors if requires wrapping more than once - * @param that an UInt whose properties determine the wrap - * @return - */ - final def wrap(that: UInt): Interval = macro SourceInfoTransform.thatArg - def do_wrap(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - that.widthOption match { - case Some(w) => - val u = BigDecimal(BigInt(1) << w) - 1 - do_wrap(0.U.asInterval(IntervalRange(firrtlir.Closed(0), firrtlir.Closed(u), BinaryPoint(0)))) - case _ => - throwException(s"$this.wrap($that) requires UInt with known width") - } - } - - /** - * Wrap this interval into the range determined by an SInt - * Errors if requires wrapping more than once - * @param that an SInt whose properties determine the bounds of the wrap - * @return - */ - final def wrap(that: SInt): Interval = macro SourceInfoTransform.thatArg - def do_wrap(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - that.widthOption match { - case Some(w) => - val l = -BigDecimal(BigInt(1) << (that.getWidth - 1)) - val u = BigDecimal(BigInt(1) << (that.getWidth - 1)) - 1 - do_wrap(Wire(Interval(IntervalRange(firrtlir.Closed(l), firrtlir.Closed(u), BinaryPoint(0))))) - case _ => - throwException(s"$this.wrap($that) requires SInt with known width") - } - } - - /** - * Wrap this interval into the range determined by an IntervalRange - * Adds hardware to change values outside of wrapped range to be at the boundary - * Errors if requires wrapping more than once - * Ignores binary point of argument - * @param that an Interval whose properties determine the bounds of the wrap - * @return - */ - final def wrap(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg - def do_wrap(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - (that.lowerBound, that.upperBound) match { - case (lower: firrtlconstraint.IsKnown, upperBound: firrtlconstraint.IsKnown) => - do_wrap(0.U.asInterval(IntervalRange(that.lowerBound, that.upperBound, BinaryPoint(0)))) - case _ => - throwException(s"$this.wrap($that) requires Interval argument with known lower and upper bounds") - } - } - - /** - * Clip this interval into the range determined by argument's range - * Adds hardware to change values outside of clipped range to be at the boundary - * Ignores binary point of argument - * @param that an Interval whose properties determine the clipping - * @return - */ - final def clip(that: Interval): Interval = macro SourceInfoTransform.thatArg - def do_clip(that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - binop(sourceInfo, Interval(this.range.clip(that.range)), ClipOp, that) - } - - /** - * Clip this interval into the range determined by argument's range - * Adds hardware to change values outside of clipped range to be at the boundary - * @param that an UInt whose width determines the clipping - * @return - */ - final def clip(that: UInt): Interval = macro SourceInfoTransform.thatArg - def do_clip(that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - require(that.widthKnown, "UInt clip width must be known") - val u = BigDecimal(BigInt(1) << that.getWidth) - 1 - do_clip(Wire(Interval(IntervalRange(firrtlir.Closed(0), firrtlir.Closed(u), BinaryPoint(0))))) - } - - /** - * Clip this interval into the range determined by argument's range - * Adds hardware to move values outside of clipped range to the boundary - * @param that an SInt whose width determines the clipping - * @return - */ - final def clip(that: SInt): Interval = macro SourceInfoTransform.thatArg - def do_clip(that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - require(that.widthKnown, "SInt clip width must be known") - val l = -BigDecimal(BigInt(1) << (that.getWidth - 1)) - val u = BigDecimal(BigInt(1) << (that.getWidth - 1)) - 1 - do_clip(Wire(Interval(IntervalRange(firrtlir.Closed(l), firrtlir.Closed(u), BinaryPoint(0))))) - } - - /** - * Clip this interval into the range determined by argument's range - * Adds hardware to move values outside of clipped range to the boundary - * Ignores binary point of argument - * @param that an SInt whose width determines the clipping - * @return - */ - final def clip(that: IntervalRange): Interval = macro SourceInfoTransform.thatArg - def do_clip(that: IntervalRange)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - (that.lowerBound, that.upperBound) match { - case (lower: firrtlconstraint.IsKnown, upperBound: firrtlconstraint.IsKnown) => - do_clip(0.U.asInterval(IntervalRange(that.lowerBound, that.upperBound, BinaryPoint(0)))) - case _ => - throwException(s"$this.clip($that) requires Interval argument with known lower and upper bounds") - } - } - - override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = { - pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref)) - } - override def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = { - pushOp(DefPrim(sourceInfo, SInt(this.width), AsSIntOp, ref)) - } - - override def do_asFixedPoint( - binaryPoint: BinaryPoint - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): FixedPoint = { - binaryPoint match { - case KnownBinaryPoint(value) => - val iLit = ILit(value) - pushOp(DefPrim(sourceInfo, FixedPoint(width, binaryPoint), AsFixedPointOp, ref, iLit)) - case _ => - throwException( - s"cannot call $this.asFixedPoint(binaryPoint=$binaryPoint), you must specify a known binaryPoint" - ) - } - } - - // TODO: intervals chick INVALID -- not enough args - def do_asInterval(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = { - pushOp(DefPrim(sourceInfo, Interval(this.range), AsIntervalOp, ref)) - throwException(s"($this).asInterval must specify arguments INVALID") - } - - // TODO:(chick) intervals chick looks like this is wrong and only for FP? - def do_fromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): this.type = { - /*val res = Wire(this, null).asInstanceOf[this.type] - res := (that match { - case fp: FixedPoint => fp.asSInt.asFixedPoint(this.binaryPoint) - case _ => that.asFixedPoint(this.binaryPoint) - }) - res*/ - throwException("fromBits INVALID for intervals") - } - - private[chisel3] override def connectFromBits( - that: Bits - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ) { - this := that.asInterval(this.range) - } - } - - /** Use PrivateObject to force users to specify width and binaryPoint by name - */ - - /** - * Factory and convenience methods for the Interval class - * IMPORTANT: The API provided here is experimental and may change in the future. - */ - object Interval extends NumObject { - - /** Create an Interval type with inferred width and binary point. */ - def apply(): Interval = Interval(range"[?,?]") - - /** Create an Interval type with specified width. */ - def apply(binaryPoint: BinaryPoint): Interval = { - val binaryPointString = binaryPoint match { - case KnownBinaryPoint(value) => s"$value" - case _ => s"" - } - Interval(range"[?,?].$binaryPointString") - } - - /** Create an Interval type with specified width. */ - def apply(width: Width): Interval = Interval(width, 0.BP) - - /** Create an Interval type with specified width and binary point */ - def apply(width: Width, binaryPoint: BinaryPoint): Interval = { - Interval(IntervalRange(width, binaryPoint)) - } - - /** Create an Interval type with specified range. - * @param range defines the properties - */ - def apply(range: IntervalRange): Interval = { - new Interval(range) - } - - /** Creates a Interval connected to a Interval literal with the value zero */ - def Zero: Interval = Lit(0, 1.W, 0.BP) - - /** Creates an Interval zero that supports the given range - * Useful for creating a Interval register that has a desired number of bits - * {{{ - * val myRegister = RegInit(Interval.Zero(r"[0,12]") - * }}} - * @param range - * @return - */ - def Zero(range: IntervalRange): Interval = Lit(0, range) - - /** Make an interval from this BigInt, the BigInt is treated as bits - * So lower binaryPoint number of bits will treated as mantissa - * - * @param value - * @param width - * @param binaryPoint - * @return - */ - def fromBigInt(value: BigInt, width: Width = Width(), binaryPoint: BinaryPoint = 0.BP): Interval = { - Interval.Lit(value, Width(), binaryPoint) - } - - /** Create an Interval literal with inferred width from Double. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromDouble( - value: Double, - dummy: PrivateType = PrivateObject, - width: Width, - binaryPoint: BinaryPoint - ): Interval = { - fromBigInt( - toBigInt(value, binaryPoint), - width = width, - binaryPoint = binaryPoint - ) - } - - /** Create an Interval literal with inferred width from Double. - * Use PrivateObject to force users to specify width and binaryPoint by name - */ - def fromBigDecimal( - value: Double, - dummy: PrivateType = PrivateObject, - width: Width, - binaryPoint: BinaryPoint - ): Interval = { - fromBigInt( - toBigInt(value, binaryPoint), - width = width, - binaryPoint = binaryPoint - ) - } - - protected[chisel3] def Lit(value: BigInt, width: Width, binaryPoint: BinaryPoint): Interval = { - width match { - case KnownWidth(w) => - if (value >= 0 && value.bitLength >= w || value < 0 && value.bitLength > w) { - throw new ChiselException( - s"Error literal interval value $value is too many bits for specified width $w" - ) - } - case _ => - } - val lit = IntervalLit(value, width, binaryPoint) - val bound = firrtlir.Closed(Interval.toBigDecimal(value, binaryPoint.asInstanceOf[KnownBinaryPoint].value)) - val result = new Interval(IntervalRange(bound, bound, binaryPoint)) - lit.bindLitArg(result) - } - - protected[chisel3] def Lit(value: BigInt, range: IntervalRange): Interval = { - val lit = IntervalLit(value, range.getWidth, range.binaryPoint) - val bigDecimal = BigDecimal(value) / (1 << lit.binaryPoint.get) - val inRange = (range.lowerBound, range.upperBound) match { - case (firrtlir.Closed(l), firrtlir.Closed(u)) => l <= bigDecimal && bigDecimal <= u - case (firrtlir.Closed(l), firrtlir.Open(u)) => l <= bigDecimal && bigDecimal < u - case (firrtlir.Open(l), firrtlir.Closed(u)) => l < bigDecimal && bigDecimal <= u - case (firrtlir.Open(l), firrtlir.Open(u)) => l < bigDecimal && bigDecimal < u - } - if (!inRange) { - throw new ChiselException( - s"Error literal interval value $bigDecimal is not contained in specified range $range" - ) - } - val result = Interval(range) - lit.bindLitArg(result) - } - - /** - * This returns the smallest Interval literal that can legally fit in range, if possible - * If the lower bound or binary point is not known then return None - * - * @param range use to figure low number - * @return - */ - def getSmallestLegalLit(range: IntervalRange): Option[Interval] = { - val bp = range.binaryPoint - range.lowerBound match { - case firrtlir.Closed(lowerBound) => - Some(Interval.Lit(toBigInt(lowerBound.toDouble, bp), width = range.getWidth, bp)) - case firrtlir.Open(lowerBound) => - Some(Interval.Lit(toBigInt(lowerBound.toDouble, bp) + BigInt(1), width = range.getWidth, bp)) - case _ => - None - } - } - - /** - * This returns the largest Interval literal that can legally fit in range, if possible - * If the upper bound or binary point is not known then return None - * - * @param range use to figure low number - * @return - */ - def getLargestLegalLit(range: IntervalRange): Option[Interval] = { - val bp = range.binaryPoint - range.upperBound match { - case firrtlir.Closed(upperBound) => - Some(Interval.Lit(toBigInt(upperBound.toDouble, bp), width = range.getWidth, bp)) - case firrtlir.Open(upperBound) => - Some(Interval.Lit(toBigInt(upperBound.toDouble, bp) - BigInt(1), width = range.getWidth, bp)) - case _ => - None - } - } - - /** Contains the implicit classes used to provide the .I methods to create intervals - * from the standard numberic types. - * {{{ - * val x = 7.I - * val y = 7.5.I(4.BP) - * }}} - */ - object Implicits { - implicit class fromBigIntToLiteralInterval(bigInt: BigInt) { - def I: Interval = { - Interval.Lit(bigInt, width = Width(), 0.BP) - } - - def I(binaryPoint: BinaryPoint): Interval = { - Interval.Lit(bigInt, width = Width(), binaryPoint = binaryPoint) - } - - def I(width: Width, binaryPoint: BinaryPoint): Interval = { - Interval.Lit(bigInt, width, binaryPoint) - } - - def I(range: IntervalRange): Interval = { - Interval.Lit(bigInt, range) - } - } - - implicit class fromIntToLiteralInterval(int: Int) extends fromBigIntToLiteralInterval(int) - implicit class fromLongToLiteralInterval(long: Long) extends fromBigIntToLiteralInterval(long) - - implicit class fromBigDecimalToLiteralInterval(bigDecimal: BigDecimal) { - def I: Interval = { - Interval.Lit(Interval.toBigInt(bigDecimal, 0.BP), width = Width(), 0.BP) - } - - def I(binaryPoint: BinaryPoint): Interval = { - Interval.Lit(Interval.toBigInt(bigDecimal, binaryPoint), width = Width(), binaryPoint = binaryPoint) - } - - def I(width: Width, binaryPoint: BinaryPoint): Interval = { - Interval.Lit(Interval.toBigInt(bigDecimal, binaryPoint), width, binaryPoint) - } - - def I(range: IntervalRange): Interval = { - Interval.Lit(Interval.toBigInt(bigDecimal, range.binaryPoint), range) - } - } - - implicit class fromDoubleToLiteralInterval(double: Double) - extends fromBigDecimalToLiteralInterval(BigDecimal(double)) - } - } } diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala deleted file mode 100644 index c3cb3e66..00000000 --- a/core/src/main/scala/chisel3/BlackBox.scala +++ /dev/null @@ -1,203 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3 - -import chisel3.experimental.{BaseModule, Param} -import chisel3.internal.BaseBlackBox -import chisel3.internal.Builder.pushCommand -import chisel3.internal.firrtl._ -import chisel3.internal.throwException -import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} -import scala.annotation.nowarn - -package internal { - - private[chisel3] abstract class BaseBlackBox extends BaseModule - -} - -package experimental { - - /** Parameters for BlackBoxes */ - sealed abstract class Param - case class IntParam(value: BigInt) extends Param - case class DoubleParam(value: Double) extends Param - case class StringParam(value: String) extends Param - - /** Unquoted String */ - case class RawParam(value: String) extends Param - - /** Defines a black box, which is a module that can be referenced from within - * Chisel, but is not defined in the emitted Verilog. Useful for connecting - * to RTL modules defined outside Chisel. - * - * A variant of BlackBox, this has a more consistent naming scheme in allowing - * multiple top-level IO and does not drop the top prefix. - * - * @example - * Some design require a differential input clock to clock the all design. - * With the xilinx FPGA for example, a Verilog template named IBUFDS must be - * integrated to use differential input: - * {{{ - * IBUFDS #(.DIFF_TERM("TRUE"), - * .IOSTANDARD("DEFAULT")) ibufds ( - * .IB(ibufds_IB), - * .I(ibufds_I), - * .O(ibufds_O) - * ); - * }}} - * - * To instantiate it, a BlackBox can be used like following: - * {{{ - * import chisel3._ - * import chisel3.experimental._ - * - * // Example with Xilinx differential buffer IBUFDS - * class IBUFDS extends ExtModule(Map("DIFF_TERM" -> "TRUE", // Verilog parameters - * "IOSTANDARD" -> "DEFAULT" - * )) { - * val O = IO(Output(Clock())) - * val I = IO(Input(Clock())) - * val IB = IO(Input(Clock())) - * } - * }}} - * @note The parameters API is experimental and may change - */ - @nowarn("msg=class Port") // delete when Port becomes private - abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox { - private[chisel3] override def generateComponent(): Option[Component] = { - require(!_closed, "Can't generate module more than once") - _closed = true - - val names = nameIds(classOf[ExtModule]) - - // Ports are named in the same way as regular Modules - namePorts(names) - - // All suggestions are in, force names to every node. - // While BlackBoxes are not supposed to have an implementation, we still need to call - // _onModuleClose on all nodes (for example, Aggregates use it for recursive naming). - for (id <- getIds) { - id._onModuleClose - } - - closeUnboundIds(names) - - val firrtlPorts = getModulePorts.map { port => Port(port, port.specifiedDirection) } - val component = DefBlackBox(this, name, firrtlPorts, SpecifiedDirection.Unspecified, params) - _component = Some(component) - _component - } - - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = { - implicit val sourceInfo = UnlocatableSourceInfo - - if (!parentCompileOptions.explicitInvalidate) { - for (x <- getModulePorts) { - pushCommand(DefInvalid(sourceInfo, x.ref)) - } - } - } - } -} - -/** Defines a black box, which is a module that can be referenced from within - * Chisel, but is not defined in the emitted Verilog. Useful for connecting - * to RTL modules defined outside Chisel. - * - * @example - * Some design require a differential input clock to clock the all design. - * With the xilinx FPGA for example, a Verilog template named IBUFDS must be - * integrated to use differential input: - * {{{ - * IBUFDS #(.DIFF_TERM("TRUE"), - * .IOSTANDARD("DEFAULT")) ibufds ( - * .IB(ibufds_IB), - * .I(ibufds_I), - * .O(ibufds_O) - * ); - * }}} - * - * To instantiate it, a BlackBox can be used like following: - * {{{ - * import chisel3._ - * import chisel3.experimental._ - * - * // Example with Xilinx differential buffer IBUFDS - * class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE", // Verilog parameters - * "IOSTANDARD" -> "DEFAULT" - * )) { - * val io = IO(new Bundle { - * val O = Output(Clock()) // IO names will be the same - * val I = Input(Clock()) // (without 'io_' in prefix) - * val IB = Input(Clock()) // - * }) - * } - * }}} - * @note The parameters API is experimental and may change - */ -@nowarn("msg=class Port") // delete when Port becomes private -abstract class BlackBox( - val params: Map[String, Param] = Map.empty[String, Param] -)( - implicit compileOptions: CompileOptions) - extends BaseBlackBox { - - // Find a Record port named "io" for purposes of stripping the prefix - private[chisel3] lazy val _io: Option[Record] = - this - .findPort("io") - .collect { case r: Record => r } // Must be a Record - - // Allow access to bindings from the compatibility package - protected def _compatIoPortBound() = _io.exists(portsContains(_)) - - private[chisel3] override def generateComponent(): Option[Component] = { - _compatAutoWrapPorts() // pre-IO(...) compatibility hack - - // Restrict IO to just io, clock, and reset - if (!_io.exists(portsContains)) { - throwException(s"BlackBox '$this' must have a port named 'io' of type Record wrapped in IO(...)!") - } - - require(portsSize == 1, "BlackBox must only have one IO, called `io`") - - require(!_closed, "Can't generate module more than once") - _closed = true - - val io = _io.get - - val namedPorts = io.elements.toSeq.reverse // ListMaps are stored in reverse order - - // There is a risk of user improperly attempting to connect directly with io - // Long term solution will be to define BlackBox IO differently as part of - // it not descending from the (current) Module - for ((name, port) <- namedPorts) { - // We are setting a 'fake' ref for io, so that cloneType works but if a user connects to io, it still fails. - this.findPort("io").get.setRef(ModuleIO(internal.ViewParent, ""), force = true) - // We have to force override the _ref because it was set during IO binding - port.setRef(ModuleIO(this, _namespace.name(name)), force = true) - } - - // We need to call forceName and onModuleClose on all of the sub-elements - // of the io bundle, but NOT on the io bundle itself. - // Doing so would cause the wrong names to be assigned, since their parent - // is now the module itself instead of the io bundle. - for (id <- getIds; if id ne io) { - id._onModuleClose - } - - val firrtlPorts = namedPorts.map { namedPort => Port(namedPort._2, namedPort._2.specifiedDirection) } - val component = DefBlackBox(this, name, firrtlPorts, io.specifiedDirection, params) - _component = Some(component) - _component - } - - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = { - if (!parentCompileOptions.explicitInvalidate) { - for ((_, port) <- _io.map(_.elements).getOrElse(Nil)) { - pushCommand(DefInvalid(UnlocatableSourceInfo, port.ref)) - } - } - } -} diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala index 259e6545..ec5a6321 100644 --- a/core/src/main/scala/chisel3/Data.scala +++ b/core/src/main/scala/chisel3/Data.scala @@ -2,10 +2,8 @@ package chisel3 -import chisel3.experimental.dataview.reify - import scala.language.experimental.macros -import chisel3.experimental.{Analog, BaseModule, DataMirror, FixedPoint, Interval} +import chisel3.experimental.{Analog, BaseModule, DataMirror} import chisel3.internal.Builder.pushCommand import chisel3.internal._ import chisel3.internal.firrtl._ @@ -146,8 +144,6 @@ object ActualDirection { } package experimental { - import chisel3.internal.requireIsHardware // Fix ambiguous import - /** Experimental hardware construction reflection API */ object DataMirror { @@ -222,7 +218,7 @@ package experimental { * // ) * }}} */ - def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts + def modulePorts(target: BaseModule): Seq[(String, Data)] = Seq.empty /** Returns a recursive representation of a module's ports with underscore-qualified names * {{{ @@ -318,24 +314,6 @@ private[chisel3] object cloneSupertype { // TODO: perhaps redefine Widths to allow >= op? if (elt1.width == (elt1.width.max(elt2.width))) elt1 else elt2 case (elt1: SInt, elt2: SInt) => if (elt1.width == (elt1.width.max(elt2.width))) elt1 else elt2 - case (elt1: FixedPoint, elt2: FixedPoint) => { - (elt1.binaryPoint, elt2.binaryPoint, elt1.width, elt2.width) match { - case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), KnownWidth(w1), KnownWidth(w2)) => - val maxBinaryPoint = bp1.max(bp2) - val maxIntegerWidth = (w1 - bp1).max(w2 - bp2) - FixedPoint((maxIntegerWidth + maxBinaryPoint).W, (maxBinaryPoint).BP) - case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), _, _) => - FixedPoint(Width(), (bp1.max(bp2)).BP) - case _ => FixedPoint() - } - } - case (elt1: Interval, elt2: Interval) => - val range = if (elt1.range.width == elt1.range.width.max(elt2.range.width)) elt1.range else elt2.range - Interval(range) - case (elt1, elt2) => - throw new AssertionError( - s"can't create $createdType with heterogeneous types ${elt1.getClass} and ${elt2.getClass}" - ) }).asInstanceOf[T] } model.cloneTypeFull @@ -629,7 +607,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { if (connectCompileOptions.emitStrictConnects) { try { - MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule) + MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.currentModule.get) } catch { case MonoConnectException(message) => throwException( @@ -658,7 +636,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { } if (connectCompileOptions.emitStrictConnects) { try { - BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule) + BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.currentModule.get) } catch { case BiConnectException(message) => throwException( @@ -697,7 +675,6 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { topBindingOpt match { case Some(binding: ReadOnlyBinding) => throwException(s"internal error: attempted to generate LHS ref to ReadOnlyBinding $binding") - case Some(ViewBinding(target)) => reify(target).lref case Some(binding: TopBinding) => Node(this) case opt => throwException(s"internal error: unknown binding $opt in generating LHS ref") } @@ -713,14 +690,6 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { } requireIsHardware(this) topBindingOpt match { - // DataView - case Some(ViewBinding(target)) => reify(target).ref - case Some(AggregateViewBinding(viewMap)) => - viewMap.get(this) match { - case None => materializeWire() // FIXME FIRRTL doesn't have Aggregate Init expressions - // This should not be possible because Element does the lookup in .topBindingOpt - case x: Some[_] => throwException(s"Internal Error: In .ref for $this got '$topBindingOpt' and '$x'") - } // Literals case Some(ElementLitBinding(litArg)) => litArg case Some(BundleLitBinding(litMap)) => @@ -928,8 +897,6 @@ object Data { case (thiz: SInt, that: SInt) => thiz === that case (thiz: AsyncReset, that: AsyncReset) => thiz.asBool === that.asBool case (thiz: Reset, that: Reset) => thiz === that - case (thiz: Interval, that: Interval) => thiz === that - case (thiz: FixedPoint, that: FixedPoint) => thiz === that case (thiz: EnumType, that: EnumType) => thiz === that case (thiz: Clock, that: Clock) => thiz.asUInt === that.asUInt case (thiz: Vec[_], that: Vec[_]) => @@ -992,7 +959,7 @@ trait WireFactory { x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen)) pushCommand(DefWire(sourceInfo, x)) - if (!compileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) { + if (!compileOptions.explicitInvalidate) { pushCommand(DefInvalid(sourceInfo, x.ref)) } diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala index a2d5cec6..794d1bf4 100644 --- a/core/src/main/scala/chisel3/Module.scala +++ b/core/src/main/scala/chisel3/Module.scala @@ -172,7 +172,7 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw private[chisel3] def mkReset: Reset = { // Top module and compatibility mode use Bool for reset // Note that a Definition elaboration will lack a parent, but still not be a Top module - val inferReset = (_parent.isDefined || Builder.inDefinition) && moduleCompileOptions.inferModuleReset + val inferReset = (_parent.isDefined) && moduleCompileOptions.inferModuleReset if (moduleCompileOptions.migrateInferModuleReset && !moduleCompileOptions.inferModuleReset) { this match { case _: RequireSyncReset => // Good! It's been migrated. @@ -210,215 +210,16 @@ package experimental { package internal { import chisel3.experimental.BaseModule - import chisel3.experimental.hierarchy.{Clone, IsInstantiable, Proto} - object BaseModule { - - /** Represents a clone of an underlying object. This is used to support CloneModuleAsRecord and Instance/Definition. - * - * @note We don't actually "clone" anything in the traditional sense but is a placeholder so we lazily clone internal state - */ - trait IsClone[+T] { - // Underlying object of which this is a clone of - private[chisel3] def getProto: T - - /** Determines whether another object is a clone of the same underlying proto - * - * @param a - */ - def hasSameProto(a: Any): Boolean = { - val aProto = a match { - case x: IsClone[BaseModule] => x.getProto - case o => o - } - this == aProto || getProto == aProto - } - } - - // Private internal class to serve as a _parent for Data in cloned ports - private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T) extends PseudoModule with IsClone[T] { - override def toString = s"ModuleClone(${getProto})" - // Do not call default addId function, which may modify a module that is already "closed" - override def addId(d: HasId): Unit = () - def getPorts = _portsRecord - // ClonePorts that hold the bound ports for this module - // Used for setting the refs of both this module and the Record - private[BaseModule] var _portsRecord: Record = _ - // This is necessary for correctly supporting .toTarget on a Module Clone. If it is made from the - // Instance/Definition API, it should return an instanceTarget. If made from CMAR, it should return a - // ModuleTarget. - private[chisel3] var _madeFromDefinition: Boolean = false - // Don't generate a component, but point to the one for the cloned Module - private[chisel3] def generateComponent(): Option[Component] = { - require(!_closed, "Can't generate module more than once") - _closed = true - _component = getProto._component - None - } - // Maps proto ports to module clone's ports - private[chisel3] lazy val ioMap: Map[Data, Data] = { - getProto match { - // BlackBox needs special handling for its pseduo-io Bundle - case protoBB: BlackBox => - Map(protoBB._io.get -> getPorts.elements("io")) - case _ => - val name2Port = getPorts.elements - getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap - } - } - // This module doesn't actually exist in the FIRRTL so no initialization to do - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () - - // Name of this instance's module is the same as the proto's name - override def desiredName: String = getProto.name - - private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = { - val record = _portsRecord - // Use .forceName to re-use default name resolving behavior - record.forceName(default = this.desiredName, namespace) - // Now take the Ref that forceName set and convert it to the correct Arg - val instName = record.getRef match { - case Ref(name) => name - case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad") - } - // Set both the record and the module to have the same instance name - val ref = ModuleCloneIO(getProto, instName) - record.setRef(ref, force = true) // force because we did .forceName first - getProto match { - // BlackBox needs special handling for its pseduo-io Bundle - case _: BlackBox => - // Override the io Bundle's ref so that it thinks it is the top for purposes of - // generating FIRRTL - record.elements("io").setRef(ref, force = true) - case _ => // Do nothing - } - - this.setRef(Ref(instName)) - } - } - - /** Represents a module viewed from a different instance context. - * - * @note Why do we need both ModuleClone and InstanceClone? If we are annotating a reference in a module-clone, - * all submodules must be also be 'cloned' so the toTarget can be computed properly. However, we don't need separate - * connectable ports for this instance; all that's different from the proto is the parent. - * - * @note In addition, the instance name of an InstanceClone is going to be the SAME as the proto, but this is not true - * for ModuleClone. - */ - private[chisel3] final class InstanceClone[T <: BaseModule](val getProto: T, val instName: () => String) - extends PseudoModule - with IsClone[T] { - override def toString = s"InstanceClone(${getProto})" - // No addition components are generated - private[chisel3] def generateComponent(): Option[Component] = None - // Necessary for toTarget to work - private[chisel3] def setAsInstanceRef(): Unit = { this.setRef(Ref(instName())) } - // This module doesn't acutally exist in the FIRRTL so no initialization to do - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () - // Instance name is the same as proto's instance name - override def instanceName = instName() - // Module name is the same as proto's module name - override def desiredName: String = getProto.name - } - - /** Represents a Definition root module, when accessing something from a definition - * - * @note This is necessary to distinguish between the toTarget behavior for a Module returned from a Definition, - * versus a normal Module. A normal Module.toTarget will always return a local target. If calling toTarget - * on a Module returned from a Definition (and thus wrapped in an Instance), we need to return the non-local - * target whose root is the Definition. This DefinitionClone is used to represent the root parent of the - * InstanceClone (which represents the returned module). - */ - private[chisel3] class DefinitionClone[T <: BaseModule](val getProto: T) extends PseudoModule with IsClone[T] { - override def toString = s"DefinitionClone(${getProto})" - // No addition components are generated - private[chisel3] def generateComponent(): Option[Component] = None - // Do not call default addId function, which may modify a module that is already "closed" - override def addId(d: HasId): Unit = () - // Necessary for toTarget to work - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () - // Module name is the same as proto's module name - override def desiredName: String = getProto.name - } - - /** @note If we are cloning a non-module, we need another object which has the proper _parent set! - */ - trait InstantiableClone[T <: IsInstantiable] extends IsClone[T] { - private[chisel3] def _innerContext: experimental.hierarchy.Hierarchy[_] - private[chisel3] def getInnerContext: Option[BaseModule] = _innerContext.getInnerDataContext - } - - /** Record type returned by CloneModuleAsRecord - * - * @note These are not true Data (the Record doesn't correspond to anything in the emitted - * FIRRTL yet its elements *do*) so have some very specialized behavior. - */ - private[chisel3] class ClonePorts(elts: (String, Data)*)(implicit compileOptions: CompileOptions) extends Record { - val elements = ListMap(elts.map { case (name, d) => name -> d.cloneTypeFull }: _*) - def apply(field: String) = elements(field) - override def cloneType = (new ClonePorts(elts: _*)).asInstanceOf[this.type] - } - - private[chisel3] def cloneIORecord( - proto: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): ClonePorts = { - require(proto.isClosed, "Can't clone a module before module close") - // Fake Module to serve as the _parent of the cloned ports - // We make this before clonePorts because we want it to come up first in naming in - // currentModule - val cloneParent = Module(new ModuleClone(proto)) - require(proto.isClosed, "Can't clone a module before module close") - require(cloneParent.getOptionRef.isEmpty, "Can't have ref set already!") - // Fake Module to serve as the _parent of the cloned ports - // We don't create this inside the ModuleClone because we need the ref to be set by the - // currentModule (and not clonePorts) - val clonePorts = proto match { - // BlackBox needs special handling for its pseduo-io Bundle - case b: BlackBox => - new ClonePorts(proto.getChiselPorts :+ ("io" -> b._io.get): _*) - case _ => new ClonePorts(proto.getChiselPorts: _*) - } - // getChiselPorts (nor cloneTypeFull in general) - // does not recursively copy the right specifiedDirection, - // still need to fix it up here. - Module.assignCompatDir(clonePorts) - clonePorts.bind(PortBinding(cloneParent)) - clonePorts.setAllParents(Some(cloneParent)) - cloneParent._portsRecord = clonePorts - // Normally handled during Module construction but ClonePorts really lives in its parent's parent - if (!compileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) { - // FIXME This almost certainly doesn't work since clonePorts is not a real thing... - pushCommand(DefInvalid(sourceInfo, clonePorts.ref)) - } - if (proto.isInstanceOf[Module]) { - clonePorts("clock") := Module.clock - clonePorts("reset") := Module.reset - } - clonePorts - } - } + object BaseModule {} } package experimental { - import chisel3.experimental.hierarchy.{IsInstantiable, Proto} - - object BaseModule { - implicit class BaseModuleExtensions[T <: BaseModule](b: T) { - import chisel3.experimental.hierarchy.{Definition, Instance} - def toInstance: Instance[T] = new Instance(Proto(b)) - def toDefinition: Definition[T] = new Definition(Proto(b)) - } - } - /** Abstract base class for Modules, an instantiable organizational unit for RTL. */ // TODO: seal this? - abstract class BaseModule extends HasId with IsInstantiable { + abstract class BaseModule extends HasId { _parent.foreach(_.addId(this)) // @@ -450,12 +251,8 @@ package experimental { private[chisel3] val _namespace = Namespace.empty private val _ids = ArrayBuffer[HasId]() private[chisel3] def addId(d: HasId) { - if (Builder.aspectModule(this).isDefined) { - aspectModule(this).get.addId(d) - } else { - require(!_closed, "Can't write to module after module close") - _ids += d - } + require(!_closed, "Can't write to module after module close") + _ids += d } // Returns the last id contained within a Module @@ -471,25 +268,6 @@ package experimental { _ids.toSeq } - private val _ports = new ArrayBuffer[Data]() - - // getPorts unfortunately already used for tester compatibility - protected[chisel3] def getModulePorts = { - require(_closed, "Can't get ports before module close") - _ports.toSeq - } - - // These methods allow checking some properties of ports before the module is closed, - // mainly for compatibility purposes. - protected def portsContains(elem: Data): Boolean = _ports contains elem - - // This is dangerous because it can be called before the module is closed and thus there could - // be more ports and names have not yet been finalized. - // This should only to be used during the process of closing when it is safe to do so. - private[chisel3] def findPort(name: String): Option[Data] = _ports.find(_.seedOpt.contains(name)) - - protected def portsSize: Int = _ports.size - /** Generates the FIRRTL Component (Module or Blackbox) of this Module. * Also closes the module so no more construction can happen inside. */ @@ -499,27 +277,6 @@ package experimental { */ private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit - private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = { - for (port <- getModulePorts) { - port._computeName(None).orElse(names.get(port)) match { - case Some(name) => - if (_namespace.contains(name)) { - Builder.error( - s"""Unable to name port $port to "$name" in $this,""" + - " name is already taken by another port!" - ) - } - port.setRef(ModuleIO(this, _namespace.name(name))) - case None => - Builder.error( - s"Unable to name port $port in $this, " + - "try making it a public field of the Module" - ) - port.setRef(ModuleIO(this, "<UNNAMED>")) - } - } - } - // // Chisel Internals // @@ -578,35 +335,9 @@ package experimental { * * @note Should not be called until circuit elaboration is complete */ - final def toTarget: ModuleTarget = this match { - case m: internal.BaseModule.InstanceClone[_] => - throwException(s"Internal Error! It's not legal to call .toTarget on an InstanceClone. $m") - case m: internal.BaseModule.DefinitionClone[_] => - throwException(s"Internal Error! It's not legal to call .toTarget on an DefinitionClone. $m") - case _ => ModuleTarget(this.circuitName, this.name) - } + final def toTarget: ModuleTarget = ModuleTarget(this.circuitName, this.name) - /** Returns the real target of a Module which may be an [[InstanceTarget]] - * - * BaseModule.toTarget returns a ModuleTarget because the classic Module(new MyModule) API elaborates - * Modules in a way that there is a 1:1 relationship between instances and elaborated definitions - * - * Instance/Definition introduced special internal modules [[InstanceClone]] and [[ModuleClone]] that - * do not have this 1:1 relationship so need the ability to return [[InstanceTarget]]s. - * Because users can never actually get references to these underlying objects, we can maintain - * BaseModule.toTarget's API returning [[ModuleTarget]] while providing an internal API for getting - * the correct [[InstanceTarget]]s whenever using the Definition/Instance API. - */ - private[chisel3] def getTarget: IsModule = this match { - case m: internal.BaseModule.InstanceClone[_] if m._parent.nonEmpty => - m._parent.get.getTarget.instOf(instanceName, name) - case m: internal.BaseModule.ModuleClone[_] if m._madeFromDefinition => - m._parent.get.getTarget.instOf(instanceName, name) - // Without this, we get the wrong CircuitName for the Definition - case m: internal.BaseModule.DefinitionClone[_] if m._circuit.nonEmpty => - ModuleTarget(this._circuit.get.circuitName, this.name) - case _ => this.toTarget - } + private[chisel3] def getTarget: IsModule = this.toTarget /** Returns a FIRRTL ModuleTarget that references this object * @@ -615,30 +346,7 @@ package experimental { final def toAbsoluteTarget: IsModule = { _parent match { case Some(parent) => parent.toAbsoluteTarget.instOf(this.instanceName, name) - case None => - // FIXME Special handling for Views - evidence of "weirdness" of .toAbsoluteTarget - // In theory, .toAbsoluteTarget should not be necessary, .toTarget combined with the - // target disambiguation in FIRRTL's deduplication transform should ensure that .toTarget - // is always unambigous. However, legacy workarounds for Chisel's lack of an instance API - // have lead some to use .toAbsoluteTarget as a workaround. A proper instance API will make - // it possible to deprecate and remove .toAbsoluteTarget - if (this == ViewParent) ViewParent.absoluteTarget else getTarget - } - } - - /** - * Internal API. Returns a list of this module's generated top-level ports as a map of a String - * (FIRRTL name) to the IO object. Only valid after the module is closed. - * - * Note: for BlackBoxes (but not ExtModules), this returns the contents of the top-level io - * object, consistent with what is emitted in FIRRTL. - * - * TODO: Use SeqMap/VectorMap when those data structures become available. - */ - private[chisel3] def getChiselPorts: Seq[(String, Data)] = { - require(_closed, "Can't get ports before module close") - _component.get.ports.map { port => - (port.id.getRef.asInstanceOf[ModuleIO].name, port.id) + case None => getTarget } } @@ -699,7 +407,6 @@ package experimental { Module.assignCompatDir(iodef) iodef.bind(PortBinding(this)) - _ports += iodef } /** Private accessor for _bindIoInPlace */ diff --git a/core/src/main/scala/chisel3/ModuleAspect.scala b/core/src/main/scala/chisel3/ModuleAspect.scala deleted file mode 100644 index 471ab980..00000000 --- a/core/src/main/scala/chisel3/ModuleAspect.scala +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3 - -import chisel3.internal.{Builder, PseudoModule} - -/** Used by Chisel Aspects to inject Chisel code into modules, after they have been elaborated. - * This is an internal API - don't use! - * - * It adds itself as an aspect to the module, which allows proper checking of connection and binding legality. - * - * @param module Module for which this object is an aspect of - * @param moduleCompileOptions - */ -abstract class ModuleAspect private[chisel3] (module: RawModule)(implicit moduleCompileOptions: CompileOptions) - extends RawModule - with PseudoModule { - - Builder.addAspect(module, this) - - override def circuitName: String = module.toTarget.circuit - - override def desiredName: String = module.name - - override val _namespace = module._namespace -} diff --git a/core/src/main/scala/chisel3/Num.scala b/core/src/main/scala/chisel3/Num.scala index c7e0721f..4a984b5a 100644 --- a/core/src/main/scala/chisel3/Num.scala +++ b/core/src/main/scala/chisel3/Num.scala @@ -2,7 +2,6 @@ package chisel3 -import chisel3.internal.ChiselException import chisel3.internal.firrtl.{BinaryPoint, KnownBinaryPoint} import scala.language.experimental.macros diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala index 9668313a..19b719e0 100644 --- a/core/src/main/scala/chisel3/RawModule.scala +++ b/core/src/main/scala/chisel3/RawModule.scala @@ -7,7 +7,6 @@ import scala.language.experimental.macros import scala.annotation.nowarn import chisel3.experimental.BaseModule import chisel3.internal._ -import chisel3.internal.BaseModule.{InstanceClone, ModuleClone} import chisel3.internal.Builder._ import chisel3.internal.firrtl._ import chisel3.internal.sourceinfo.UnlocatableSourceInfo @@ -37,14 +36,6 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends _component.get.asInstanceOf[DefModule].commands } - // - // Other Internal Functions - // - private var _firrtlPorts: Option[Seq[firrtl.Port]] = None - - @deprecated("Use DataMirror.modulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5") - lazy val getPorts: Seq[Port] = _firrtlPorts.get - val compileOptions = moduleCompileOptions // This could be factored into a common utility @@ -69,9 +60,6 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends val names = nameIds(classOf[RawModule]) - // Ports get first naming priority, since they are part of a Module's IO spec - namePorts(names) - // Then everything else gets named val warnReflectiveNaming = Builder.warnReflectiveNaming for ((node, name) <- names) { @@ -96,8 +84,6 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends // All suggestions are in, force names to every node. for (id <- getIds) { id match { - case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling - case id: InstanceClone[_] => id.setAsInstanceRef() case id: BaseModule => id.forceName(default = id.desiredName, _namespace) case id: MemBase[_] => id.forceName(default = "MEM", _namespace) case id: stop.Stop => id.forceName(default = "stop", _namespace) @@ -127,50 +113,12 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends closeUnboundIds(names) - val firrtlPorts = getModulePorts.map { port: Data => - // Special case Vec to make FIRRTL emit the direction of its - // element. - // Just taking the Vec's specifiedDirection is a bug in cases like - // Vec(Flipped()), since the Vec's specifiedDirection is - // Unspecified. - val direction = port match { - case v: Vec[_] => - v.specifiedDirection match { - case SpecifiedDirection.Input => SpecifiedDirection.Input - case SpecifiedDirection.Output => SpecifiedDirection.Output - case SpecifiedDirection.Flip => SpecifiedDirection.flip(v.sample_element.specifiedDirection) - case SpecifiedDirection.Unspecified => v.sample_element.specifiedDirection - } - case _ => port.specifiedDirection - } - - Port(port, direction) - } - _firrtlPorts = Some(firrtlPorts) - - // Generate IO invalidation commands to initialize outputs as unused, - // unless the client wants explicit control over their generation. - val invalidateCommands = { - if (!compileOptions.explicitInvalidate || this.isInstanceOf[ImplicitInvalidate]) { - getModulePorts.map { port => DefInvalid(UnlocatableSourceInfo, port.ref) } - } else { - Seq() - } - } - val component = DefModule(this, name, firrtlPorts, invalidateCommands ++: _commands.result()) + val component = DefModule(this, name, null, Seq.empty) _component = Some(component) _component } - private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = { - implicit val sourceInfo = UnlocatableSourceInfo - - if (!parentCompileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) { - for (port <- getModulePorts) { - pushCommand(DefInvalid(sourceInfo, port.ref)) - } - } - } + private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {} } trait RequireAsyncReset extends Module { @@ -182,7 +130,6 @@ trait RequireSyncReset extends Module { } /** Mix with a [[RawModule]] to automatically connect DontCare to the module's ports, wires, and children instance IOs. */ -trait ImplicitInvalidate { self: RawModule => } package object internal { @@ -227,158 +174,4 @@ package object internal { builder.toString } } - - // Private reflective version of "val io" to maintain Chisel.Module semantics without having - // io as a virtual method. See https://github.com/freechipsproject/chisel3/pull/1550 for more - // information about the removal of "val io" - private def reflectivelyFindValIO(self: BaseModule): Option[Record] = { - // Java reflection is faster and works for the common case - def tryJavaReflect: Option[Record] = Try { - self.getClass.getMethod("io").invoke(self).asInstanceOf[Record] - }.toOption - .filter(_ != null) - // Anonymous subclasses don't work with Java reflection, so try slower, Scala reflection - def tryScalaReflect: Option[Record] = { - val ru = scala.reflect.runtime.universe - import ru.{Try => _, _} - val m = ru.runtimeMirror(self.getClass.getClassLoader) - val im = m.reflect(self) - val tpe = im.symbol.toType - // For some reason, in anonymous subclasses, looking up the Term by name (TermName("io")) - // hits an internal exception. Searching for the term seems to work though so we use that. - val ioTerm: Option[TermSymbol] = tpe.decls.collectFirst { - case d if d.name.toString == "io" && d.isTerm => d.asTerm - } - ioTerm.flatMap { term => - Try { - im.reflectField(term).get.asInstanceOf[Record] - }.toOption - .filter(_ != null) - } - } - - tryJavaReflect - .orElse(tryScalaReflect) - .map(_.forceFinalName("io")) - .orElse { - // Fallback if reflection fails, user can wrap in IO(...) - self.findPort("io").collect { case r: Record => r } - } - } - - /** Legacy Module class that restricts IOs to just io, clock, and reset, and provides a constructor - * for threading through explicit clock and reset. - * - * '''Do not use this class in user code'''. Use whichever `Module` is imported by your wildcard - * import (preferably `import chisel3._`). - */ - abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions) extends Module { - // Provide a non-deprecated constructor - def this( - override_clock: Option[Clock] = None, - override_reset: Option[Bool] = None - )( - implicit moduleCompileOptions: CompileOptions - ) = { - this() - this.override_clock = override_clock - this.override_reset = override_reset - } - def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = - this(Option(_clock), None)(moduleCompileOptions) - def this(_reset: Bool)(implicit moduleCompileOptions: CompileOptions) = - this(None, Option(_reset))(moduleCompileOptions) - def this(_clock: Clock, _reset: Bool)(implicit moduleCompileOptions: CompileOptions) = - this(Option(_clock), Option(_reset))(moduleCompileOptions) - - // Sort of a DIY lazy val because if the user tries to construct hardware before val io is - // constructed, _compatAutoWrapPorts will try to access it but it will be null - // In that case, we basically need to delay setting this var until later - private var _ioValue: Option[Record] = None - private def _io: Option[Record] = _ioValue.orElse { - _ioValue = reflectivelyFindValIO(this) - _ioValue - } - - // Allow access to bindings from the compatibility package - protected def _compatIoPortBound() = _io.exists(portsContains(_)) - - private[chisel3] override def generateComponent(): Option[Component] = { - _compatAutoWrapPorts() // pre-IO(...) compatibility hack - - // Restrict IO to just io, clock, and reset - if (_io.isEmpty || !_compatIoPortBound) { - throwException( - s"Compatibility mode Module '$this' must have a 'val io' Bundle. " + - "If there is such a field and you still see this error, autowrapping has failed (sorry!). " + - "Please wrap the Bundle declaration in IO(...)." - ) - } - require( - (portsContains(clock)) && (portsContains(reset)), - "Internal error, module did not have clock or reset as IO" - ) - require(portsSize == 3, "Module must only have io, clock, and reset as IO") - - super.generateComponent() - } - - override def _compatAutoWrapPorts(): Unit = { - if (!_compatIoPortBound()) { - _io.foreach(_bindIoInPlace(_)) - } - } - } - - import chisel3.experimental.Param - - /** Legacy BlackBox class will reflectively autowrap val io - * - * '''Do not use this class in user code'''. Use whichever `BlackBox` is imported by your wildcard - * import (preferably `import chisel3._`). - */ - abstract class LegacyBlackBox( - params: Map[String, Param] = Map.empty[String, Param] - )( - implicit moduleCompileOptions: CompileOptions) - extends chisel3.BlackBox(params) { - - override private[chisel3] lazy val _io: Option[Record] = reflectivelyFindValIO(this) - - // This class auto-wraps the BlackBox with IO(...), allowing legacy code (where IO(...) wasn't - // required) to build. - override def _compatAutoWrapPorts(): Unit = { - if (!_compatIoPortBound()) { - _io.foreach(_bindIoInPlace(_)) - } - } - } - - /** Internal API for [[ViewParent]] */ - sealed private[chisel3] class ViewParentAPI extends RawModule()(ExplicitCompileOptions.Strict) with PseudoModule { - // We must provide `absoluteTarget` but not `toTarget` because otherwise they would be exactly - // the same and we'd have no way to distinguish the kind of target when renaming view targets in - // the Converter - // Note that this is not overriding .toAbsoluteTarget, that is a final def in BaseModule that delegates - // to this method - private[chisel3] val absoluteTarget: IsModule = ModuleTarget(this.circuitName, "_$$AbsoluteView$$_") - - // This module is not instantiable - override private[chisel3] def generateComponent(): Option[Component] = None - override private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = () - // This module is not really part of the circuit - _parent = None - - // Sigil to mark views, starts with '_' to make it a legal FIRRTL target - override def desiredName = "_$$View$$_" - - private[chisel3] val fakeComponent: Component = DefModule(this, desiredName, Nil, Nil) - } - - /** Special internal object representing the parent of all views - * - * @note this is a val instead of an object because of the need to wrap in Module(...) - */ - private[chisel3] val ViewParent = - Module.do_apply(new ViewParentAPI)(UnlocatableSourceInfo, ExplicitCompileOptions.Strict) } diff --git a/core/src/main/scala/chisel3/SIntFactory.scala b/core/src/main/scala/chisel3/SIntFactory.scala index 3fafacda..8cceda13 100644 --- a/core/src/main/scala/chisel3/SIntFactory.scala +++ b/core/src/main/scala/chisel3/SIntFactory.scala @@ -2,7 +2,7 @@ package chisel3 -import chisel3.internal.firrtl.{IntervalRange, SLit, Width} +import chisel3.internal.firrtl.{SLit, Width} trait SIntFactory { @@ -12,11 +12,6 @@ trait SIntFactory { /** Create a SInt type or port with fixed width. */ def apply(width: Width): SInt = new SInt(width) - /** Create a SInt with the specified range */ - def apply(range: IntervalRange): SInt = { - apply(range.getWidth) - } - /** Create an SInt literal with specified width. */ protected[chisel3] def Lit(value: BigInt, width: Width): SInt = { val lit = SLit(value, width) diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala index 9d975349..6cc7b6cf 100644 --- a/core/src/main/scala/chisel3/SeqUtils.scala +++ b/core/src/main/scala/chisel3/SeqUtils.scala @@ -2,7 +2,6 @@ package chisel3 -import chisel3.experimental.FixedPoint import chisel3.internal.{prefix, throwException} import scala.language.experimental.macros @@ -73,9 +72,6 @@ private[chisel3] object SeqUtils { /** Returns the data value corresponding to the lone true predicate. * This is elaborated to firrtl using a structure that should be optimized into and and/or tree. - * - * @note assumes exactly one true predicate, results undefined otherwise - * FixedPoint values or aggregates containing FixedPoint values cause this optimized structure to be lost */ def oneHotMux[T <: Data](in: Iterable[(Bool, T)]): T = macro SourceInfoTransform.inArg @@ -108,26 +104,6 @@ private[chisel3] object SeqUtils { val masked = for ((s, i) <- sInts) yield Mux(s, i, 0.S) masked.reduceLeft(_ | _).asTypeOf(output) - case _: FixedPoint => - val (sels, possibleOuts) = in.toSeq.unzip - - val (intWidths, binaryPoints) = in.toSeq.map { - case (_, o) => - val fo = o.asInstanceOf[FixedPoint] - require(fo.binaryPoint.known, "Mux1H requires width/binary points to be defined") - (fo.getWidth - fo.binaryPoint.get, fo.binaryPoint.get) - }.unzip - - if (intWidths.distinct.length == 1 && binaryPoints.distinct.length == 1) { - buildAndOrMultiplexor(in) - } else { - val maxIntWidth = intWidths.max - val maxBP = binaryPoints.max - val inWidthMatched = Seq.fill(intWidths.length)(Wire(FixedPoint((maxIntWidth + maxBP).W, maxBP.BP))) - inWidthMatched.zipWithIndex.foreach { case (e, idx) => e := possibleOuts(idx).asInstanceOf[FixedPoint] } - buildAndOrMultiplexor(sels.zip(inWidthMatched)) - } - case agg: Aggregate => val allDefineWidth = in.forall { case (_, element) => element.widthOption.isDefined } if (allDefineWidth) { diff --git a/core/src/main/scala/chisel3/UIntFactory.scala b/core/src/main/scala/chisel3/UIntFactory.scala index 64127991..66c6f9c8 100644 --- a/core/src/main/scala/chisel3/UIntFactory.scala +++ b/core/src/main/scala/chisel3/UIntFactory.scala @@ -2,7 +2,7 @@ package chisel3 -import chisel3.internal.firrtl.{IntervalRange, KnownWidth, ULit, UnknownWidth, Width} +import chisel3.internal.firrtl.{KnownWidth, ULit, UnknownWidth, Width} import firrtl.Utils import firrtl.constraint.IsKnown import firrtl.ir.{Closed, IntWidth, Open} @@ -23,26 +23,4 @@ trait UIntFactory { // Bind result to being an Literal lit.bindLitArg(result) } - - /** Create a UInt with the specified range, validate that range is effectively > 0 - */ - def apply(range: IntervalRange): UInt = { - // Check is only done against lower bound because range will already insist that range high >= low - range.lowerBound match { - case Closed(bound) if bound < 0 => - throw new ChiselException(s"Attempt to create UInt with closed lower bound of $bound, must be > 0") - case Open(bound) if bound < -1 => - throw new ChiselException(s"Attempt to create UInt with open lower bound of $bound, must be > -1") - case _ => - } - - // because this is a UInt we don't have to take into account the lower bound - val newWidth = if (range.upperBound.isInstanceOf[IsKnown]) { - KnownWidth(Utils.getUIntWidth(range.maxAdjusted.get).max(1)) // max(1) handles range"[0,0]" - } else { - UnknownWidth() - } - - apply(newWidth) - } } diff --git a/core/src/main/scala/chisel3/aop/Aspect.scala b/core/src/main/scala/chisel3/aop/Aspect.scala deleted file mode 100644 index dd014357..00000000 --- a/core/src/main/scala/chisel3/aop/Aspect.scala +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.aop - -import chisel3.RawModule -import firrtl.annotations.{Annotation, NoTargetAnnotation} -import firrtl.options.Unserializable -import firrtl.AnnotationSeq - -/** Represents an aspect of a Chisel module, by specifying - * what behavior should be done to instance, via the FIRRTL Annotation Mechanism - * @tparam T Type of top-level module - */ -abstract class Aspect[T <: RawModule] extends Annotation with Unserializable with NoTargetAnnotation { - - /** variable to save [[AnnotationSeq]] from [[chisel3.stage.phases.AspectPhase]] - * to be used at [[chisel3.aop.injecting.InjectorAspect]], exposes annotations to [[chisel3.internal.DynamicContext]] - */ - private[aop] var annotationsInAspect: AnnotationSeq = Seq() - - /** Convert this Aspect to a seq of FIRRTL annotation - * @param top - * @return - */ - def toAnnotation(top: T): AnnotationSeq - - /** Called by [[chisel3.stage.phases.AspectPhase]] to resolve this Aspect into annotations - * @param top - * @return - */ - private[chisel3] def resolveAspect(top: RawModule, remainingAnnotations: AnnotationSeq): AnnotationSeq = { - annotationsInAspect = remainingAnnotations - toAnnotation(top.asInstanceOf[T]) - } -} - -/** Holds utility functions for Aspect stuff */ -object Aspect { - - /** Converts elaborated Chisel components to FIRRTL modules - * @param chiselIR - * @return - */ - def getFirrtl(chiselIR: chisel3.internal.firrtl.Circuit): firrtl.ir.Circuit = { - chisel3.internal.firrtl.Converter.convert(chiselIR) - } -} diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala index 7d89025c..7bb0ac5d 100644 --- a/core/src/main/scala/chisel3/experimental/Analog.scala +++ b/core/src/main/scala/chisel3/experimental/Analog.scala @@ -13,7 +13,6 @@ import chisel3.{ Element, PString, Printable, - RawModule, SpecifiedDirection, UInt } @@ -50,7 +49,7 @@ final class Analog private (private[chisel3] val width: Width) extends Element { // Used to enforce single bulk connect of Analog types, multi-attach is still okay // Note that this really means 1 bulk connect per Module because a port can // be connected in the parent module as well - private[chisel3] val biConnectLocs = mutable.Map.empty[RawModule, SourceInfo] + private[chisel3] val biConnectLocs = mutable.Map.empty[BaseModule, SourceInfo] // Define setter/getter pairing // Analog can only be bound to Ports and Wires (and Unbound) diff --git a/core/src/main/scala/chisel3/experimental/Attach.scala b/core/src/main/scala/chisel3/experimental/Attach.scala index 5c9cfe53..1d32e941 100644 --- a/core/src/main/scala/chisel3/experimental/Attach.scala +++ b/core/src/main/scala/chisel3/experimental/Attach.scala @@ -15,7 +15,7 @@ object attach { AttachException(": Conditional attach is not allowed!") // Actual implementation - private[chisel3] def impl(elts: Seq[Analog], contextModule: RawModule)(implicit sourceInfo: SourceInfo): Unit = { + private[chisel3] def impl(elts: Seq[Analog], contextModule: BaseModule)(implicit sourceInfo: SourceInfo): Unit = { if (Builder.whenDepth != 0) throw ConditionalAttachException // TODO Check that references are valid and can be attached diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala deleted file mode 100644 index c6ebe604..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.dataview - -import chisel3.experimental.BaseModule -import chisel3.{getRecursiveFields, Data, Vec} - -import scala.annotation.implicitNotFound - -/** Typeclass interface for getting elements of type [[Data]] - * - * This is needed for validating [[DataView]]s targeting type `A`. - * Can be thought of as "can be the Target of a DataView". - * - * Chisel provides some implementations in [[DataProduct$ object DataProduct]] that are available - * by default in the implicit scope. - * - * @tparam A Type that has elements of type [[Data]] - * @see [[https://www.chisel-lang.org/chisel3/docs/explanations/dataview#dataproduct Detailed Documentation]] - */ -@implicitNotFound( - "Could not find implicit value for DataProduct[${A}].\n" + - "Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview#dataproduct" -) -trait DataProduct[-A] { - - /** Provides [[Data]] elements within some containing object - * - * @param a Containing object - * @param path Hierarchical path to current signal (for error reporting) - * @return Data elements and associated String paths (Strings for error reporting only!) - */ - def dataIterator(a: A, path: String): Iterator[(Data, String)] - - /** Returns a checker to test if the containing object contains a `Data` object - * @note Implementers may want to override if iterating on all `Data` is expensive for `A` and `A` - * will primarily be used in `PartialDataViews` - * @note The returned value is a function, not a true Set, but is describing the functionality of - * Set containment - * @param a Containing object - * @return A checker that itself returns True if a given `Data` is contained in `a` - * as determined by an `==` test - */ - def dataSet(a: A): Data => Boolean = dataIterator(a, "").map(_._1).toSet -} - -/** Low priority built-in implementations of [[DataProduct]] - * - * @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity - */ -sealed trait LowPriorityDataProduct { - - /** [[DataProduct]] implementation for [[Data]] */ - implicit val dataDataProduct: DataProduct[Data] = new DataProduct[Data] { - def dataIterator(a: Data, path: String): Iterator[(Data, String)] = - getRecursiveFields.lazily(a, path).iterator - } -} - -/** Encapsulating object for built-in implementations of [[DataProduct]] - * - * @note DataProduct implementations provided in this object are available in the implicit scope - */ -object DataProduct extends LowPriorityDataProduct { - - /** [[DataProduct]] implementation for [[BaseModule]] */ - implicit val userModuleDataProduct: DataProduct[BaseModule] = new DataProduct[BaseModule] { - def dataIterator(a: BaseModule, path: String): Iterator[(Data, String)] = { - a.getIds.iterator.flatMap { - case d: Data if d.getOptionRef.isDefined => // Using ref to decide if it's truly hardware in the module - Seq(d -> s"${path}.${d.instanceName}") - case b: BaseModule => dataIterator(b, s"$path.${b.instanceName}") - case _ => Seq.empty - } - } - // Overridden for performance - override def dataSet(a: BaseModule): Data => Boolean = { - val lastId = a._lastId // Not cheap to compute - // Return a function - e => e._id > a._id && e._id <= lastId - } - } - - /** [[DataProduct]] implementation for any `Seq[A]` where `A` has an implementation of `DataProduct`. */ - implicit def seqDataProduct[A: DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] { - def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - a.iterator.zipWithIndex.flatMap { - case (elt, idx) => - dpa.dataIterator(elt, s"$path[$idx]") - } - } - } - - /** [[DataProduct]] implementation for any [[Tuple2]] where each field has an implementation of `DataProduct`. */ - implicit def tuple2DataProduct[A: DataProduct, B: DataProduct]: DataProduct[(A, B)] = new DataProduct[(A, B)] { - def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val (a, b) = tup - dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") - } - } - - /** [[DataProduct]] implementation for any [[Tuple3]] where each field has an implementation of `DataProduct`. */ - implicit def tuple3DataProduct[A: DataProduct, B: DataProduct, C: DataProduct]: DataProduct[(A, B, C)] = - new DataProduct[(A, B, C)] { - def dataIterator(tup: (A, B, C), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val (a, b, c) = tup - dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") ++ dpc.dataIterator(c, s"$path._3") - } - } - - /** [[DataProduct]] implementation for any [[Tuple4]] where each field has an implementation of `DataProduct`. */ - implicit def tuple4DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct - ]: DataProduct[(A, B, C, D)] = - new DataProduct[(A, B, C, D)] { - def dataIterator(tup: (A, B, C, D), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val (a, b, c, d) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") - } - } - - /** [[DataProduct]] implementation for any [[Tuple5]] where each field has an implementation of `DataProduct`. */ - implicit def tuple5DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct - ]: DataProduct[(A, B, C, D, E)] = - new DataProduct[(A, B, C, D, E)] { - def dataIterator(tup: (A, B, C, D, E), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val (a, b, c, d, e) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") - } - } - - /** [[DataProduct]] implementation for any [[Tuple6]] where each field has an implementation of `DataProduct`. */ - implicit def tuple6DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct - ]: DataProduct[(A, B, C, D, E, F)] = - new DataProduct[(A, B, C, D, E, F)] { - def dataIterator(tup: (A, B, C, D, E, F), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val (a, b, c, d, e, f) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") - } - } - - /** [[DataProduct]] implementation for any [[Tuple7]] where each field has an implementation of `DataProduct`. */ - implicit def tuple7DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G)] = - new DataProduct[(A, B, C, D, E, F, G)] { - def dataIterator(tup: (A, B, C, D, E, F, G), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val (a, b, c, d, e, f, g) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") - } - } - - /** [[DataProduct]] implementation for any [[Tuple8]] where each field has an implementation of `DataProduct`. */ - implicit def tuple8DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H)] = - new DataProduct[(A, B, C, D, E, F, G, H)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val (a, b, c, d, e, f, g, h) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") - } - } - - /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ - implicit def tuple9DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct, - I: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H, I)] = - new DataProduct[(A, B, C, D, E, F, G, H, I)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H, I), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val dpi = implicitly[DataProduct[I]] - val (a, b, c, d, e, f, g, h, i) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") ++ - dpi.dataIterator(i, s"$path._9") - } - } - - /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */ - implicit def tuple10DataProduct[ - A: DataProduct, - B: DataProduct, - C: DataProduct, - D: DataProduct, - E: DataProduct, - F: DataProduct, - G: DataProduct, - H: DataProduct, - I: DataProduct, - J: DataProduct - ]: DataProduct[(A, B, C, D, E, F, G, H, I, J)] = - new DataProduct[(A, B, C, D, E, F, G, H, I, J)] { - def dataIterator(tup: (A, B, C, D, E, F, G, H, I, J), path: String): Iterator[(Data, String)] = { - val dpa = implicitly[DataProduct[A]] - val dpb = implicitly[DataProduct[B]] - val dpc = implicitly[DataProduct[C]] - val dpd = implicitly[DataProduct[D]] - val dpe = implicitly[DataProduct[E]] - val dpf = implicitly[DataProduct[F]] - val dpg = implicitly[DataProduct[G]] - val dph = implicitly[DataProduct[H]] - val dpi = implicitly[DataProduct[I]] - val dpj = implicitly[DataProduct[J]] - val (a, b, c, d, e, f, g, h, i, j) = tup - dpa.dataIterator(a, s"$path._1") ++ - dpb.dataIterator(b, s"$path._2") ++ - dpc.dataIterator(c, s"$path._3") ++ - dpd.dataIterator(d, s"$path._4") ++ - dpe.dataIterator(e, s"$path._5") ++ - dpf.dataIterator(f, s"$path._6") ++ - dpg.dataIterator(g, s"$path._7") ++ - dph.dataIterator(h, s"$path._8") ++ - dpi.dataIterator(i, s"$path._9") ++ - dpj.dataIterator(j, s"$path._10") - } - } -} diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala deleted file mode 100644 index cc555b11..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala +++ /dev/null @@ -1,618 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.dataview - -import chisel3._ -import chisel3.experimental.DataMirror.internal.chiselTypeClone -import chisel3.experimental.{HWTuple10, HWTuple2, HWTuple3, HWTuple4, HWTuple5, HWTuple6, HWTuple7, HWTuple8, HWTuple9} -import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo} -import chisel3.ExplicitCompileOptions.Strict - -import scala.reflect.runtime.universe.WeakTypeTag -import annotation.implicitNotFound - -/** Mapping between a target type `T` and a view type `V` - * - * Enables calling `.viewAs[T]` on instances of the target type. - * - * ==Detailed documentation== - * - [[https://www.chisel-lang.org/chisel3/docs/explanations/dataview Explanation]] - * - [[https://www.chisel-lang.org/chisel3/docs/cookbooks/dataview Cookbook]] - * - * @example {{{ - * class Foo(val w: Int) extends Bundle { - * val a = UInt(w.W) - * } - * class Bar(val w: Int) extends Bundle { - * val b = UInt(w.W) - * } - * // DataViews are created using factory methods in the companion object - * implicit val view = DataView[Foo, Bar]( - * // The first argument is a function constructing a Foo from a Bar - * foo => new Bar(foo.w) - * // The remaining arguments are a variable number of field pairings - * _.a -> _.b - * ) - * }}} - * - * @tparam T Target type (must have an implementation of [[DataProduct]]) - * @tparam V View type - * @see [[DataView$ object DataView]] for factory methods - * @see [[PartialDataView object PartialDataView]] for defining non-total `DataViews` - */ -@implicitNotFound( - "Could not find implicit value for DataView[${T}, ${V}].\n" + - "Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview" -) -sealed class DataView[T: DataProduct, V <: Data] private[chisel3] ( - /** Function constructing an object of the View type from an object of the Target type */ - private[chisel3] val mkView: T => V, - /** Function that returns corresponding fields of the target and view */ - private[chisel3] val mapping: (T, V) => Iterable[(Data, Data)], - // Aliasing this with a def below to make the ScalaDoc show up for the field - _total: Boolean -)( - implicit private[chisel3] val sourceInfo: SourceInfo) { - - /** Indicates if the mapping contains every field of the target */ - def total: Boolean = _total - - override def toString: String = { - val base = sourceInfo.makeMessage(x => x) - val loc = if (base.nonEmpty) base else "@unknown" - val name = if (total) "DataView" else "PartialDataView" - s"$name(defined $loc)" - } - - /** Compose two `DataViews` together to construct a view from the target of this `DataView` to the - * view type of the second `DataView` - * - * @param g a DataView from `V` to new view-type `V2` - * @tparam V2 View type of `DataView` `g` - * @return a new `DataView` from the original `T` to new view-type `V2` - */ - def andThen[V2 <: Data](g: DataView[V, V2])(implicit sourceInfo: SourceInfo): DataView[T, V2] = { - val self = this - // We have to pass the DataProducts and DataViews manually to .viewAs below - val tdp = implicitly[DataProduct[T]] - val vdp = implicitly[DataProduct[V]] - new DataView[T, V2]( - t => g.mkView(mkView(t)), - { case (t, v2) => List(t.viewAs[V](tdp, self).viewAs[V2](vdp, g) -> v2) }, - this.total && g.total - ) { - override def toString: String = s"$self andThen $g" - } - } -} - -/** Factory methods for constructing [[DataView]]s, see class for example use */ -object DataView { - - /** Default factory method, alias for [[pairs]] */ - def apply[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - DataView.pairs(mkView, pairs: _*) - - /** Construct [[DataView]]s with pairs of functions from the target and view to corresponding fields */ - def pairs[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - mapping(mkView: T => V, swizzle(pairs)) - - /** More general factory method for complex mappings */ - def mapping[T: DataProduct, V <: Data]( - mkView: T => V, - mapping: (T, V) => Iterable[(Data, Data)] - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - new DataView[T, V](mkView, mapping, _total = true) - - /** Provides `invert` for invertible [[DataView]]s - * - * This must be done as an extension method because it applies an addition constraint on the `Target` - * type parameter, namely that it must be a subtype of [[Data]]. - * - * @note [[PartialDataView]]s are **not** invertible and will result in an elaboration time exception - */ - implicit class InvertibleDataView[T <: Data: WeakTypeTag, V <: Data: WeakTypeTag](view: DataView[T, V]) { - def invert(mkView: V => T): DataView[V, T] = { - // It would've been nice to make this a compiler error, but it's unclear how to make that work. - // We tried having separate TotalDataView and PartialDataView and only defining inversion for - // TotalDataView. For some reason, implicit resolution wouldn't invert TotalDataViews. This is - // probably because it was looking for the super-type DataView and since invertDataView was - // only defined on TotalDataView, it wasn't included in implicit resolution. Thus we end up - // with a runtime check. - if (!view.total) { - val tt = implicitly[WeakTypeTag[T]].tpe - val vv = implicitly[WeakTypeTag[V]].tpe - val msg = s"Cannot invert '$view' as it is non-total.\n Try providing a DataView[$vv, $tt]." + - s"\n Please see https://www.chisel-lang.org/chisel3/docs/explanations/dataview." - throw InvalidViewException(msg) - } - implicit val sourceInfo = view.sourceInfo - new DataView[V, T](mkView, swapArgs(view.mapping), view.total) - } - } - - private[dataview] def swizzle[A, B, C, D](fs: Iterable[(A, B) => (C, D)]): (A, B) => Iterable[(C, D)] = { - case (a, b) => fs.map(f => f(a, b)) - } - - private def swapArgs[A, B, C, D](f: (A, B) => Iterable[(C, D)]): (B, A) => Iterable[(D, C)] = { - case (b, a) => f(a, b).map(_.swap) - } - - // ****************************** Built-in Implementations of DataView ****************************** - // Sort of the "Standard library" implementations - - /** All Chisel Data are viewable as their own type */ - implicit def identityView[A <: Data](implicit sourceInfo: SourceInfo): DataView[A, A] = - DataView[A, A](chiselTypeOf.apply, { case (x, y) => (x, y) }) - - /** Provides `DataView[Seq[A], Vec[B]]` for all `A` such that there exists `DataView[A, B]` */ - implicit def seqDataView[A: DataProduct, B <: Data]( - implicit dv: DataView[A, B], - sourceInfo: SourceInfo - ): DataView[Seq[A], Vec[B]] = { - // TODO this would need a better way to determine the prototype for the Vec - DataView.mapping[Seq[A], Vec[B]]( - xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B]))(sourceInfo, Strict), // xs.head is not correct in general - { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } } - ) - } - - /** Provides implementations of [[DataView]] for [[Tuple2]] to [[HWTuple2]] */ - implicit def tuple2DataView[T1: DataProduct, T2: DataProduct, V1 <: Data, V2 <: Data]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - sourceInfo: SourceInfo - ): DataView[(T1, T2), HWTuple2[V1, V2]] = - DataView.mapping( - { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType) }, - { - case ((a, b), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple3]] to [[HWTuple3]] */ - implicit def tuple3DataView[T1: DataProduct, T2: DataProduct, T3: DataProduct, V1 <: Data, V2 <: Data, V3 <: Data]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3), HWTuple3[V1, V2, V3]] = - DataView.mapping( - { case (a, b, c) => new HWTuple3(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType) }, - { - case ((a, b, c), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2, c.viewAs[V3] -> hwt._3) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple4]] to [[HWTuple4]] */ - implicit def tuple4DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4), HWTuple4[V1, V2, V3, V4]] = - DataView.mapping( - { - case (a, b, c, d) => - new HWTuple4(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType) - }, - { - case ((a, b, c, d), hwt) => - Seq(a.viewAs[V1] -> hwt._1, b.viewAs[V2] -> hwt._2, c.viewAs[V3] -> hwt._3, d.viewAs[V4] -> hwt._4) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple5]] to [[HWTuple5]] */ - implicit def tuple5DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5), HWTuple5[V1, V2, V3, V4, V5]] = { - DataView.mapping( - { - case tup: Tuple5[T1, T2, T3, T4, T5] => - val (a, b, c, d, e) = tup - new HWTuple5( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType - ) - }, - { - case ((a, b, c, d, e), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5 - ) - } - ) - } - - /** Provides implementations of [[DataView]] for [[Tuple6]] to [[HWTuple6]] */ - implicit def tuple6DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6), HWTuple6[V1, V2, V3, V4, V5, V6]] = - DataView.mapping( - { - case (a, b, c, d, e, f) => - new HWTuple6( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType - ) - }, - { - case ((a, b, c, d, e, f), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple7]] to [[HWTuple7]] */ - implicit def tuple7DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7), HWTuple7[V1, V2, V3, V4, V5, V6, V7]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g) => - new HWTuple7( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple8]] to [[HWTuple8]] */ - implicit def tuple8DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8), HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h) => - new HWTuple8( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple9]] to [[HWTuple9]] */ - implicit def tuple9DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - T9: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data, - V9 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - v9: DataView[T9, V9], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9), HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h, i) => - new HWTuple9( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType, - i.viewAs[V9].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h, i), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8, - i.viewAs[V9] -> hwt._9 - ) - } - ) - - /** Provides implementations of [[DataView]] for [[Tuple10]] to [[HWTuple10]] */ - implicit def tuple10DataView[ - T1: DataProduct, - T2: DataProduct, - T3: DataProduct, - T4: DataProduct, - T5: DataProduct, - T6: DataProduct, - T7: DataProduct, - T8: DataProduct, - T9: DataProduct, - T10: DataProduct, - V1 <: Data, - V2 <: Data, - V3 <: Data, - V4 <: Data, - V5 <: Data, - V6 <: Data, - V7 <: Data, - V8 <: Data, - V9 <: Data, - V10 <: Data - ]( - implicit v1: DataView[T1, V1], - v2: DataView[T2, V2], - v3: DataView[T3, V3], - v4: DataView[T4, V4], - v5: DataView[T5, V5], - v6: DataView[T6, V6], - v7: DataView[T7, V7], - v8: DataView[T8, V8], - v9: DataView[T9, V9], - v10: DataView[T10, V10], - sourceInfo: SourceInfo - ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] = - DataView.mapping( - { - case (a, b, c, d, e, f, g, h, i, j) => - new HWTuple10( - a.viewAs[V1].cloneType, - b.viewAs[V2].cloneType, - c.viewAs[V3].cloneType, - d.viewAs[V4].cloneType, - e.viewAs[V5].cloneType, - f.viewAs[V6].cloneType, - g.viewAs[V7].cloneType, - h.viewAs[V8].cloneType, - i.viewAs[V9].cloneType, - j.viewAs[V10].cloneType - ) - }, - { - case ((a, b, c, d, e, f, g, h, i, j), hwt) => - Seq( - a.viewAs[V1] -> hwt._1, - b.viewAs[V2] -> hwt._2, - c.viewAs[V3] -> hwt._3, - d.viewAs[V4] -> hwt._4, - e.viewAs[V5] -> hwt._5, - f.viewAs[V6] -> hwt._6, - g.viewAs[V7] -> hwt._7, - h.viewAs[V8] -> hwt._8, - i.viewAs[V9] -> hwt._9, - j.viewAs[V10] -> hwt._10 - ) - } - ) -} - -/** Factory methods for constructing non-total [[DataView]]s */ -object PartialDataView { - - /** Default factory method, alias for [[pairs]] */ - def apply[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - PartialDataView.pairs(mkView, pairs: _*) - - /** Construct [[DataView]]s with pairs of functions from the target and view to corresponding fields */ - def pairs[T: DataProduct, V <: Data]( - mkView: T => V, - pairs: ((T, V) => (Data, Data))* - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - mapping(mkView, DataView.swizzle(pairs)) - - /** More general factory method for complex mappings */ - def mapping[T: DataProduct, V <: Data]( - mkView: T => V, - mapping: (T, V) => Iterable[(Data, Data)] - )( - implicit sourceInfo: SourceInfo - ): DataView[T, V] = - new DataView[T, V](mkView, mapping, _total = false) - - /** Constructs a non-total [[DataView]] mapping from a [[Bundle]] type to a parent [[Bundle]] type - * - * @param mkView a function constructing an instance `V` from an instance of `T` - * @return the [[DataView]] that enables viewing instances of a [[Bundle]] as instances of a parent type - */ - def supertype[T <: Bundle, V <: Bundle]( - mkView: T => V - )( - implicit ev: SubTypeOf[T, V], - sourceInfo: SourceInfo - ): DataView[T, V] = - mapping[T, V]( - mkView, - { - case (a, b) => - val aElts = a.elements - val bElts = b.elements - val bKeys = bElts.keySet - val keys = aElts.keysIterator.filter(bKeys.contains) - keys.map(k => aElts(k) -> bElts(k)).toSeq - } - ) -} diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala deleted file mode 100644 index a52e88cf..00000000 --- a/core/src/main/scala/chisel3/experimental/dataview/package.scala +++ /dev/null @@ -1,268 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental - -import chisel3._ -import chisel3.internal._ -import chisel3.internal.sourceinfo.SourceInfo - -import scala.annotation.{implicitNotFound, tailrec} -import scala.collection.mutable -import scala.collection.immutable.LazyList // Needed for 2.12 alias - -package object dataview { - case class InvalidViewException(message: String) extends ChiselException(message) - - /** Provides `viewAs` for types that have an implementation of [[DataProduct]] - * - * Calling `viewAs` also requires an implementation of [[DataView]] for the target type - */ - implicit class DataViewable[T](target: T) { - def viewAs[V <: Data](implicit dataproduct: DataProduct[T], dataView: DataView[T, V]): V = { - // TODO put a try catch here for ExpectedHardwareException and perhaps others - // It's likely users will accidentally use chiselTypeOf or something that may error, - // The right thing to use is DataMirror...chiselTypeClone because of composition with DataView.andThen - // Another option is that .andThen could give a fake binding making chiselTypeOfs in the user code safe - val result: V = dataView.mkView(target) - requireIsChiselType(result, "viewAs") - - doBind(target, result, dataView) - - // Setting the parent marks these Data as Views - result.setAllParents(Some(ViewParent)) - // The names of views do not matter except for when a view is annotated. For Views that correspond - // To a single Data, we just forward the name of the Target. For Views that correspond to more - // than one Data, we return this assigned name but rename it in the Convert stage - result.forceName("view", Builder.viewNamespace) - result - } - } - - // This private type alias lets us provide a custom error message for misuing the .viewAs for upcasting Bundles - @implicitNotFound( - "${A} is not a subtype of ${B}! Did you mean .viewAs[${B}]? " + - "Please see https://www.chisel-lang.org/chisel3/docs/cookbooks/dataview" - ) - private[dataview] type SubTypeOf[A, B] = A <:< B - - /** Provides `viewAsSupertype` for subclasses of [[Bundle]] */ - implicit class BundleUpcastable[T <: Bundle](target: T) { - - /** View a [[Bundle]] or [[Record]] as a parent type (upcast) */ - def viewAsSupertype[V <: Bundle](proto: V)(implicit ev: SubTypeOf[T, V], sourceInfo: SourceInfo): V = { - implicit val dataView = PartialDataView.supertype[T, V](_ => proto) - target.viewAs[V] - } - } - - private def nonTotalViewException( - dataView: DataView[_, _], - target: Any, - view: Data, - targetFields: Seq[String], - viewFields: Seq[String] - ) = { - def missingMsg(name: String, fields: Seq[String]): Option[String] = { - val str = fields.mkString(", ") - fields.size match { - case 0 => None - case 1 => Some(s"$name field '$str' is missing") - case _ => Some(s"$name fields '$str' are missing") - } - } - val vs = missingMsg("view", viewFields) - val ts = missingMsg("target", targetFields) - val reasons = (ts ++ vs).mkString(" and ").capitalize - val suggestion = if (ts.nonEmpty) "\n If the view *should* be non-total, try a 'PartialDataView'." else "" - val msg = s"Viewing $target as $view is non-Total!\n $reasons.\n DataView used is $dataView.$suggestion" - throw InvalidViewException(msg) - } - - // TODO should this be moved to class Aggregate / can it be unified with Aggregate.bind? - private def doBind[T: DataProduct, V <: Data](target: T, view: V, dataView: DataView[T, V]): Unit = { - val mapping = dataView.mapping(target, view) - val total = dataView.total - // Lookups to check the mapping results - val viewFieldLookup: Map[Data, String] = getRecursiveFields(view, "_").toMap - val targetContains: Data => Boolean = implicitly[DataProduct[T]].dataSet(target) - - // Resulting bindings for each Element of the View - // Kept separate from Aggregates for totality checking - val elementBindings = - new mutable.HashMap[Data, mutable.ListBuffer[Element]] ++ - viewFieldLookup.view.collect { case (elt: Element, _) => elt } - .map(_ -> new mutable.ListBuffer[Element]) - - // Record any Aggregates that correspond 1:1 for reification - // Using Data instead of Aggregate to avoid unnecessary checks - val aggregateMappings = mutable.ArrayBuffer.empty[(Data, Data)] - - def viewFieldName(d: Data): String = - viewFieldLookup.get(d).map(_ + " ").getOrElse("") + d.toString - - // Helper for recording the binding of each - def onElt(te: Element, ve: Element): Unit = { - // TODO can/should we aggregate these errors? - def err(name: String, arg: Data) = - throw InvalidViewException(s"View mapping must only contain Elements within the $name, got $arg") - - // The elements may themselves be views, look through the potential chain of views for the Elements - // that are actually members of the target or view - val tex = unfoldView(te).find(targetContains).getOrElse(err("Target", te)) - val vex = unfoldView(ve).find(viewFieldLookup.contains).getOrElse(err("View", ve)) - - if (tex.getClass != vex.getClass) { - val fieldName = viewFieldName(vex) - throw InvalidViewException(s"Field $fieldName specified as view of non-type-equivalent value $tex") - } - // View width must be unknown or match target width - if (vex.widthKnown && vex.width != tex.width) { - def widthAsString(x: Element) = x.widthOption.map("<" + _ + ">").getOrElse("<unknown>") - val fieldName = viewFieldName(vex) - val vwidth = widthAsString(vex) - val twidth = widthAsString(tex) - throw InvalidViewException( - s"View field $fieldName has width ${vwidth} that is incompatible with target value $tex's width ${twidth}" - ) - } - elementBindings(vex) += tex - } - - mapping.foreach { - // Special cased because getMatchedFields checks typeEquivalence on Elements (and is used in Aggregate path) - // Also saves object allocations on common case of Elements - case (ae: Element, be: Element) => onElt(ae, be) - - case (aa: Aggregate, ba: Aggregate) => - if (!ba.typeEquivalent(aa)) { - val fieldName = viewFieldLookup(ba) - throw InvalidViewException(s"field $fieldName specified as view of non-type-equivalent value $aa") - } - getMatchedFields(aa, ba).foreach { - case (aelt: Element, belt: Element) => onElt(aelt, belt) - case (t, v) => aggregateMappings += (v -> t) - } - } - - // Errors in totality of the View, use var List to keep fast path cheap (no allocation) - var viewNonTotalErrors: List[Data] = Nil - var targetNonTotalErrors: List[String] = Nil - - val targetSeen: Option[mutable.Set[Data]] = if (total) Some(mutable.Set.empty[Data]) else None - - val elementResult = elementBindings.map { - case (data, targets) => - val targetsx = targets match { - case collection.Seq(target: Element) => target - case collection.Seq() => - viewNonTotalErrors = data :: viewNonTotalErrors - data.asInstanceOf[Element] // Return the Data itself, will error after this map, cast is safe - case x => - throw InvalidViewException(s"Got $x, expected Seq(_: Direct)") - } - // TODO record and report aliasing errors - targetSeen.foreach(_ += targetsx) - data -> targetsx - }.toMap - - // Check for totality of Target - targetSeen.foreach { seen => - val lookup = implicitly[DataProduct[T]].dataIterator(target, "_") - for (missed <- lookup.collect { case (d: Element, name) if !seen(d) => name }) { - targetNonTotalErrors = missed :: targetNonTotalErrors - } - } - if (viewNonTotalErrors != Nil || targetNonTotalErrors != Nil) { - val viewErrors = viewNonTotalErrors.map(f => viewFieldLookup.getOrElse(f, f.toString)) - nonTotalViewException(dataView, target, view, targetNonTotalErrors, viewErrors) - } - - view match { - case elt: Element => view.bind(ViewBinding(elementResult(elt))) - case agg: Aggregate => - // Don't forget the potential mapping of the view to the target! - target match { - case d: Data if total => - aggregateMappings += (agg -> d) - case _ => - } - - val fullResult = elementResult ++ aggregateMappings - - // We need to record any Aggregates that don't have a 1-1 mapping (including the view - // itself) - getRecursiveFields.lazily(view, "_").foreach { - case (unnamed: Aggregate, _) if !fullResult.contains(unnamed) => - Builder.unnamedViews += unnamed - case _ => // Do nothing - } - agg.bind(AggregateViewBinding(fullResult)) - } - } - - // Traces an Element that may (or may not) be a view until it no longer maps - // Inclusive of the argument - private def unfoldView(elt: Element): LazyList[Element] = { - def rec(e: Element): LazyList[Element] = e.topBindingOpt match { - case Some(ViewBinding(target)) => target #:: rec(target) - case Some(avb: AggregateViewBinding) => - val target = avb.lookup(e).get - target #:: rec(target) - case Some(_) | None => LazyList.empty - } - elt #:: rec(elt) - } - - // Safe for all Data - private[chisel3] def isView(d: Data): Boolean = d._parent.contains(ViewParent) - - /** Turn any [[Element]] that could be a View into a concrete Element - * - * This is the fundamental "unwrapping" or "tracing" primitive operation for handling Views within - * Chisel. - */ - private[chisel3] def reify(elt: Element): Element = - reify(elt, elt.topBinding) - - /** Turn any [[Element]] that could be a View into a concrete Element - * - * This is the fundamental "unwrapping" or "tracing" primitive operation for handling Views within - * Chisel. - */ - @tailrec private[chisel3] def reify(elt: Element, topBinding: TopBinding): Element = - topBinding match { - case ViewBinding(target) => reify(target, elt.topBinding) - case _ => elt - } - - /** Determine the target of a View if it is a single Target - * - * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this - * there is no single Data representing the Target and this function will return None - * @return The single Data target of this view or None if a single Data doesn't exist - */ - private[chisel3] def reifySingleData(data: Data): Option[Data] = { - val candidate: Option[Data] = - data.topBindingOpt match { - case None => None - case Some(ViewBinding(target)) => Some(target) - case Some(AggregateViewBinding(lookup)) => lookup.get(data) - case Some(_) => None - } - candidate.flatMap { d => - // Candidate may itself be a view, keep tracing in those cases - if (isView(d)) reifySingleData(d) else Some(d) - } - } - - /** Determine the target of a View if it is a single Target - * - * @note An Aggregate may be a view of unrelated [[Data]] (eg. like a Seq or tuple) and thus this - * there is no single Data representing the Target and this function will return None - * @return The single Data target of this view or None if a single Data doesn't exist - */ - private[chisel3] def reifyToAggregate(data: Data): Option[Aggregate] = reifySingleData(data) match { - case Some(a: Aggregate) => Some(a) - case other => None - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala deleted file mode 100644 index 99eacc7d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.language.experimental.macros -import chisel3._ - -import scala.collection.mutable.HashMap -import chisel3.internal.{Builder, DynamicContext} -import chisel3.internal.sourceinfo.{DefinitionTransform, DefinitionWrapTransform, SourceInfo} -import chisel3.experimental.BaseModule -import chisel3.internal.BaseModule.IsClone -import firrtl.annotations.{IsModule, ModuleTarget} -import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation} - -/** User-facing Definition type. - * Represents a definition of an object of type [[A]] which are marked as @instantiable - * Can be created using Definition.apply method. - * - * These definitions are then used to create multiple [[Instance]]s. - * - * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object - */ -final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) - extends IsLookupable - with SealedHierarchy[A] { - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the instance. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C = { - lookup.definitionLookup(that, this) - } - - /** @return the context of any Data's return from inside the instance */ - private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match { - case value: BaseModule => - val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))( - chisel3.internal.sourceinfo.UnlocatableSourceInfo, - chisel3.ExplicitCompileOptions.Strict - ) - newChild._circuit = value._circuit.orElse(Some(value)) - newChild._parent = None - Some(newChild) - case value: IsInstantiable => None - } - - override def toDefinition: Definition[A] = this - override def toInstance: Instance[A] = new Instance(underlying) - -} - -/** Factory methods for constructing [[Definition]]s */ -object Definition extends SourceInfoDoc { - implicit class DefinitionBaseModuleExtensions[T <: BaseModule](d: Definition[T]) { - - /** If this is an instance of a Module, returns the toTarget of this instance - * @return target of this instance - */ - def toTarget: ModuleTarget = d.proto.toTarget - - /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance - * @return absoluteTarget of this instance - */ - def toAbsoluteTarget: IsModule = d.proto.toAbsoluteTarget - } - - /** A construction method to build a Definition of a Module - * - * @param proto the Module being defined - * - * @return the input module as a Definition - */ - def apply[T <: BaseModule with IsInstantiable](proto: => T): Definition[T] = macro DefinitionTransform.apply[T] - - /** A construction method to build a Definition of a Module - * - * @param bc the Module being defined - * - * @return the input module as a Definition - */ - def do_apply[T <: BaseModule with IsInstantiable]( - proto: => T - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Definition[T] = { - val dynamicContext = { - val context = Builder.captureContext() - new DynamicContext(Nil, context.throwOnFirstError, context.warnReflectiveNaming, context.warningsAsErrors) - } - Builder.globalNamespace.copyTo(dynamicContext.globalNamespace) - dynamicContext.inDefinition = true - val (ir, module) = Builder.build(Module(proto), dynamicContext, false) - Builder.components ++= ir.components - Builder.annotations ++= ir.annotations - module._circuit = Builder.currentModule - dynamicContext.globalNamespace.copyTo(Builder.globalNamespace) - new Definition(Proto(module)) - } - -} - -/** Stores a [[Definition]] that is imported so that its Instances can be - * compiled separately. - */ -case class ImportDefinitionAnnotation[T <: BaseModule with IsInstantiable]( - definition: Definition[T], - overrideDefName: Option[String] = None) - extends NoTargetAnnotation diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala deleted file mode 100644 index 2016bb54..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala +++ /dev/null @@ -1,117 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3._ -import scala.collection.mutable.{HashMap, HashSet} -import scala.reflect.runtime.universe.TypeTag -import chisel3.internal.BaseModule.IsClone -import chisel3.experimental.BaseModule -import _root_.firrtl.annotations.IsModule -import scala.annotation.implicitNotFound - -/** Super-trait for Instance and Definition - * - * Enables writing functions which are Instance/Definition agnostic - */ -sealed trait Hierarchy[+A] { - private[chisel3] def underlying: Underlying[A] - private[chisel3] def proto: A = underlying match { - case Proto(value: A) => value - case Clone(i: IsClone[A]) => i.getProto - } - - /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */ - private[chisel3] val cache = HashMap[Data, Data]() - private[chisel3] def getInnerDataContext: Option[BaseModule] - - /** Determine whether underlying proto is of type provided. - * - * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class. - * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure. - * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type - * - * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String] - * @return Whether underlying proto is of provided type (with caveats outlined above) - */ - def isA[B: TypeTag]: Boolean = { - val tptag = implicitly[TypeTag[B]] - // drop any type information for the comparison, because the proto will not have that information. - val name = tptag.tpe.toString.takeWhile(_ != '[') - inBaseClasses(name) - } - - // This code handles a special-case where, within an mdoc context, the type returned from - // scala reflection (typetag) looks different than when returned from java reflection. - // This function detects this case and reshapes the string to match. - private def modifyReplString(clz: String): String = { - if (clz != null) { - clz.split('.').toList match { - case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".") - case other => clz - } - } else clz - } - private lazy val superClasses = calculateSuperClasses(proto.getClass()) - private def calculateSuperClasses(clz: Class[_]): Set[String] = { - if (clz != null) { - Set(modifyReplString(clz.getCanonicalName())) ++ - clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++ - calculateSuperClasses(clz.getSuperclass()) - } else { - Set.empty[String] - } - } - private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz) - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the hierarchy. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C - - /** @return Return the underlying Definition[A] of this Hierarchy[A] */ - def toDefinition: Definition[A] - - /** @return Convert this Hierarchy[A] as a top-level Instance[A] */ - def toInstance: Instance[A] -} - -// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file. -private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A] - -object Hierarchy { - implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) { - - /** Returns the toTarget of this hierarchy - * @return target of this hierarchy - */ - def toTarget: IsModule = i match { - case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget - case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget - } - - /** Returns the toAbsoluteTarget of this hierarchy - * @return absoluteTarget of this Hierarchy - */ - def toAbsoluteTarget: IsModule = i match { - case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget - case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget - } - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala deleted file mode 100644 index 861023a1..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.language.experimental.macros -import chisel3._ -import chisel3.internal.BaseModule.{InstantiableClone, IsClone, ModuleClone} -import chisel3.internal.Builder -import chisel3.internal.sourceinfo.{InstanceTransform, SourceInfo} -import chisel3.experimental.{BaseModule, ExtModule} -import chisel3.internal.firrtl.{Component, DefBlackBox, DefModule, Port} -import firrtl.annotations.IsModule -import chisel3.internal.throwException - -/** User-facing Instance type. - * Represents a unique instance of type [[A]] which are marked as @instantiable - * Can be created using Instance.apply method. - * - * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object - */ -final case class Instance[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) extends SealedHierarchy[A] { - underlying match { - case Proto(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Proto with a clone!") - case other => //Ok - } - - /** @return the context of any Data's return from inside the instance */ - private[chisel3] def getInnerDataContext: Option[BaseModule] = underlying match { - case Proto(value: BaseModule) => Some(value) - case Proto(value: IsInstantiable) => None - case Clone(i: BaseModule) => Some(i) - case Clone(i: InstantiableClone[_]) => i.getInnerContext - } - - /** @return the context this instance. Note that for non-module clones, getInnerDataContext will be the same as getClonedParent */ - private[chisel3] def getClonedParent: Option[BaseModule] = underlying match { - case Proto(value: BaseModule) => value._parent - case Clone(i: BaseModule) => i._parent - case Clone(i: InstantiableClone[_]) => i.getInnerContext - } - - /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!! - * Instead, mark the field you are accessing with [[@public]] - * - * Given a selector function (that) which selects a member from the original, return the - * corresponding member from the instance. - * - * Our @instantiable and @public macros generate the calls to this apply method - * - * By calling this function, we summon the proper Lookupable typeclass from our implicit scope. - * - * @param that a user-specified lookup function - * @param lookup typeclass which contains the correct lookup function, based on the types of A and B - * @param macroGenerated a value created in the macro, to make it harder for users to use this API - */ - def _lookup[B, C]( - that: A => B - )( - implicit lookup: Lookupable[B], - macroGenerated: chisel3.internal.MacroGenerated - ): lookup.C = { - lookup.instanceLookup(that, this) - } - - /** Returns the definition of this Instance */ - override def toDefinition: Definition[A] = new Definition(Proto(proto)) - override def toInstance: Instance[A] = this - -} - -/** Factory methods for constructing [[Instance]]s */ -object Instance extends SourceInfoDoc { - implicit class InstanceBaseModuleExtensions[T <: BaseModule](i: Instance[T]) { - - /** If this is an instance of a Module, returns the toTarget of this instance - * @return target of this instance - */ - def toTarget: IsModule = i.underlying match { - case Proto(x: BaseModule) => x.getTarget - case Clone(x: IsClone[_] with BaseModule) => x.getTarget - } - - /** If this is an instance of a Module, returns the toAbsoluteTarget of this instance - * @return absoluteTarget of this instance - */ - def toAbsoluteTarget: IsModule = i.underlying match { - case Proto(x) => x.toAbsoluteTarget - case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget - } - - } - - /** A constructs an [[Instance]] from a [[Definition]] - * - * @param definition the Module being created - * @return an instance of the module definition - */ - def apply[T <: BaseModule with IsInstantiable](definition: Definition[T]): Instance[T] = - macro InstanceTransform.apply[T] - - /** A constructs an [[Instance]] from a [[Definition]] - * - * @param definition the Module being created - * @return an instance of the module definition - */ - def do_apply[T <: BaseModule with IsInstantiable]( - definition: Definition[T] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Instance[T] = { - // Check to see if the module is already defined internally or externally - val existingMod = Builder.components.map { - case c: DefModule if c.id == definition.proto => Some(c) - case c: DefBlackBox if c.name == definition.proto.name => Some(c) - case _ => None - }.flatten - - if (existingMod.isEmpty) { - // Add a Definition that will get emitted as an ExtModule so that FIRRTL - // does not complain about a missing element - val extModName = Builder.importDefinitionMap.getOrElse( - definition.proto.name, - throwException( - "Imported Definition information not found - possibly forgot to add ImportDefinition annotation?" - ) - ) - class EmptyExtModule extends ExtModule { - override def desiredName: String = extModName - override def generateComponent(): Option[Component] = { - require(!_closed, s"Can't generate $desiredName module more than once") - _closed = true - val firrtlPorts = definition.proto.getModulePorts.map { port => Port(port, port.specifiedDirection) } - val component = DefBlackBox(this, definition.proto.name, firrtlPorts, SpecifiedDirection.Unspecified, params) - Some(component) - } - } - Definition(new EmptyExtModule() {}) - } - - val ports = experimental.CloneModuleAsRecord(definition.proto) - val clone = ports._parent.get.asInstanceOf[ModuleClone[T]] - clone._madeFromDefinition = true - - new Instance(Clone(clone)) - } - -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala deleted file mode 100644 index 27e06d92..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -/** While this is public, it is not recommended for users to extend directly. - * Instead, use the [[@instantiable]] annotation on your trait or class. - * - * This trait indicates whether a class can be returned from an Instance. - */ -trait IsInstantiable - -object IsInstantiable { - implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) { - def toInstance: Instance[T] = new Instance(Proto(i)) - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala deleted file mode 100644 index a82cbd7d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/IsLookupable.scala +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -/** A User-extendable trait to mark metadata-containers, e.g. parameter case classes, as valid to return unchanged - * from an instance. - * - * This should only be true of the metadata returned is identical for ALL instances! - * - * @example For instances of the same proto, metadata or other construction parameters - * may be useful to access outside of the instance construction. For parameters that are - * the same for all instances, we should mark it as IsLookupable - * {{{ - * case class Params(debugMessage: String) extends IsLookupable - * class MyModule(p: Params) extends MultiIOModule { - * printf(p.debugMessage) - * } - * val myParams = Params("Hello World") - * val definition = Definition(new MyModule(myParams)) - * val i0 = Instance(definition) - * val i1 = Instance(definition) - * require(i0.p == i1.p) // p is only accessable because it extends IsLookupable - * }}} - */ -trait IsLookupable diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala deleted file mode 100644 index d4818f63..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import scala.annotation.implicitNotFound - -@implicitNotFound("These functions are only for building hierarchy-compatible Chisel libraries! Users beware!") -// DO NOT extend unless you know what you are doing!!!!!! Not for the casual user! -trait InsideHierarchyLibraryExtension - -// Collection of public functions to give non-core-Chisel libraries the ability to build integrations with -// the experimental hierarchy package -object LibraryHooks { - - /** Builds a new instance given a definition and function to create a new instance-specific Underlying, from the - * definition's Underlying - * @note Implicitly requires being inside a Hierarchy Library Extension - */ - def buildInstance[A]( - definition: Definition[A], - createUnderlying: Underlying[A] => Underlying[A] - )( - implicit inside: InsideHierarchyLibraryExtension - ): Instance[A] = { - new Instance(createUnderlying(definition.underlying)) - } - - /** Builds a new definition given an Underlying implementation - * @note Implicitly requires being inside a Hierarchy Library Extension - */ - def buildDefinition[A](underlying: Underlying[A])(implicit inside: InsideHierarchyLibraryExtension): Definition[A] = { - new Definition(underlying) - } -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala deleted file mode 100644 index aa35455d..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala +++ /dev/null @@ -1,511 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3.experimental.BaseModule -import chisel3.internal.sourceinfo.SourceInfo -import chisel3.internal.BaseModule.{InstanceClone, InstantiableClone, IsClone, ModuleClone} - -import scala.annotation.implicitNotFound -import scala.collection.mutable.HashMap -import chisel3._ -import chisel3.experimental.dataview.{isView, reify, reifySingleData} -import chisel3.internal.firrtl.{Arg, ILit, Index, ModuleIO, Slot, ULit} -import chisel3.internal.{throwException, AggregateViewBinding, Builder, ChildBinding, ViewBinding, ViewParent} - -/** Represents lookup typeclass to determine how a value accessed from an original IsInstantiable - * should be tweaked to return the Instance's version - * Sealed. - */ -@implicitNotFound( - "@public is only legal within a class or trait marked @instantiable, and only on vals of type" + - " Data, BaseModule, MemBase, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable, Option, Either, or Tuple2" -) -trait Lookupable[-B] { - type C // Return type of the lookup - /** Function called to modify the returned value of type B from A, into C - * - * @param that function that selects B from A - * @param instance Instance of A, used to determine C's context - * @return - */ - def instanceLookup[A](that: A => B, instance: Instance[A]): C - - /** Function called to modify the returned value of type B from A, into C - * - * @param that function that selects B from A - * @param definition Definition of A, used to determine C's context - * @return - */ - def definitionLookup[A](that: A => B, definition: Definition[A]): C - protected def getProto[A](h: Hierarchy[A]): A = h.proto - protected def getUnderlying[A](h: Hierarchy[A]): Underlying[A] = h.underlying -} - -object Lookupable { - - /** Clones a data and sets its internal references to its parent module to be in a new context. - * - * @param data data to be cloned - * @param context new context - * @return - */ - private[chisel3] def cloneDataToContext[T <: Data]( - data: T, - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): T = { - internal.requireIsHardware(data, "cross module reference type") - data._parent match { - case None => data - case Some(parent) => - val newParent = cloneModuleToContext(Proto(parent), context) - newParent match { - case Proto(p) if p == parent => data - case Clone(m: BaseModule) => - val newChild = data.cloneTypeFull - newChild.setRef(data.getRef, true) - newChild.bind(internal.CrossModuleBinding) - newChild.setAllParents(Some(m)) - newChild - } - } - } - // The business logic of lookupData - // Also called by cloneViewToContext which potentially needs to lookup stuff from ioMap or the cache - private[chisel3] def doLookupData[A, B <: Data]( - data: B, - cache: HashMap[Data, Data], - ioMap: Option[Map[Data, Data]], - context: Option[BaseModule] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): B = { - def impl[C <: Data](d: C): C = d match { - case x: Data if ioMap.nonEmpty && ioMap.get.contains(x) => ioMap.get(x).asInstanceOf[C] - case x: Data if cache.contains(x) => cache(x).asInstanceOf[C] - case _ => - assert(context.nonEmpty) // TODO is this even possible? Better error message here - val ret = cloneDataToContext(d, context.get) - cache(d) = ret - ret - } - data.binding match { - case Some(_: ChildBinding) => mapRootAndExtractSubField(data, impl) - case _ => impl(data) - } - } - - // Helper for co-iterating on Elements of aggregates, they must be the same type but that is unchecked - private def coiterate(a: Data, b: Data): Iterable[(Element, Element)] = { - val as = getRecursiveFields.lazily(a, "_") - val bs = getRecursiveFields.lazily(b, "_") - as.zip(bs).collect { case ((ae: Element, _), (be: Element, _)) => (ae, be) } - } - - /** Given a Data, find the root of its binding, apply a function to the root to get a "new root", - * and find the equivalent child Data in the "new root" - * - * @example {{{ - * Given `arg = a.b[2].c` and some `f`: - * 1. a = root(arg) = root(a.b[2].c) - * 2. newRoot = f(root(arg)) = f(a) - * 3. return newRoot.b[2].c - * }}} - * - * Invariants that elt is a Child of something of the type of data is dynamically checked as we traverse - */ - private def mapRootAndExtractSubField[A <: Data](arg: A, f: Data => Data): A = { - def err(msg: String) = throwException(s"Internal Error! $msg") - def unrollCoordinates(res: List[Arg], d: Data): (List[Arg], Data) = d.binding.get match { - case ChildBinding(parent) => - d.getRef match { - case arg @ (_: Slot | _: Index | _: ModuleIO) => unrollCoordinates(arg :: res, parent) - case other => err(s"unrollCoordinates failed for '$arg'! Unexpected arg '$other'") - } - case _ => (res, d) - } - def applyCoordinates(fullCoor: List[Arg], start: Data): Data = { - def rec(coor: List[Arg], d: Data): Data = { - if (coor.isEmpty) d - else { - val next = (coor.head, d) match { - case (Slot(_, name), rec: Record) => rec.elements(name) - case (Index(_, ILit(n)), vec: Vec[_]) => vec.apply(n.toInt) - case (ModuleIO(_, name), rec: Record) => rec.elements(name) - case (arg, _) => err(s"Unexpected Arg '$arg' applied to '$d'! Root was '$start'.") - } - applyCoordinates(coor.tail, next) - } - } - rec(fullCoor, start) - } - val (coor, root) = unrollCoordinates(Nil, arg) - val newRoot = f(root) - val result = applyCoordinates(coor, newRoot) - try { - result.asInstanceOf[A] - } catch { - case _: ClassCastException => err(s"Applying '$coor' to '$newRoot' somehow resulted in '$result'") - } - } - - // TODO this logic is complicated, can any of it be unified with viewAs? - // If `.viewAs` would capture its arguments, we could potentially use it - // TODO Describe what this is doing at a high level - private[chisel3] def cloneViewToContext[A, B <: Data]( - data: B, - cache: HashMap[Data, Data], - ioMap: Option[Map[Data, Data]], - context: Option[BaseModule] - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): B = { - // alias to shorten lookups - def lookupData[C <: Data](d: C) = doLookupData(d, cache, ioMap, context) - - val result = data.cloneTypeFull - - // We have to lookup the target(s) of the view since they may need to be underlying into the current context - val newBinding = data.topBinding match { - case ViewBinding(target) => ViewBinding(lookupData(reify(target))) - case avb @ AggregateViewBinding(map) => - data match { - case e: Element => ViewBinding(lookupData(reify(avb.lookup(e).get))) - case _: Aggregate => - // Provide a 1:1 mapping if possible - val singleTargetOpt = map.get(data).filter(_ => avb == data.binding.get).flatMap(reifySingleData) - singleTargetOpt match { - case Some(singleTarget) => // It is 1:1! - // This is a little tricky because the values in newMap need to point to Elements of newTarget - val newTarget = lookupData(singleTarget) - val newMap = coiterate(result, data).map { - case (res, from) => - (res: Data) -> mapRootAndExtractSubField(map(from), _ => newTarget) - }.toMap - AggregateViewBinding(newMap + (result -> newTarget)) - - case None => // No 1:1 mapping so we have to do a flat binding - // Just remap each Element of this aggregate - val newMap = coiterate(result, data).map { - // Upcast res to Data since Maps are invariant in the Key type parameter - case (res, from) => (res: Data) -> lookupData(reify(avb.lookup(from).get)) - }.toMap - AggregateViewBinding(newMap) - } - } - } - - // TODO Unify the following with `.viewAs` - // We must also mark non-1:1 and child Aggregates in the view for renaming - newBinding match { - case _: ViewBinding => // Do nothing - case AggregateViewBinding(childMap) => - if (!childMap.contains(result)) { - Builder.unnamedViews += result - } - // Binding does not capture 1:1 for child aggregates views - getRecursiveFields.lazily(result, "_").foreach { - case (agg: Aggregate, _) if agg != result => - Builder.unnamedViews += agg - case _ => // Do nothing - } - } - - result.bind(newBinding) - result.setAllParents(Some(ViewParent)) - result.forceName("view", Builder.viewNamespace) - result - } - - /** Given a module (either original or a clone), clone it to a new context - * - * This function effectively recurses up the parents of module to find whether: - * (1) A parent is already in the context; then we do nothing and return module - * (2) A parent is in a different clone of the context; then we clone all the parents up - * to that parent and set their parents to be in this underlying context - * (3) A parent has no root; in that case, we do nothing and return the module. - * - * @param module original or clone to be underlying into a new context - * @param context new context - * @return original or clone in the new context - */ - private[chisel3] def cloneModuleToContext[T <: BaseModule]( - module: Underlying[T], - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): Underlying[T] = { - // Recursive call - def rec[A <: BaseModule](m: A): Underlying[A] = { - def clone(x: A, p: Option[BaseModule], name: () => String): Underlying[A] = { - val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name)) - newChild._parent = p - Clone(newChild) - } - (m, context) match { - case (c, ctx) if ctx == c => Proto(c) - case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Clone(ctx.asInstanceOf[IsClone[A]]) - case (c, ctx) if c._parent.isEmpty => Proto(c) - case (_, _) => - cloneModuleToContext(Proto(m._parent.get), context) match { - case Proto(p) => Proto(m) - case Clone(p: BaseModule) => - clone(m, Some(p), () => m.instanceName) - } - } - } - module match { - case Proto(m) => rec(m) - case Clone(m: ModuleClone[_]) => - rec(m) match { - case Proto(mx) => Clone(mx) - case Clone(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) - newChild._parent = i._parent - Clone(newChild) - } - case Clone(m: InstanceClone[_]) => - rec(m) match { - case Proto(mx) => Clone(mx) - case Clone(i: InstanceClone[_]) => - val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName)) - newChild._parent = i._parent - Clone(newChild) - } - } - } - - class SimpleLookupable[X] extends Lookupable[X] { - type B = X - type C = X - def definitionLookup[A](that: A => B, definition: Definition[A]): C = that(definition.proto) - def instanceLookup[A](that: A => B, instance: Instance[A]): C = that(instance.proto) - } - - implicit def lookupInstance[B <: BaseModule](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[Instance[B]] { - type C = Instance[B] - def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = { - val ret = that(definition.proto) - new Instance(cloneModuleToContext(ret.underlying, definition.getInnerDataContext.get)) - } - def instanceLookup[A](that: A => Instance[B], instance: Instance[A]): C = { - val ret = that(instance.proto) - instance.underlying match { - // If instance is just a normal module, no changing of context is necessary - case Proto(_) => new Instance(ret.underlying) - case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get)) - } - } - } - - implicit def lookupModule[B <: BaseModule](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = Instance[B] - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get)) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - instance.underlying match { - // If instance is just a normal module, no changing of context is necessary - case Proto(_) => new Instance(Proto(ret)) - case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get)) - } - } - } - - implicit def lookupData[B <: Data](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = B - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - if (isView(ret)) { - ??? // TODO!!!!!! cloneViewToContext(ret, instance, ioMap, instance.getInnerDataContext) - } else { - doLookupData(ret, definition.cache, None, definition.getInnerDataContext) - } - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - - def getIoMap(hierarchy: Hierarchy[_]): Option[Map[Data, Data]] = { - hierarchy.underlying match { - case Clone(x: ModuleClone[_]) => Some(x.ioMap) - case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap) - case Clone(x: InstantiableClone[_]) => getIoMap(x._innerContext) - case Clone(x: InstanceClone[_]) => None - case other => { - Builder.exception(s"Internal Error! Unexpected case where we can't get IO Map: $other") - } - } - } - val ioMap = getIoMap(instance) - - if (isView(ret)) { - cloneViewToContext(ret, instance.cache, ioMap, instance.getInnerDataContext) - } else { - doLookupData(ret, instance.cache, ioMap, instance.getInnerDataContext) - } - - } - } - - private[chisel3] def cloneMemToContext[T <: MemBase[_]]( - mem: T, - context: BaseModule - )( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ): T = { - mem._parent match { - case None => mem - case Some(parent) => - val newParent = cloneModuleToContext(Proto(parent), context) - newParent match { - case Proto(p) if p == parent => mem - case Clone(mod: BaseModule) => - val existingMod = Builder.currentModule - Builder.currentModule = Some(mod) - val newChild: T = mem match { - case m: Mem[_] => new Mem(m.t.asInstanceOf[Data].cloneTypeFull, m.length).asInstanceOf[T] - case m: SyncReadMem[_] => - new SyncReadMem(m.t.asInstanceOf[Data].cloneTypeFull, m.length, m.readUnderWrite).asInstanceOf[T] - } - Builder.currentModule = existingMod - newChild.setRef(mem.getRef, true) - newChild - } - } - } - - implicit def lookupMem[B <: MemBase[_]](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new Lookupable[B] { - type C = B - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - cloneMemToContext(that(definition.proto), definition.getInnerDataContext.get) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - cloneMemToContext(that(instance.proto), instance.getInnerDataContext.get) - } - } - - import scala.language.higherKinds // Required to avoid warning for lookupIterable type parameter - implicit def lookupIterable[B, F[_] <: Iterable[_]]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupable: Lookupable[B] - ) = new Lookupable[F[B]] { - type C = F[lookupable.C] - def definitionLookup[A](that: A => F[B], definition: Definition[A]): C = { - val ret = that(definition.proto).asInstanceOf[Iterable[B]] - ret.map { x: B => lookupable.definitionLookup[A](_ => x, definition) }.asInstanceOf[C] - } - def instanceLookup[A](that: A => F[B], instance: Instance[A]): C = { - import instance._ - val ret = that(proto).asInstanceOf[Iterable[B]] - ret.map { x: B => lookupable.instanceLookup[A](_ => x, instance) }.asInstanceOf[C] - } - } - implicit def lookupOption[B]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupable: Lookupable[B] - ) = new Lookupable[Option[B]] { - type C = Option[lookupable.C] - def definitionLookup[A](that: A => Option[B], definition: Definition[A]): C = { - val ret = that(definition.proto) - ret.map { x: B => lookupable.definitionLookup[A](_ => x, definition) } - } - def instanceLookup[A](that: A => Option[B], instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - ret.map { x: B => lookupable.instanceLookup[A](_ => x, instance) } - } - } - implicit def lookupEither[L, R]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupableL: Lookupable[L], - lookupableR: Lookupable[R] - ) = new Lookupable[Either[L, R]] { - type C = Either[lookupableL.C, lookupableR.C] - def definitionLookup[A](that: A => Either[L, R], definition: Definition[A]): C = { - val ret = that(definition.proto) - ret.map { x: R => lookupableR.definitionLookup[A](_ => x, definition) }.left.map { x: L => - lookupableL.definitionLookup[A](_ => x, definition) - } - } - def instanceLookup[A](that: A => Either[L, R], instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - ret.map { x: R => lookupableR.instanceLookup[A](_ => x, instance) }.left.map { x: L => - lookupableL.instanceLookup[A](_ => x, instance) - } - } - } - - implicit def lookupTuple2[X, Y]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions, - lookupableX: Lookupable[X], - lookupableY: Lookupable[Y] - ) = new Lookupable[(X, Y)] { - type C = (lookupableX.C, lookupableY.C) - def definitionLookup[A](that: A => (X, Y), definition: Definition[A]): C = { - val ret = that(definition.proto) - ( - lookupableX.definitionLookup[A](_ => ret._1, definition), - lookupableY.definitionLookup[A](_ => ret._2, definition) - ) - } - def instanceLookup[A](that: A => (X, Y), instance: Instance[A]): C = { - import instance._ - val ret = that(proto) - (lookupableX.instanceLookup[A](_ => ret._1, instance), lookupableY.instanceLookup[A](_ => ret._2, instance)) - } - } - - implicit def lookupIsInstantiable[B <: IsInstantiable]( - implicit sourceInfo: SourceInfo, - compileOptions: CompileOptions - ) = new Lookupable[B] { - type C = Instance[B] - def definitionLookup[A](that: A => B, definition: Definition[A]): C = { - val ret = that(definition.proto) - val underlying = new InstantiableClone[B] { - val getProto = ret - lazy val _innerContext = definition - } - new Instance(Clone(underlying)) - } - def instanceLookup[A](that: A => B, instance: Instance[A]): C = { - val ret = that(instance.proto) - val underlying = new InstantiableClone[B] { - val getProto = ret - lazy val _innerContext = instance - } - new Instance(Clone(underlying)) - } - } - - implicit def lookupIsLookupable[B <: IsLookupable](implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) = - new SimpleLookupable[B]() - - implicit val lookupInt = new SimpleLookupable[Int]() - implicit val lookupByte = new SimpleLookupable[Byte]() - implicit val lookupShort = new SimpleLookupable[Short]() - implicit val lookupLong = new SimpleLookupable[Long]() - implicit val lookupFloat = new SimpleLookupable[Float]() - implicit val lookupChar = new SimpleLookupable[Char]() - implicit val lookupString = new SimpleLookupable[String]() - implicit val lookupBoolean = new SimpleLookupable[Boolean]() - implicit val lookupBigInt = new SimpleLookupable[BigInt]() -} diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala deleted file mode 100644 index 864cc8af..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -package chisel3.experimental.hierarchy - -import chisel3.internal.BaseModule.IsClone - -/** Represents the underlying implementation of a Definition or Instance */ -sealed trait Underlying[+T] - -/** A clone of a real implementation */ -final case class Clone[+T](isClone: IsClone[T]) extends Underlying[T] - -/** An actual implementation */ -final case class Proto[+T](proto: T) extends Underlying[T] diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/package.scala b/core/src/main/scala/chisel3/experimental/hierarchy/package.scala deleted file mode 100644 index c309ab52..00000000 --- a/core/src/main/scala/chisel3/experimental/hierarchy/package.scala +++ /dev/null @@ -1,48 +0,0 @@ -package chisel3.experimental - -package object hierarchy { - - /** Classes or traits which will be used with the [[Definition]] + [[Instance]] api should be marked - * with the [[@instantiable]] annotation at the class/trait definition. - * - * @example {{{ - * @instantiable - * class MyModule extends Module { - * ... - * } - * - * val d = Definition(new MyModule) - * val i0 = Instance(d) - * val i1 = Instance(d) - * }}} - */ - class instantiable extends chisel3.internal.instantiable - - /** Classes marked with [[@instantiable]] can have their vals marked with the [[@public]] annotation to - * enable accessing these values from a [[Definition]] or [[Instance]] of the class. - * - * Only vals of the the following types can be marked [[@public]]: - * 1. IsInstantiable - * 2. IsLookupable - * 3. Data - * 4. BaseModule - * 5. Iterable/Option containing a type that meets these requirements - * 6. Basic type like String, Int, BigInt etc. - * - * @example {{{ - * @instantiable - * class MyModule extends Module { - * @public val in = IO(Input(UInt(3.W))) - * @public val out = IO(Output(UInt(3.W))) - * .. - * } - * - * val d = Definition(new MyModule) - * val i0 = Instance(d) - * val i1 = Instance(d) - * - * i1.in := i0.out - * }}} - */ - class public extends chisel3.internal.public -} diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala index 2b493aab..a69c5b6e 100644 --- a/core/src/main/scala/chisel3/experimental/package.scala +++ b/core/src/main/scala/chisel3/experimental/package.scala @@ -15,91 +15,16 @@ package object experimental { import scala.language.implicitConversions import chisel3.internal.BaseModule - // Implicit conversions for BlackBox Parameters - implicit def fromIntToIntParam(x: Int): IntParam = IntParam(BigInt(x)) - implicit def fromLongToIntParam(x: Long): IntParam = IntParam(BigInt(x)) - implicit def fromBigIntToIntParam(x: BigInt): IntParam = IntParam(x) - implicit def fromDoubleToDoubleParam(x: Double): DoubleParam = DoubleParam(x) - implicit def fromStringToStringParam(x: String): StringParam = StringParam(x) - @deprecated("This type has moved to chisel3", "Chisel 3.5") type ChiselEnum = EnumFactory // Rocket Chip-style clonemodule - /** A record containing the results of CloneModuleAsRecord - * The apply method is retrieves the element with the supplied name. - */ - type ClonePorts = BaseModule.ClonePorts - - object CloneModuleAsRecord { - - /** Clones an existing module and returns a record of all its top-level ports. - * Each element of the record is named with a string matching the - * corresponding port's name and shares the port's type. - * @example {{{ - * val q1 = Module(new Queue(UInt(32.W), 2)) - * val q2_io = CloneModuleAsRecord(q1)("io").asInstanceOf[q1.io.type] - * q2_io.enq <> q1.io.deq - * }}} - */ - def apply( - proto: BaseModule - )( - implicit sourceInfo: chisel3.internal.sourceinfo.SourceInfo, - compileOptions: CompileOptions - ): ClonePorts = { - BaseModule.cloneIORecord(proto) - } - } - val requireIsHardware = chisel3.internal.requireIsHardware val requireIsChiselType = chisel3.internal.requireIsChiselType type Direction = ActualDirection val Direction = ActualDirection - /** The same as [[IO]] except there is no prefix for the name of the val */ - def FlatIO[T <: Record](gen: => T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = noPrefix { - import dataview._ - def coerceDirection(d: Data) = { - import chisel3.{SpecifiedDirection => SD} - DataMirror.specifiedDirectionOf(gen) match { - case SD.Flip => Flipped(d) - case SD.Input => Input(d) - case SD.Output => Output(d) - case _ => d - } - } - val ports: Seq[Data] = - gen.elements.toSeq.reverse.map { - case (name, data) => - val p = chisel3.IO(coerceDirection(chiselTypeClone(data).asInstanceOf[Data])) - p.suggestName(name) - p - - } - - implicit val dv: DataView[Seq[Data], T] = DataView.mapping( - _ => chiselTypeClone(gen).asInstanceOf[T], - (seq, rec) => seq.zip(rec.elements.toSeq.reverse).map { case (port, (_, field)) => port -> field } - ) - ports.viewAs[T] - } - - implicit class ChiselRange(val sc: StringContext) extends AnyVal { - - import scala.language.experimental.macros - - /** Specifies a range using mathematical range notation. Variables can be interpolated using - * standard string interpolation syntax. - * @example {{{ - * UInt(range"[0, 2)") - * UInt(range"[0, \$myInt)") - * UInt(range"[0, \${myInt + 2})") - * }}} - */ - def range(args: Any*): chisel3.internal.firrtl.IntervalRange = macro chisel3.internal.RangeTransform.apply - } class dump extends chisel3.internal.naming.dump class treedump extends chisel3.internal.naming.treedump diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala index 74376598..82835052 100644 --- a/core/src/main/scala/chisel3/internal/BiConnect.scala +++ b/core/src/main/scala/chisel3/internal/BiConnect.scala @@ -3,7 +3,6 @@ package chisel3.internal import chisel3._ -import chisel3.experimental.dataview.{isView, reify, reifyToAggregate} import chisel3.experimental.{attach, Analog, BaseModule} import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{Connect, Converter, DefInvalid} @@ -79,7 +78,7 @@ private[chisel3] object BiConnect { connectCompileOptions: CompileOptions, left: Data, right: Data, - context_mod: RawModule + context_mod: BaseModule ): Unit = { (left, right) match { // Handle element case (root case) @@ -109,27 +108,12 @@ private[chisel3] object BiConnect { throw MismatchedVecException } - val leftReified: Option[Aggregate] = if (isView(left_v)) reifyToAggregate(left_v) else Some(left_v) - val rightReified: Option[Aggregate] = if (isView(right_v)) reifyToAggregate(right_v) else Some(right_v) - - if ( - leftReified.nonEmpty && rightReified.nonEmpty && canBulkConnectAggregates( - leftReified.get, - rightReified.get, - sourceInfo, - connectCompileOptions, - context_mod - ) - ) { - pushCommand(Connect(sourceInfo, leftReified.get.lref, rightReified.get.lref)) - } else { - for (idx <- 0 until left_v.length) { - try { - implicit val compileOptions = connectCompileOptions - connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod) - } catch { - case BiConnectException(message) => throw BiConnectException(s"($idx)$message") - } + for (idx <- 0 until left_v.length) { + try { + implicit val compileOptions = connectCompileOptions + connect(sourceInfo, connectCompileOptions, left_v(idx), right_v(idx), context_mod) + } catch { + case BiConnectException(message) => throw BiConnectException(s"($idx)$message") } } } @@ -166,24 +150,7 @@ private[chisel3] object BiConnect { !MonoConnect.canBeSink(left_r, context_mod) || !MonoConnect.canBeSource(right_r, context_mod) val (newLeft, newRight) = if (flipConnection) (right_r, left_r) else (left_r, right_r) - val leftReified: Option[Aggregate] = if (isView(newLeft)) reifyToAggregate(newLeft) else Some(newLeft) - val rightReified: Option[Aggregate] = if (isView(newRight)) reifyToAggregate(newRight) else Some(newRight) - - if ( - leftReified.nonEmpty && rightReified.nonEmpty && canBulkConnectAggregates( - leftReified.get, - rightReified.get, - sourceInfo, - connectCompileOptions, - context_mod - ) - ) { - pushCommand(Connect(sourceInfo, leftReified.get.lref, rightReified.get.lref)) - } else if (!emitStrictConnects) { - newLeft.legacyConnect(newRight)(sourceInfo) - } else { - recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod) - } + recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod) // Handle Records connected to DontCare case (left_r: Record, DontCare) => @@ -224,7 +191,7 @@ private[chisel3] object BiConnect { connectCompileOptions: CompileOptions, left_r: Record, right_r: Record, - context_mod: RawModule + context_mod: BaseModule ): Unit = { // Verify right has no extra fields that left doesn't have @@ -270,7 +237,7 @@ private[chisel3] object BiConnect { source: Aggregate, sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, - context_mod: RawModule + context_mod: BaseModule ): Boolean = { // check that the aggregates have the same types @@ -304,13 +271,7 @@ private[chisel3] object BiConnect { case _ => true } - // do not bulk connect the 'io' pseudo-bundle of a BlackBox since it will be decomposed in FIRRTL - def blackBoxCheck = Seq(source, sink).map(_._parent).forall { - case Some(_: BlackBox) => false - case _ => true - } - - typeCheck && contextCheck && bindingCheck && flow_check && sourceNotLiteralCheck && blackBoxCheck + typeCheck && contextCheck && bindingCheck && flow_check && sourceNotLiteralCheck } // These functions (finally) issue the connection operation @@ -344,11 +305,11 @@ private[chisel3] object BiConnect { connectCompileOptions: CompileOptions, _left: Element, _right: Element, - context_mod: RawModule + context_mod: BaseModule ): Unit = { import BindingDirection.{Input, Internal, Output} // Using extensively so import these - val left = reify(_left) - val right = reify(_right) + val left = _left + val right = _right // If left or right have no location, assume in context module // This can occur if one of them is a literal, unbound will error previously val left_mod: BaseModule = left.topBinding.location.getOrElse(context_mod) @@ -451,7 +412,7 @@ private[chisel3] object BiConnect { } // This function checks if analog element-level attaching is allowed, then marks the Analog as connected - def markAnalogConnected(implicit sourceInfo: SourceInfo, analog: Analog, contextModule: RawModule): Unit = { + def markAnalogConnected(implicit sourceInfo: SourceInfo, analog: Analog, contextModule: BaseModule): Unit = { analog.biConnectLocs.get(contextModule) match { case Some(sl) => throw AttachAlreadyBulkConnectedException(sl) case None => // Do nothing diff --git a/core/src/main/scala/chisel3/internal/Binding.scala b/core/src/main/scala/chisel3/internal/Binding.scala index bab79bc1..63936212 100644 --- a/core/src/main/scala/chisel3/internal/Binding.scala +++ b/core/src/main/scala/chisel3/internal/Binding.scala @@ -82,15 +82,7 @@ sealed trait UnconstrainedBinding extends TopBinding { // Location will track where this Module is, and the bound object can be referenced in FIRRTL sealed trait ConstrainedBinding extends TopBinding { def enclosure: BaseModule - def location: Option[BaseModule] = { - // If an aspect is present, return the aspect module. Otherwise, return the enclosure module - // This allows aspect modules to pretend to be enclosed modules for connectivity checking, - // inside vs outside instance checking, etc. - Builder.aspectModule(enclosure) match { - case None => Some(enclosure) - case Some(aspect) => Some(aspect) - } - } + def location: Option[BaseModule] = Some(enclosure) } // A binding representing a data that cannot be (re)assigned to. diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala index ab1435c5..57f878aa 100644 --- a/core/src/main/scala/chisel3/internal/Builder.scala +++ b/core/src/main/scala/chisel3/internal/Builder.scala @@ -6,13 +6,11 @@ import scala.util.DynamicVariable import scala.collection.mutable.ArrayBuffer import chisel3._ import chisel3.experimental._ -import chisel3.experimental.hierarchy.{Clone, ImportDefinitionAnnotation, Instance} import chisel3.internal.firrtl._ import chisel3.internal.naming._ import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget} import _root_.firrtl.annotations.AnnotationUtils.validComponentName import _root_.firrtl.{AnnotationSeq, RenameMap} -import chisel3.experimental.dataview.{reify, reifySingleData} import chisel3.internal.Builder.Prefix import logger.LazyLogging @@ -316,7 +314,6 @@ private[chisel3] trait HasId extends InstanceId { } val parentGuess: String = _parent match { - case Some(ViewParent) => s", in module '${reifyParent.pathName}'" case Some(p) => s", in module '${p.pathName}'" case None => "" } @@ -324,18 +321,8 @@ private[chisel3] trait HasId extends InstanceId { nameGuess + parentGuess } - // Helper for reifying views if they map to a single Target - private[chisel3] def reifyTarget: Option[Data] = this match { - case d: Data => reifySingleData(d) // Only Data can be views - case bad => throwException(s"This shouldn't be possible - got $bad with ${_parent}") - } - - // Helper for reifying the parent of a view if the view maps to a single Target - private[chisel3] def reifyParent: BaseModule = reifyTarget.flatMap(_._parent).getOrElse(ViewParent) - // Implementation of public methods. def instanceName: String = _parent match { - case Some(ViewParent) => reifyTarget.map(_.instanceName).getOrElse(this.refName(ViewParent.fakeComponent)) case Some(p) => (p._component, this) match { case (Some(c), _) => refName(c) @@ -348,16 +335,13 @@ private[chisel3] trait HasId extends InstanceId { } def pathName: String = _parent match { case None => instanceName - case Some(ViewParent) => s"${reifyParent.pathName}.$instanceName" case Some(p) => s"${p.pathName}.$instanceName" } def parentPathName: String = _parent match { - case Some(ViewParent) => reifyParent.pathName case Some(p) => p.pathName case None => throwException(s"$instanceName doesn't have a parent") } def parentModName: String = _parent match { - case Some(ViewParent) => reifyParent.name case Some(p) => p.name case None => throwException(s"$instanceName doesn't have a parent") } @@ -368,7 +352,6 @@ private[chisel3] trait HasId extends InstanceId { case None => instanceName case Some(o) => o.circuitName } - case Some(ViewParent) => reifyParent.circuitName case Some(p) => p.circuitName } @@ -413,7 +396,6 @@ private[chisel3] trait NamedComponent extends HasId { if (!validComponentName(name)) throwException(s"Illegal component name: $name (note: literals are illegal)") import _root_.firrtl.annotations.{Target, TargetToken} val root = _parent.map { - case ViewParent => reifyParent case other => other }.get.getTarget // All NamedComponents will have a parent, only the top module can have None here Target.toTargetTokens(name).toList match { @@ -427,7 +409,6 @@ private[chisel3] trait NamedComponent extends HasId { val localTarget = toTarget def makeTarget(p: BaseModule) = p.toAbsoluteTarget.ref(localTarget.ref).copy(component = localTarget.component) _parent match { - case Some(ViewParent) => makeTarget(reifyParent) case Some(parent) => makeTarget(parent) case None => localTarget } @@ -455,11 +436,6 @@ private[chisel3] class ChiselContext() { // Records the different prefixes which have been scoped at this point in time var prefixStack: Prefix = Nil - - // Views belong to a separate namespace (for renaming) - // The namespace outside of Builder context is useless, but it ensures that views can still be created - // and the resulting .toTarget is very clearly useless (_$$View$$_...) - val viewNamespace = Namespace.empty } private[chisel3] class DynamicContext( @@ -467,43 +443,9 @@ private[chisel3] class DynamicContext( val throwOnFirstError: Boolean, val warnReflectiveNaming: Boolean, val warningsAsErrors: Boolean) { - val importDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a } - - // Map holding the actual names of extModules - // Pick the definition name by default in case not passed through annotation. - val importDefinitionMap = importDefinitionAnnos - .map(a => a.definition.proto.name -> a.overrideDefName.getOrElse(a.definition.proto.name)) - .toMap - - // Helper function which does 2 things - // 1. Ensure there are no repeated names for imported Definitions - both Proto Names as well as ExtMod Names - // 2. Return the distinct definition / extMod names - private def checkAndGeDistinctProtoExtModNames() = { - val importAllDefinitionProtoNames = importDefinitionAnnos.map { a => a.definition.proto.name } - val importDistinctDefinitionProtoNames = importDefinitionMap.keys.toSeq - val importAllDefinitionExtModNames = importDefinitionMap.toSeq.map(_._2) - val importDistinctDefinitionExtModNames = importAllDefinitionExtModNames.distinct - - if (importDistinctDefinitionProtoNames.length < importAllDefinitionProtoNames.length) { - val duplicates = importAllDefinitionProtoNames.diff(importDistinctDefinitionProtoNames).mkString(", ") - throwException(s"Expected distinct imported Definition names but found duplicates for: $duplicates") - } - if (importDistinctDefinitionExtModNames.length < importAllDefinitionExtModNames.length) { - val duplicates = importAllDefinitionExtModNames.diff(importDistinctDefinitionExtModNames).mkString(", ") - throwException(s"Expected distinct overrideDef names but found duplicates for: $duplicates") - } - (importAllDefinitionProtoNames ++ importAllDefinitionExtModNames).distinct - } val globalNamespace = Namespace.empty - // Ensure imported Definitions emit as ExtModules with the correct name so - // that instantiations will also use the correct name and prevent any name - // conflicts with Modules/Definitions in this elaboration - checkAndGeDistinctProtoExtModNames().foreach { - globalNamespace.name(_) - } - val components = ArrayBuffer[Component]() val annotations = ArrayBuffer[ChiselAnnotation]() val newAnnotations = ArrayBuffer[ChiselMultiAnnotation]() @@ -518,9 +460,6 @@ private[chisel3] class DynamicContext( */ val aspectModule: mutable.HashMap[BaseModule, BaseModule] = mutable.HashMap.empty[BaseModule, BaseModule] - // Views that do not correspond to a single ReferenceTarget and thus require renaming - val unnamedViews: ArrayBuffer[Data] = ArrayBuffer.empty - // Set by object Module.apply before calling class Module constructor // Used to distinguish between no Module() wrapping, multiple wrappings, and rewrapping var readyForModuleConstr: Boolean = false @@ -529,9 +468,6 @@ private[chisel3] class DynamicContext( var currentReset: Option[Reset] = None val errors = new ErrorLog(warningsAsErrors) val namingStack = new NamingStack - - // Used to indicate if this is the top-level module of full elaboration, or from a Definition - var inDefinition: Boolean = false } private[chisel3] object Builder extends LazyLogging { @@ -588,10 +524,6 @@ private[chisel3] object Builder extends LazyLogging { def annotationSeq: AnnotationSeq = dynamicContext.annotationSeq def namingStack: NamingStack = dynamicContext.namingStack - def importDefinitionMap: Map[String, String] = dynamicContext.importDefinitionMap - - def unnamedViews: ArrayBuffer[Data] = dynamicContext.unnamedViews - def viewNamespace: Namespace = chiselContext.get.viewNamespace // Puts a prefix string onto the prefix stack def pushPrefix(d: String): Unit = { @@ -612,7 +544,6 @@ private[chisel3] object Builder extends LazyLogging { case Index(_, ILit(n)) => Some(n.toString) // Vec static indexing case Index(_, ULit(n, _)) => Some(n.toString) // Vec lit indexing case Index(_, _: Node) => None // Vec dynamic indexing - case ModuleIO(_, n) => Some(n) // BlackBox port } def map2[A, B](a: Option[A], b: Option[A])(f: (A, A) => B): Option[B] = a.flatMap(ax => b.map(f(ax, _))) @@ -628,7 +559,6 @@ private[chisel3] object Builder extends LazyLogging { case PortBinding(mod) if Builder.currentModule.contains(mod) => data.seedOpt case PortBinding(mod) => map2(mod.seedOpt, data.seedOpt)(_ + "_" + _) case (_: LitBinding | _: DontCareBinding) => None - case _ => Some("view_") // TODO implement } id match { case d: Data => recData(d) @@ -672,10 +602,7 @@ private[chisel3] object Builder extends LazyLogging { def currentModule_=(target: Option[BaseModule]): Unit = { dynamicContext.currentModule = target } - def aspectModule(module: BaseModule): Option[BaseModule] = dynamicContextVar.value match { - case Some(dynamicContext) => dynamicContext.aspectModule.get(module) - case _ => None - } + /** Retrieves the parent of a module based on the elaboration context * @@ -683,25 +610,8 @@ private[chisel3] object Builder extends LazyLogging { * @param context the context the parent should be evaluated in * @return the parent of the module provided */ - def retrieveParent(module: BaseModule, context: BaseModule): Option[BaseModule] = { - module._parent match { - case Some(parentModule) => { //if a parent exists investigate, otherwise return None - context match { - case aspect: ModuleAspect => { //if aspect context, do the translation - Builder.aspectModule(parentModule) match { - case Some(parentAspect) => Some(parentAspect) //we've found a translation - case _ => Some(parentModule) //no translation found - } - } //otherwise just return our parent - case _ => Some(parentModule) - } - } - case _ => None - } - } - def addAspect(module: BaseModule, aspect: BaseModule): Unit = { - dynamicContext.aspectModule += ((module, aspect)) - } + def retrieveParent(module: BaseModule, context: BaseModule): Option[BaseModule] = module._parent + def forcedModule: BaseModule = currentModule match { case Some(module) => module case None => @@ -710,20 +620,7 @@ private[chisel3] object Builder extends LazyLogging { // A bare api call is, e.g. calling Wire() from the scala console). ) } - def referenceUserModule: RawModule = { - currentModule match { - case Some(module: RawModule) => - aspectModule(module) match { - case Some(aspect: RawModule) => aspect - case other => module - } - case _ => - throwException( - "Error: Not in a RawModule. Likely cause: Missed Module() wrap, bare chisel API call, or attempting to construct hardware inside a BlackBox." - // A bare api call is, e.g. calling Wire() from the scala console). - ) - } - } + def forcedUserModule: RawModule = currentModule match { case Some(module: RawModule) => module case _ => @@ -768,12 +665,6 @@ private[chisel3] object Builder extends LazyLogging { dynamicContext.currentReset = newReset } - def inDefinition: Boolean = { - dynamicContextVar.value - .map(_.inDefinition) - .getOrElse(false) - } - def forcedClock: Clock = currentClock.getOrElse( throwException("Error: No implicit clock.") ) @@ -801,11 +692,6 @@ private[chisel3] object Builder extends LazyLogging { * (Note: Map is Iterable[Tuple2[_,_]] and thus excluded) */ def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match { - case (id: Instance[_]) => - id.underlying match { - case Clone(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix) - case _ => - } case (id: HasId) => namer(id, prefix) case Some(elt) => nameRecursively(prefix, elt, namer) case (iter: Iterable[_]) if iter.hasDefiniteSize => @@ -853,31 +739,12 @@ private[chisel3] object Builder extends LazyLogging { } } - // Builds a RenameMap for all Views that do not correspond to a single Data - // These Data give a fake ReferenceTarget for .toTarget and .toReferenceTarget that the returned - // RenameMap can split into the constituent parts - private[chisel3] def makeViewRenameMap: RenameMap = { - val renames = RenameMap() - for (view <- unnamedViews) { - val localTarget = view.toTarget - val absTarget = view.toAbsoluteTarget - val elts = getRecursiveFields.lazily(view, "").collect { case (elt: Element, _) => elt } - for (elt <- elts) { - val targetOfView = reify(elt) - renames.record(localTarget, targetOfView.toTarget) - renames.record(absTarget, targetOfView.toAbsoluteTarget) - } - } - renames - } - private[chisel3] def build[T <: BaseModule]( f: => T, dynamicContext: DynamicContext, forceModName: Boolean = true ): (Circuit, T) = { dynamicContextVar.withValue(Some(dynamicContext)) { - ViewParent // Must initialize the singleton in a Builder context or weird things can happen // in tiny designs/testcases that never access anything in chisel3.internal checkScalaVersion() logger.info("Elaborating design...") @@ -888,7 +755,7 @@ private[chisel3] object Builder extends LazyLogging { errors.checkpoint(logger) logger.info("Done elaborating.") - (Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap, newAnnotations.toSeq), mod) + (Circuit(components.last.name, components.toSeq, annotations.toSeq, null, newAnnotations.toSeq), mod) } } initializeSingletons() diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala index a0cca4a6..257c543f 100644 --- a/core/src/main/scala/chisel3/internal/MonoConnect.scala +++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala @@ -3,10 +3,9 @@ package chisel3.internal import chisel3._ -import chisel3.experimental.{Analog, BaseModule, FixedPoint, Interval, UnsafeEnum} +import chisel3.experimental.{Analog, BaseModule, UnsafeEnum} import chisel3.internal.Builder.pushCommand import chisel3.internal.firrtl.{Connect, Converter, DefInvalid} -import chisel3.experimental.dataview.{isView, reify, reifyToAggregate} import scala.language.experimental.macros import chisel3.internal.sourceinfo.SourceInfo @@ -96,7 +95,7 @@ private[chisel3] object MonoConnect { connectCompileOptions: CompileOptions, sink: Data, source: Data, - context_mod: RawModule + context_mod: BaseModule ): Unit = (sink, source) match { @@ -109,10 +108,6 @@ private[chisel3] object MonoConnect { elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) case (sink_e: SInt, source_e: SInt) => elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) - case (sink_e: FixedPoint, source_e: FixedPoint) => - elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) - case (sink_e: Interval, source_e: Interval) => - elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) case (sink_e: Clock, source_e: Clock) => elemConnect(sourceInfo, connectCompileOptions, sink_e, source_e, context_mod) case (sink_e: AsyncReset, source_e: AsyncReset) => @@ -131,28 +126,12 @@ private[chisel3] object MonoConnect { // Handle Vec case case (sink_v: Vec[Data @unchecked], source_v: Vec[Data @unchecked]) => if (sink_v.length != source_v.length) { throw MismatchedVecException } - - val sinkReified: Option[Aggregate] = if (isView(sink_v)) reifyToAggregate(sink_v) else Some(sink_v) - val sourceReified: Option[Aggregate] = if (isView(source_v)) reifyToAggregate(source_v) else Some(source_v) - - if ( - sinkReified.nonEmpty && sourceReified.nonEmpty && canBulkConnectAggregates( - sinkReified.get, - sourceReified.get, - sourceInfo, - connectCompileOptions, - context_mod - ) - ) { - pushCommand(Connect(sourceInfo, sinkReified.get.lref, sourceReified.get.ref)) - } else { - for (idx <- 0 until sink_v.length) { - try { - implicit val compileOptions = connectCompileOptions - connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod) - } catch { - case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message") - } + for (idx <- 0 until sink_v.length) { + try { + implicit val compileOptions = connectCompileOptions + connect(sourceInfo, connectCompileOptions, sink_v(idx), source_v(idx), context_mod) + } catch { + case MonoConnectException(message) => throw MonoConnectException(s"($idx)$message") } } // Handle Vec connected to DontCare. Apply the DontCare to individual elements. @@ -168,34 +147,19 @@ private[chisel3] object MonoConnect { // Handle Record case case (sink_r: Record, source_r: Record) => - val sinkReified: Option[Aggregate] = if (isView(sink_r)) reifyToAggregate(sink_r) else Some(sink_r) - val sourceReified: Option[Aggregate] = if (isView(source_r)) reifyToAggregate(source_r) else Some(source_r) - - if ( - sinkReified.nonEmpty && sourceReified.nonEmpty && canBulkConnectAggregates( - sinkReified.get, - sourceReified.get, - sourceInfo, - connectCompileOptions, - context_mod - ) - ) { - pushCommand(Connect(sourceInfo, sinkReified.get.lref, sourceReified.get.ref)) - } else { - // For each field, descend with right - for ((field, sink_sub) <- sink_r.elements) { - try { - source_r.elements.get(field) match { - case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod) - case None => { - if (connectCompileOptions.connectFieldsMustMatch) { - throw MissingFieldException(field) - } + // For each field, descend with right + for ((field, sink_sub) <- sink_r.elements) { + try { + source_r.elements.get(field) match { + case Some(source_sub) => connect(sourceInfo, connectCompileOptions, sink_sub, source_sub, context_mod) + case None => { + if (connectCompileOptions.connectFieldsMustMatch) { + throw MissingFieldException(field) } } - } catch { - case MonoConnectException(message) => throw MonoConnectException(s".$field$message") } + } catch { + case MonoConnectException(message) => throw MonoConnectException(s".$field$message") } } // Handle Record connected to DontCare. Apply the DontCare to individual elements. @@ -210,8 +174,7 @@ private[chisel3] object MonoConnect { } // Source is DontCare - it may be connected to anything. It generates a defInvalid for the sink. - case (_sink: Element, DontCare) => - val sink = reify(_sink) // Handle views + case (sink: Element, DontCare) => pushCommand(DefInvalid(sourceInfo, sink.lref)) // DontCare as a sink is illegal. case (DontCare, _) => throw DontCareCantBeSink @@ -235,7 +198,7 @@ private[chisel3] object MonoConnect { connectCompileOptions: CompileOptions, sink: Aggregate, source: Aggregate, - context_mod: RawModule + context_mod: BaseModule ): Boolean = { import ActualDirection.{Bidirectional, Input, Output} // If source has no location, assume in context module @@ -334,7 +297,7 @@ private[chisel3] object MonoConnect { wantToBeSink: Boolean, currentlyFlipped: Boolean, data: Data, - context_mod: RawModule + context_mod: BaseModule ): Boolean = { val sdir = data.specifiedDirection val coercedFlip = sdir == SpecifiedDirection.Input @@ -349,8 +312,8 @@ private[chisel3] object MonoConnect { case _ => true } } - def canBeSink(data: Data, context_mod: RawModule): Boolean = traceFlow(true, false, data, context_mod) - def canBeSource(data: Data, context_mod: RawModule): Boolean = traceFlow(false, false, data, context_mod) + def canBeSink(data: Data, context_mod: BaseModule): Boolean = traceFlow(true, false, data, context_mod) + def canBeSource(data: Data, context_mod: BaseModule): Boolean = traceFlow(false, false, data, context_mod) /** Check whether two aggregates can be bulk connected (<=) in FIRRTL. (MonoConnect case) * @@ -363,7 +326,7 @@ private[chisel3] object MonoConnect { source: Aggregate, sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, - context_mod: RawModule + context_mod: BaseModule ): Boolean = { // Assuming we're using a <>, check if a bulk connect is valid in that case def biConnectCheck = @@ -391,13 +354,11 @@ private[chisel3] object MonoConnect { def elemConnect( implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, - _sink: Element, - _source: Element, - context_mod: RawModule + sink: Element, + source: Element, + context_mod: BaseModule ): Unit = { import BindingDirection.{Input, Internal, Output} // Using extensively so import these - val sink = reify(_sink) - val source = reify(_source) // If source has no location, assume in context module // This can occur if is a literal, unbound will error previously val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException(sink, source)) diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala index ca39608f..c9719498 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala @@ -90,16 +90,6 @@ private[chisel3] object Converter { val uint = convert(ULit(unsigned, slit.width), ctx, info) fir.DoPrim(firrtl.PrimOps.AsSInt, Seq(uint), Seq.empty, fir.UnknownType) // TODO Simplify - case fplit @ FPLit(n, w, bp) => - val unsigned = if (n < 0) (BigInt(1) << fplit.width.get) + n else n - val uint = convert(ULit(unsigned, fplit.width), ctx, info) - val lit = bp.asInstanceOf[KnownBinaryPoint].value - fir.DoPrim(firrtl.PrimOps.AsFixedPoint, Seq(uint), Seq(lit), fir.UnknownType) - case intervalLit @ IntervalLit(n, w, bp) => - val unsigned = if (n < 0) (BigInt(1) << intervalLit.width.get) + n else n - val uint = convert(ULit(unsigned, intervalLit.width), ctx, info) - val lit = bp.asInstanceOf[KnownBinaryPoint].value - fir.DoPrim(firrtl.PrimOps.AsInterval, Seq(uint), Seq(n, n, lit), fir.UnknownType) case lit: ILit => throwException(s"Internal Error! Unexpected ILit: $lit") } @@ -319,8 +309,6 @@ private[chisel3] object Converter { case d: EnumType => fir.UIntType(convert(d.width)) case d: UInt => fir.UIntType(convert(d.width)) case d: SInt => fir.SIntType(convert(d.width)) - case d: FixedPoint => fir.FixedType(convert(d.width), convert(d.binaryPoint)) - case d: Interval => fir.IntervalType(d.range.lowerBound, d.range.upperBound, d.range.firrtlBinaryPoint) case d: Analog => fir.AnalogType(convert(d.width)) case d: Vec[_] => val childClearDir = clearDir || @@ -343,13 +331,6 @@ private[chisel3] object Converter { } } - def convert(name: String, param: Param): fir.Param = param match { - case IntParam(value) => fir.IntParam(name, value) - case DoubleParam(value) => fir.DoubleParam(name, value) - case StringParam(value) => fir.StringParam(name, fir.StringLit(value)) - case RawParam(value) => fir.RawStringParam(name, value) - } - def convert(port: Port, topDir: SpecifiedDirection = SpecifiedDirection.Unspecified): fir.Port = { val resolvedDir = SpecifiedDirection.fromParent(topDir, port.dir) val dir = resolvedDir match { @@ -368,14 +349,6 @@ private[chisel3] object Converter { def convert(component: Component): fir.DefModule = component match { case ctx @ DefModule(_, name, ports, cmds) => fir.Module(fir.NoInfo, name, ports.map(p => convert(p)), convert(cmds, ctx)) - case ctx @ DefBlackBox(id, name, ports, topDir, params) => - fir.ExtModule( - fir.NoInfo, - name, - ports.map(p => convert(p, topDir)), - id.desiredName, - params.map { case (name, p) => convert(name, p) }.toSeq - ) } def convert(circuit: Circuit): fir.Circuit = diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala index ddad6b10..8ed5ed07 100644 --- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala +++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala @@ -53,7 +53,6 @@ object PrimOp { val AsUIntOp = PrimOp("asUInt") val AsSIntOp = PrimOp("asSInt") val AsFixedPointOp = PrimOp("asFixedPoint") - val AsIntervalOp = PrimOp("asInterval") val WrapOp = PrimOp("wrap") val SqueezeOp = PrimOp("squz") val ClipOp = PrimOp("clip") @@ -168,25 +167,6 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n } } -case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) { - def name: String = { - val unsigned = if (n < 0) (BigInt(1) << width.get) + n else n - s"asInterval(${ULit(unsigned, width).name}, ${n}, ${n}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})" - } - val range: IntervalRange = { - new IntervalRange( - IntervalRange.getBound(isClosed = true, BigDecimal(n)), - IntervalRange.getBound(isClosed = true, BigDecimal(n)), - IntervalRange.getRangeWidth(binaryPoint) - ) - } - def minWidth: Int = 1 + n.bitLength - - def cloneWithWidth(newWidth: Width): this.type = { - IntervalLit(n, newWidth, binaryPoint).asInstanceOf[this.type] - } -} - case class Ref(name: String) extends Arg /** Arg for ports of Modules @@ -314,483 +294,6 @@ object MemPortDirection { object INFER extends MemPortDirection("infer") } -sealed trait RangeType { - def getWidth: Width - - def *(that: IntervalRange): IntervalRange - def +&(that: IntervalRange): IntervalRange - def -&(that: IntervalRange): IntervalRange - def <<(that: Int): IntervalRange - def >>(that: Int): IntervalRange - def <<(that: KnownWidth): IntervalRange - def >>(that: KnownWidth): IntervalRange - def merge(that: IntervalRange): IntervalRange -} - -object IntervalRange { - - /** Creates an IntervalRange, this is used primarily by the range interpolator macro - * @param lower lower bound - * @param upper upper bound - * @param firrtlBinaryPoint binary point firrtl style - * @return - */ - def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, firrtlBinaryPoint: firrtlir.Width): IntervalRange = { - new IntervalRange(lower, upper, firrtlBinaryPoint) - } - - def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: BinaryPoint): IntervalRange = { - new IntervalRange(lower, upper, IntervalRange.getBinaryPoint(binaryPoint)) - } - - def apply(lower: firrtlir.Bound, upper: firrtlir.Bound, binaryPoint: Int): IntervalRange = { - IntervalRange(lower, upper, BinaryPoint(binaryPoint)) - } - - /** Returns an IntervalRange appropriate for a signed value of the given width - * @param binaryPoint number of bits of mantissa - * @return - */ - def apply(binaryPoint: BinaryPoint): IntervalRange = { - IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint) - } - - /** Returns an IntervalRange appropriate for a signed value of the given width - * @param width number of bits to have in the interval - * @param binaryPoint number of bits of mantissa - * @return - */ - def apply(width: Width, binaryPoint: BinaryPoint = 0.BP): IntervalRange = { - val range = width match { - case KnownWidth(w) => - val nearestPowerOf2 = BigInt("1" + ("0" * (w - 1)), 2) - IntervalRange( - firrtlir.Closed(BigDecimal(-nearestPowerOf2)), - firrtlir.Closed(BigDecimal(nearestPowerOf2 - 1)), - binaryPoint - ) - case _ => - IntervalRange(firrtlir.UnknownBound, firrtlir.UnknownBound, binaryPoint) - } - range - } - - def unapply(arg: IntervalRange): Option[(firrtlir.Bound, firrtlir.Bound, BinaryPoint)] = { - return Some((arg.lower, arg.upper, arg.binaryPoint)) - } - - def getBound(isClosed: Boolean, value: String): firrtlir.Bound = { - if (value == "?") { - firrtlir.UnknownBound - } else if (isClosed) { - firrtlir.Closed(BigDecimal(value)) - } else { - firrtlir.Open(BigDecimal(value)) - } - } - - def getBound(isClosed: Boolean, value: BigDecimal): firrtlir.Bound = { - if (isClosed) { - firrtlir.Closed(value) - } else { - firrtlir.Open(value) - } - } - - def getBound(isClosed: Boolean, value: Int): firrtlir.Bound = { - getBound(isClosed, (BigDecimal(value))) - } - - def getBinaryPoint(s: String): firrtlir.Width = { - firrtlir.UnknownWidth - } - - def getBinaryPoint(n: Int): firrtlir.Width = { - if (n < 0) { - firrtlir.UnknownWidth - } else { - firrtlir.IntWidth(n) - } - } - def getBinaryPoint(n: BinaryPoint): firrtlir.Width = { - n match { - case UnknownBinaryPoint => firrtlir.UnknownWidth - case KnownBinaryPoint(w) => firrtlir.IntWidth(w) - } - } - - def getRangeWidth(w: Width): firrtlir.Width = { - if (w.known) { - firrtlir.IntWidth(w.get) - } else { - firrtlir.UnknownWidth - } - } - def getRangeWidth(binaryPoint: BinaryPoint): firrtlir.Width = { - if (binaryPoint.known) { - firrtlir.IntWidth(binaryPoint.get) - } else { - firrtlir.UnknownWidth - } - } - - def Unknown: IntervalRange = range"[?,?].?" -} - -sealed class IntervalRange( - val lowerBound: firrtlir.Bound, - val upperBound: firrtlir.Bound, - private[chisel3] val firrtlBinaryPoint: firrtlir.Width) - extends firrtlir.IntervalType(lowerBound, upperBound, firrtlBinaryPoint) - with RangeType { - - (lowerBound, upperBound) match { - case (firrtlir.Open(begin), firrtlir.Open(end)) => - if (begin >= end) throw new ChiselException(s"Invalid range with ${serialize}") - binaryPoint match { - case KnownBinaryPoint(bp) => - if (begin >= end - (BigDecimal(1) / BigDecimal(BigInt(1) << bp))) { - throw new ChiselException(s"Invalid range with ${serialize}") - } - case _ => - } - case (firrtlir.Open(begin), firrtlir.Closed(end)) => - if (begin >= end) throw new ChiselException(s"Invalid range with ${serialize}") - case (firrtlir.Closed(begin), firrtlir.Open(end)) => - if (begin >= end) throw new ChiselException(s"Invalid range with ${serialize}") - case (firrtlir.Closed(begin), firrtlir.Closed(end)) => - if (begin > end) throw new ChiselException(s"Invalid range with ${serialize}") - case _ => - } - - override def toString: String = { - val binaryPoint = firrtlBinaryPoint match { - case firrtlir.IntWidth(n) => s"$n" - case _ => "?" - } - val lowerBoundString = lowerBound match { - case firrtlir.Closed(l) => s"[$l" - case firrtlir.Open(l) => s"($l" - case firrtlir.UnknownBound => s"[?" - } - val upperBoundString = upperBound match { - case firrtlir.Closed(l) => s"$l]" - case firrtlir.Open(l) => s"$l)" - case firrtlir.UnknownBound => s"?]" - } - s"""range"$lowerBoundString,$upperBoundString.$binaryPoint"""" - } - - val increment: Option[BigDecimal] = firrtlBinaryPoint match { - case firrtlir.IntWidth(bp) => - Some(BigDecimal(math.pow(2, -bp.doubleValue))) - case _ => None - } - - /** If possible returns the lowest possible value for this Interval - * @return - */ - val getLowestPossibleValue: Option[BigDecimal] = { - increment match { - case Some(inc) => - lower match { - case firrtlir.Closed(n) => Some(n) - case firrtlir.Open(n) => Some(n + inc) - case _ => None - } - case _ => - None - } - } - - /** If possible returns the highest possible value for this Interval - * @return - */ - val getHighestPossibleValue: Option[BigDecimal] = { - increment match { - case Some(inc) => - upper match { - case firrtlir.Closed(n) => Some(n) - case firrtlir.Open(n) => Some(n - inc) - case _ => None - } - case _ => - None - } - } - - /** Return a Seq of the possible values for this range - * Mostly to be used for testing - * @return - */ - def getPossibleValues: NumericRange[BigDecimal] = { - (getLowestPossibleValue, getHighestPossibleValue, increment) match { - case (Some(low), Some(high), Some(inc)) => (low to high by inc) - case (_, _, None) => - throw new ChiselException(s"BinaryPoint unknown. Cannot get possible values from IntervalRange $toString") - case _ => - throw new ChiselException(s"Unknown Bound. Cannot get possible values from IntervalRange $toString") - - } - } - - override def getWidth: Width = { - width match { - case firrtlir.IntWidth(n) => KnownWidth(n.toInt) - case firrtlir.UnknownWidth => UnknownWidth() - } - } - - private def doFirrtlOp(op: firrtlir.PrimOp, that: IntervalRange): IntervalRange = { - PrimOps - .set_primop_type( - firrtlir - .DoPrim(op, Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", that)), Nil, firrtlir.UnknownType) - ) - .tpe match { - case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point) - case other => sys.error("BAD!") - } - } - - private def doFirrtlDynamicShift(that: UInt, isLeft: Boolean): IntervalRange = { - val uinttpe = that.widthOption match { - case None => firrtlir.UIntType(firrtlir.UnknownWidth) - case Some(w) => firrtlir.UIntType(firrtlir.IntWidth(w)) - } - val op = if (isLeft) PrimOps.Dshl else PrimOps.Dshr - PrimOps - .set_primop_type( - firrtlir - .DoPrim(op, Seq(firrtlir.Reference("a", this), firrtlir.Reference("b", uinttpe)), Nil, firrtlir.UnknownType) - ) - .tpe match { - case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point) - case other => sys.error("BAD!") - } - } - - private def doFirrtlOp(op: firrtlir.PrimOp, that: Int): IntervalRange = { - PrimOps - .set_primop_type( - firrtlir.DoPrim(op, Seq(firrtlir.Reference("a", this)), Seq(BigInt(that)), firrtlir.UnknownType) - ) - .tpe match { - case i: firrtlir.IntervalType => IntervalRange(i.lower, i.upper, i.point) - case other => sys.error("BAD!") - } - } - - /** Multiply this by that, here we return a fully unknown range, - * firrtl's range inference can figure this out - * @param that - * @return - */ - override def *(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Mul, that) - } - - /** Add that to this, here we return a fully unknown range, - * firrtl's range inference can figure this out - * @param that - * @return - */ - override def +&(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Add, that) - } - - /** Subtract that from this, here we return a fully unknown range, - * firrtl's range inference can figure this out - * @param that - * @return - */ - override def -&(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Sub, that) - } - - private def adjustBoundValue(value: BigDecimal, binaryPointValue: Int): BigDecimal = { - if (binaryPointValue >= 0) { - val maskFactor = BigDecimal(1 << binaryPointValue) - val a = (value * maskFactor) - val b = a.setScale(0, RoundingMode.DOWN) - val c = b / maskFactor - c - } else { - value - } - } - - private def adjustBound(bound: firrtlir.Bound, binaryPoint: BinaryPoint): firrtlir.Bound = { - binaryPoint match { - case KnownBinaryPoint(binaryPointValue) => - bound match { - case firrtlir.Open(value) => firrtlir.Open(adjustBoundValue(value, binaryPointValue)) - case firrtlir.Closed(value) => firrtlir.Closed(adjustBoundValue(value, binaryPointValue)) - case _ => bound - } - case _ => firrtlir.UnknownBound - } - } - - /** Creates a new range with the increased precision - * - * @param newBinaryPoint - * @return - */ - def incPrecision(newBinaryPoint: BinaryPoint): IntervalRange = { - newBinaryPoint match { - case KnownBinaryPoint(that) => - doFirrtlOp(PrimOps.IncP, that) - case _ => - throwException(s"$this.incPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know") - } - } - - /** Creates a new range with the decreased precision - * - * @param newBinaryPoint - * @return - */ - def decPrecision(newBinaryPoint: BinaryPoint): IntervalRange = { - newBinaryPoint match { - case KnownBinaryPoint(that) => - doFirrtlOp(PrimOps.DecP, that) - case _ => - throwException(s"$this.decPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know") - } - } - - /** Creates a new range with the given binary point, adjusting precision - * on bounds as necessary - * - * @param newBinaryPoint - * @return - */ - def setPrecision(newBinaryPoint: BinaryPoint): IntervalRange = { - newBinaryPoint match { - case KnownBinaryPoint(that) => - doFirrtlOp(PrimOps.SetP, that) - case _ => - throwException(s"$this.setPrecision(newBinaryPoint = $newBinaryPoint) error, newBinaryPoint must be know") - } - } - - /** Shift this range left, i.e. shifts the min and max by the specified amount - * @param that - * @return - */ - override def <<(that: Int): IntervalRange = { - doFirrtlOp(PrimOps.Shl, that) - } - - /** Shift this range left, i.e. shifts the min and max by the known width - * @param that - * @return - */ - override def <<(that: KnownWidth): IntervalRange = { - <<(that.value) - } - - /** Shift this range left, i.e. shifts the min and max by value - * @param that - * @return - */ - def <<(that: UInt): IntervalRange = { - doFirrtlDynamicShift(that, isLeft = true) - } - - /** Shift this range right, i.e. shifts the min and max by the specified amount - * @param that - * @return - */ - override def >>(that: Int): IntervalRange = { - doFirrtlOp(PrimOps.Shr, that) - } - - /** Shift this range right, i.e. shifts the min and max by the known width - * @param that - * @return - */ - override def >>(that: KnownWidth): IntervalRange = { - >>(that.value) - } - - /** Shift this range right, i.e. shifts the min and max by value - * @param that - * @return - */ - def >>(that: UInt): IntervalRange = { - doFirrtlDynamicShift(that, isLeft = false) - } - - /** - * Squeeze returns the intersection of the ranges this interval and that Interval - * @param that - * @return - */ - def squeeze(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Squeeze, that) - } - - /** - * Wrap the value of this [[Interval]] into the range of a different Interval with a presumably smaller range. - * @param that - * @return - */ - def wrap(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Wrap, that) - } - - /** - * Clip the value of this [[Interval]] into the range of a different Interval with a presumably smaller range. - * @param that - * @return - */ - def clip(that: IntervalRange): IntervalRange = { - doFirrtlOp(PrimOps.Clip, that) - } - - /** merges the ranges of this and that, basically takes lowest low, highest high and biggest bp - * set unknown if any of this or that's value of above is unknown - * Like an union but will slurp up points in between the two ranges that were part of neither - * @param that - * @return - */ - override def merge(that: IntervalRange): IntervalRange = { - val lowest = (this.getLowestPossibleValue, that.getLowestPossibleValue) match { - case (Some(l1), Some(l2)) => - if (l1 < l2) { this.lower } - else { that.lower } - case _ => - firrtlir.UnknownBound - } - val highest = (this.getHighestPossibleValue, that.getHighestPossibleValue) match { - case (Some(l1), Some(l2)) => - if (l1 >= l2) { this.lower } - else { that.lower } - case _ => - firrtlir.UnknownBound - } - val newBinaryPoint = (this.firrtlBinaryPoint, that.firrtlBinaryPoint) match { - case (firrtlir.IntWidth(b1), firrtlir.IntWidth(b2)) => - if (b1 > b2) { firrtlir.IntWidth(b1) } - else { firrtlir.IntWidth(b2) } - case _ => - firrtlir.UnknownWidth - } - IntervalRange(lowest, highest, newBinaryPoint) - } - - def binaryPoint: BinaryPoint = { - firrtlBinaryPoint match { - case firrtlir.IntWidth(n) => - assert(n < Int.MaxValue, s"binary point value $n is out of range") - KnownBinaryPoint(n.toInt) - case _ => UnknownBinaryPoint - } - } -} - abstract class Command { def sourceInfo: SourceInfo } @@ -858,14 +361,6 @@ abstract class Component extends Arg { } @nowarn("msg=class Port") // delete when Port becomes private case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component -@nowarn("msg=class Port") // delete when Port becomes private -case class DefBlackBox( - id: BaseBlackBox, - name: String, - ports: Seq[Port], - topDir: SpecifiedDirection, - params: Map[String, Param]) - extends Component case class Circuit( name: String, diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala index afffad1c..d30a5c83 100644 --- a/core/src/main/scala/chisel3/package.scala +++ b/core/src/main/scala/chisel3/package.scala @@ -152,31 +152,6 @@ package object chisel3 { def asBool(dummy: Int*): Bool = asBool } - // Fixed Point is experimental for now, but we alias the implicit conversion classes here - // to minimize disruption with existing code. - implicit class fromDoubleToLiteral(double: Double) - extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double) - - implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) - extends experimental.FixedPoint.Implicits.fromBigDecimalToLiteral(bigDecimal) - - // Interval is experimental for now, but we alias the implicit conversion classes here - // to minimize disruption with existing code. - implicit class fromIntToLiteralInterval(int: Int) - extends experimental.Interval.Implicits.fromIntToLiteralInterval(int) - - implicit class fromLongToLiteralInterval(long: Long) - extends experimental.Interval.Implicits.fromLongToLiteralInterval(long) - - implicit class fromBigIntToLiteralInterval(bigInt: BigInt) - extends experimental.Interval.Implicits.fromBigIntToLiteralInterval(bigInt) - - implicit class fromDoubleToLiteralInterval(double: Double) - extends experimental.Interval.Implicits.fromDoubleToLiteralInterval(double) - - implicit class fromBigDecimalToLiteralInterval(bigDecimal: BigDecimal) - extends experimental.Interval.Implicits.fromBigDecimalToLiteralInterval(bigDecimal) - implicit class fromIntToWidth(int: Int) { def W: Width = Width(int) } @@ -367,7 +342,7 @@ package object chisel3 { "duplicated with DataMirror.fullModulePorts, this returns an internal API, will be removed in Chisel 3.6", "Chisel 3.5" ) - def getModulePorts(m: Module): Seq[Port] = m.getPorts + def getModulePorts(m: Module): Seq[Port] = Seq.empty class BindingException(message: String) extends ChiselException(message) |
