summaryrefslogtreecommitdiff
path: root/chiselFrontend/src
diff options
context:
space:
mode:
authorChick Markley2019-10-18 19:44:08 -0700
committerAdam Izraelevitz2019-10-18 19:44:08 -0700
commit7b93b0f8c48e39cc9730cf9f91340cf733dadafe (patch)
tree3e9666c29d6c9901f221fed4728d05b9fd75067e /chiselFrontend/src
parentfafd984a923591841917cd4c3a1f4c823dc485b4 (diff)
Interval Data Type Support for Chisel (#1210)
Plan to be released with 3.3. Breaks experimental Range API. Adds new Interval type and associated support. This commit adds the following: - Renamed Range to IntervalRange to avoid name collision with scala Range - Changed RangeTransform macro to Return an IntervalRange - Improved error messages on missing comma or decimal - Added notational support for binary point - Some formatting cleanup also - SIntFactory - Change to use IntervalRange API - UIntFactory - UInt from range has custom width computation - It does not need to deal with lowerbound extending bit requirements - Code to handle special case of range"[0,0]" to have a width of 1 - IR.scala - Removed Bound and other constraint code that was duplicating firrtl stuff - Added new RangeType - Added IntervalRange class and object - RangeSpec - modified just a bit to handle notational differences - previous range interpolator returned tuple now returns IntervalRange - Add IntervalType to emitter - Added IntervalSpec with many tests - Added ScalaIntervalSimulatorSpec which tests golden model for Interval - Added ScalaIntervalSimulator which is a golden model for Interval - This gold may not have been polished to a high sheen - Add IntervalLit cases to Converter - Add Interval PrimOps to IR - asInterval, wrap, squz, clip, setp, decp, incp - Add IntervalLit class to IR - Add Interval to MonoConnect - Add Interval Type to Bits (in experimental package) - add conversions to Interval from other types - Add Interval clone stuff to Data - Add Literal creation helpers to chisel3 package - these may move to experimental if I can figure that out
Diffstat (limited to 'chiselFrontend/src')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/Bits.scala808
-rw-r--r--chiselFrontend/src/main/scala/chisel3/Data.scala8
-rw-r--r--chiselFrontend/src/main/scala/chisel3/SIntFactory.scala13
-rw-r--r--chiselFrontend/src/main/scala/chisel3/UIntFactory.scala37
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/package.scala3
-rw-r--r--chiselFrontend/src/main/scala/chisel3/experimental/package.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala6
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala551
-rw-r--r--chiselFrontend/src/main/scala/chisel3/package.scala222
10 files changed, 1466 insertions, 190 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/Bits.scala b/chiselFrontend/src/main/scala/chisel3/Bits.scala
index ef9a752b..28d1690d 100644
--- a/chiselFrontend/src/main/scala/chisel3/Bits.scala
+++ b/chiselFrontend/src/main/scala/chisel3/Bits.scala
@@ -4,13 +4,15 @@ package chisel3
import scala.language.experimental.macros
-import chisel3.experimental.FixedPoint
+import chisel3.experimental.{FixedPoint, Interval}
import chisel3.internal._
import chisel3.internal.Builder.pushOp
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform,
UIntTransform}
import chisel3.internal.firrtl.PrimOp._
+import _root_.firrtl.{ir => firrtlir}
+import _root_.firrtl.{constraint => firrtlconstraint}
// scalastyle:off method.name line.size.limit file.size.limit
@@ -349,6 +351,18 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
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)
@@ -670,6 +684,27 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
}
}
+ 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): Unit = {
this := that.asUInt
@@ -903,13 +938,35 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
}
}
+ 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)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
this := that.asSInt
}
}
-object SInt extends SIntFactory
-
sealed trait Reset extends Element with ToBoolable {
/** Casts this $coll to an [[AsyncReset]] */
final def asAsyncReset(): AsyncReset = macro SourceInfoWhiteboxTransform.noArg
@@ -1118,9 +1175,10 @@ sealed class Bool() extends UInt(1.W) with Reset {
pushOp(DefPrim(sourceInfo, AsyncReset(), AsAsyncResetOp, ref))
}
-object Bool extends BoolFactory
-
package experimental {
+
+ import chisel3.internal.firrtl.BinaryPoint
+
//scalastyle:off number.of.methods
/** 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.
@@ -1138,7 +1196,6 @@ package experimental {
*/
sealed class FixedPoint private(width: Width, val binaryPoint: BinaryPoint)
extends Bits(width) with Num[FixedPoint] {
- import FixedPoint.Implicits._
override def toString: String = {
val bindingString = litToDoubleOption match {
@@ -1356,7 +1413,6 @@ package experimental {
def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
throwException(s"Not is illegal on $this")
- // TODO(chick): Consider comparison with UInt and SInt
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)
@@ -1419,6 +1475,32 @@ package experimental {
}
}
+ 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 {
@@ -1426,7 +1508,6 @@ package experimental {
case _ => that.asFixedPoint(this.binaryPoint)
})
}
- //TODO(chick): Consider "convert" as an arithmetic conversion to UInt/SInt
}
/** Use PrivateObject to force users to specify width and binaryPoint by name
@@ -1441,6 +1522,7 @@ package experimental {
object FixedPoint {
import FixedPoint.Implicits._
+
/** Create an FixedPoint type with inferred width. */
def apply(): FixedPoint = apply(Width(), BinaryPoint())
@@ -1510,6 +1592,7 @@ package experimental {
result
}
+
object Implicits {
// implicit class fromDoubleToLiteral(val double: Double) extends AnyVal {
@@ -1522,12 +1605,715 @@ package experimental {
FixedPoint.fromDouble(double, width, binaryPoint)
}
}
+ }
+ }
+
+ //scalastyle:off number.of.methods cyclomatic.complexity
+ /**
+ * 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] {
+
+ override def toString: String = {
+ val bindingString = litOption match {
+ case Some(value) => s"($value)"
+ case _ => bindingToString
+ }
+ s"Interval$width$bindingString"
+ }
+
+ private[chisel3] override def cloneTypeWidth(w: Width): this.type =
+ new Interval(range).asInstanceOf[this.type]
+
+ //scalastyle:off cyclomatic.complexity
+ 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
+ final def unary_-%(): Interval = macro SourceInfoTransform.noArg
+
+ def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ Interval.Zero - this
+ }
+ def 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.noArg
+
+ 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")
+ }
+ }
- // implicit class fromIntToBinaryPoint(val int: Int) extends AnyVal {
- implicit class fromIntToBinaryPoint(int: Int) {
- def BP: BinaryPoint = BinaryPoint(int) // scalastyle:ignore method.name
+ /**
+ * 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 {
+ /** 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.toDouble(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)
+ 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 $value is not contained in specified range $range"
+ )
+ }
+ val result = Interval(range)
+ lit.bindLitArg(result)
+ }
+
+ /** How to create a BigInt from a double with a specific binaryPoint
+ *
+ * @param x a double value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(x: Double, binaryPoint: BinaryPoint): BigInt = {
+ val intBinaryPoint = binaryPoint match {
+ case KnownBinaryPoint(n) => n
+ case b =>
+ throw new ChiselException(s"Error converting Double $x to BigInt, binary point must be known, not $b")
+ }
+ val multiplier = BigInt(1) << intBinaryPoint
+ val result = BigInt(math.round(x * multiplier.doubleValue))
+ result
+
+ }
+
+ /**
+ * How to create a BigInt from a BigDecimal with a specific binaryPoint
+ *
+ * @param b a BigDecimal value
+ * @param binaryPoint a binaryPoint that you would like to use
+ * @return
+ */
+ def toBigInt(b: BigDecimal, binaryPoint: BinaryPoint): BigInt = {
+ val bp = binaryPoint match {
+ case KnownBinaryPoint(n) => n
+ case x =>
+ throw new ChiselException(s"Error converting BigDecimal $b to BigInt, binary point must be known, not $x")
+ }
+ (b * math.pow(2.0, bp.toDouble)).toBigInt
+ }
+
+ /**
+ * converts a bigInt with the given binaryPoint into the double representation
+ *
+ * @param i a BigInt
+ * @param binaryPoint the implied binaryPoint of @i
+ * @return
+ */
+ def toDouble(i: BigInt, binaryPoint: Int): Double = {
+ val multiplier = BigInt(1) << binaryPoint
+ val result = i.toDouble / multiplier.doubleValue
+ result
+ }
+
+ /**
+ * This returns the smallest number 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 number 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/chiselFrontend/src/main/scala/chisel3/Data.scala b/chiselFrontend/src/main/scala/chisel3/Data.scala
index 1a931135..59348dcd 100644
--- a/chiselFrontend/src/main/scala/chisel3/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/Data.scala
@@ -3,12 +3,11 @@
package chisel3
import scala.language.experimental.macros
-
-import chisel3.experimental.{Analog, DataMirror, FixedPoint}
+import chisel3.experimental.{Analog, DataMirror, FixedPoint, Interval}
import chisel3.internal.Builder.pushCommand
import chisel3.internal._
import chisel3.internal.firrtl._
-import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, DeprecatedSourceInfo}
+import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo}
/** User-specified directions.
*/
@@ -195,6 +194,9 @@ private[chisel3] object cloneSupertype {
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}")
diff --git a/chiselFrontend/src/main/scala/chisel3/SIntFactory.scala b/chiselFrontend/src/main/scala/chisel3/SIntFactory.scala
index 607e2e35..c1c6b1db 100644
--- a/chiselFrontend/src/main/scala/chisel3/SIntFactory.scala
+++ b/chiselFrontend/src/main/scala/chisel3/SIntFactory.scala
@@ -2,9 +2,7 @@
package chisel3
-import chisel3.internal.firrtl.{KnownSIntRange, NumericBound, Range, SLit, Width}
-
-// scalastyle:off method.name
+import chisel3.internal.firrtl.{IntervalRange, SLit, Width}
trait SIntFactory {
/** Create an SInt type with inferred width. */
@@ -13,15 +11,12 @@ trait SIntFactory {
def apply(width: Width): SInt = new SInt(width)
/** Create a SInt with the specified range */
- def apply(range: Range): SInt = {
+ def apply(range: IntervalRange): SInt = {
apply(range.getWidth)
}
- /** Create a SInt with the specified range */
- def apply(range: (NumericBound[Int], NumericBound[Int])): SInt = {
- apply(KnownSIntRange(range._1, range._2))
- }
- /** Create an SInt literal with specified width. */
+ /** Create an SInt literal with specified width. */
+ // scalastyle:off method.name
protected[chisel3] def Lit(value: BigInt, width: Width): SInt = {
val lit = SLit(value, width)
val result = new SInt(lit.width)
diff --git a/chiselFrontend/src/main/scala/chisel3/UIntFactory.scala b/chiselFrontend/src/main/scala/chisel3/UIntFactory.scala
index a62aa493..3868962b 100644
--- a/chiselFrontend/src/main/scala/chisel3/UIntFactory.scala
+++ b/chiselFrontend/src/main/scala/chisel3/UIntFactory.scala
@@ -2,9 +2,10 @@
package chisel3
-import chisel3.internal.firrtl.{KnownUIntRange, NumericBound, Range, ULit, Width}
-
-// scalastyle:off method.name
+import chisel3.internal.firrtl.{IntervalRange, KnownWidth, ULit, UnknownWidth, Width}
+import firrtl.Utils
+import firrtl.constraint.IsKnown
+import firrtl.ir.{Closed, IntWidth, Open}
// This is currently a factory because both Bits and UInt inherit it.
trait UIntFactory {
@@ -13,20 +14,34 @@ trait UIntFactory {
/** Create a UInt port with specified width. */
def apply(width: Width): UInt = new UInt(width)
- /** Create a UInt literal with specified width. */
+ /** Create a UInt literal with specified width. */
+ // scalastyle:off method.name
protected[chisel3] def Lit(value: BigInt, width: Width): UInt = {
val lit = ULit(value, width)
val result = new UInt(lit.width)
// Bind result to being an Literal
lit.bindLitArg(result)
}
+ /** Create a UInt with the specified range, validate that range is effectively > 0
+ */
+ //scalastyle:off cyclomatic.complexity
+ 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 _ =>
+ }
- /** Create a UInt with the specified range */
- def apply(range: Range): UInt = {
- apply(range.getWidth)
- }
- /** Create a UInt with the specified range */
- def apply(range: (NumericBound[Int], NumericBound[Int])): UInt = {
- apply(KnownUIntRange(range._1, range._2))
+ // 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/chiselFrontend/src/main/scala/chisel3/core/package.scala b/chiselFrontend/src/main/scala/chisel3/core/package.scala
index 2c60ce85..92c4617b 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/package.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/package.scala
@@ -231,8 +231,7 @@ package object core {
@deprecated("Use the version in chisel3.experimental._", "3.2")
implicit class fromDoubleToLiteral(double: Double) extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double)
@deprecated("Use the version in chisel3.experimental._", "3.2")
- implicit class fromIntToBinaryPoint(int: Int) extends experimental.FixedPoint.Implicits.fromIntToBinaryPoint(int)
-
+ implicit class fromIntToBinaryPoint(int: Int) extends chisel3.fromIntToBinaryPoint(int)
@deprecated("Use the version in chisel3.experimental._", "3.2")
type RunFirrtlTransform = chisel3.experimental.RunFirrtlTransform
diff --git a/chiselFrontend/src/main/scala/chisel3/experimental/package.scala b/chiselFrontend/src/main/scala/chisel3/experimental/package.scala
index 2ce3a1c6..7ade2cb3 100644
--- a/chiselFrontend/src/main/scala/chisel3/experimental/package.scala
+++ b/chiselFrontend/src/main/scala/chisel3/experimental/package.scala
@@ -55,7 +55,6 @@ package object experimental { // scalastyle:ignore object.name
val Direction = ActualDirection
implicit class ChiselRange(val sc: StringContext) extends AnyVal {
- import chisel3.internal.firrtl.NumericBound
import scala.language.experimental.macros
@@ -67,7 +66,7 @@ package object experimental { // scalastyle:ignore object.name
* UInt(range"[0, \${myInt + 2})")
* }}}
*/
- def range(args: Any*): (NumericBound[Int], NumericBound[Int]) = macro chisel3.internal.RangeTransform.apply
+ def range(args: Any*): chisel3.internal.firrtl.IntervalRange = macro chisel3.internal.RangeTransform.apply
}
class dump extends chisel3.internal.naming.dump // scalastyle:ignore class.name
@@ -76,6 +75,7 @@ package object experimental { // scalastyle:ignore object.name
object BundleLiterals {
implicit class AddBundleLiteralConstructor[T <: Bundle](x: T) {
+ //scalastyle:off method.name
def Lit(elems: (T => (Data, Data))*): T = {
x._makeLit(elems: _*)
}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
index 1c001183..41402021 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -3,7 +3,7 @@
package chisel3.internal
import chisel3._
-import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, UnsafeEnum}
+import chisel3.experimental.{Analog, BaseModule, EnumType, FixedPoint, Interval, UnsafeEnum}
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.{Connect, DefInvalid}
import scala.language.experimental.macros
@@ -85,6 +85,8 @@ private[chisel3] object MonoConnect {
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) =>
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
index 5309609b..548ed294 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -71,6 +71,11 @@ private[chisel3] object Converter {
val uint = convert(ULit(unsigned, fplit.width), ctx)
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)
+ 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")
}
@@ -220,6 +225,7 @@ private[chisel3] object Converter {
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[_] => fir.VectorType(extractType(d.sample_element, clearDir), d.length)
case d: Record =>
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
index 4643f66c..bc662ddb 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -5,11 +5,15 @@ package chisel3.internal.firrtl
import chisel3._
import chisel3.internal._
import chisel3.internal.sourceinfo.SourceInfo
-import chisel3.experimental.{BaseModule, ChiselAnnotation, Param}
+import chisel3.experimental._
+import _root_.firrtl.{ir => firrtlir}
+import _root_.firrtl.PrimOps
+
+import scala.math.BigDecimal.RoundingMode
// scalastyle:off number.of.types
-case class PrimOp(val name: String) {
+case class PrimOp(name: String) {
override def toString: String = name
}
@@ -45,7 +49,13 @@ object PrimOp {
val AsUIntOp = PrimOp("asUInt")
val AsSIntOp = PrimOp("asSInt")
val AsFixedPointOp = PrimOp("asFixedPoint")
- val SetBinaryPoint = PrimOp("bpset")
+ val AsIntervalOp = PrimOp("asInterval")
+ val WrapOp = PrimOp("wrap")
+ val SqueezeOp = PrimOp("squz")
+ val ClipOp = PrimOp("clip")
+ val SetBinaryPoint = PrimOp("setp")
+ val IncreasePrecision = PrimOp("incp")
+ val DecreasePrecision = PrimOp("decp")
val AsClockOp = PrimOp("asClock")
val AsAsyncResetOp = PrimOp("asAsyncReset")
}
@@ -111,6 +121,18 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n
def minWidth: Int = 1 + n.bitLength
}
+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
+}
+
case class Ref(name: String) extends Arg
case class ModuleIO(mod: BaseModule, name: String) extends Arg {
override def fullName(ctx: Component): String =
@@ -125,54 +147,6 @@ case class Index(imm: Arg, value: Arg) extends Arg {
override def fullName(ctx: Component): String = s"${imm.fullName(ctx)}[${value.fullName(ctx)}]"
}
-sealed trait Bound
-sealed trait NumericBound[T] extends Bound {
- val value: T
-}
-sealed case class Open[T](value: T) extends NumericBound[T]
-sealed case class Closed[T](value: T) extends NumericBound[T]
-
-sealed trait Range {
- val min: Bound
- val max: Bound
- def getWidth: Width
-}
-
-sealed trait KnownIntRange extends Range {
- val min: NumericBound[Int]
- val max: NumericBound[Int]
-
- require( (min, max) match {
- case (Open(low_val), Open(high_val)) => low_val < high_val - 1
- case (Closed(low_val), Open(high_val)) => low_val < high_val
- case (Open(low_val), Closed(high_val)) => low_val < high_val
- case (Closed(low_val), Closed(high_val)) => low_val <= high_val
- })
-}
-
-sealed case class KnownUIntRange(min: NumericBound[Int], max: NumericBound[Int]) extends KnownIntRange {
- require (min.value >= 0)
-
- def getWidth: Width = max match {
- case Open(v) => Width(BigInt(v - 1).bitLength.max(1))
- case Closed(v) => Width(BigInt(v).bitLength.max(1))
- }
-}
-
-sealed case class KnownSIntRange(min: NumericBound[Int], max: NumericBound[Int]) extends KnownIntRange {
-
- val maxWidth = max match {
- case Open(v) => Width(BigInt(v - 1).bitLength + 1)
- case Closed(v) => Width(BigInt(v).bitLength + 1)
- }
- val minWidth = min match {
- case Open(v) => Width(BigInt(v + 1).bitLength + 1)
- case Closed(v) => Width(BigInt(v).bitLength + 1)
- }
- def getWidth: Width = maxWidth.max(minWidth)
-
-}
-
object Width {
def apply(x: Int): Width = KnownWidth(x)
def apply(): Width = UnknownWidth()
@@ -257,6 +231,481 @@ 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
+ }
+ }
+
+ //scalastyle:off method.name
+ 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 _ =>
+ }
+
+ //scalastyle:off cyclomatic.complexity
+ 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) =>
+ lower 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: Seq[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
}
diff --git a/chiselFrontend/src/main/scala/chisel3/package.scala b/chiselFrontend/src/main/scala/chisel3/package.scala
index 51bcf1fe..3af21d57 100644
--- a/chiselFrontend/src/main/scala/chisel3/package.scala
+++ b/chiselFrontend/src/main/scala/chisel3/package.scala
@@ -1,118 +1,140 @@
// See LICENSE for license details.
+import chisel3.internal.firrtl.BinaryPoint
+
/** This package contains the main chisel3 API.
*/
package object chisel3 { // scalastyle:ignore package.object.name
import internal.firrtl.{Port, Width}
- import internal.sourceinfo.{SourceInfo, VecTransform}
- import internal.{Builder, chiselRuntimeDeprecated}
+ import internal.Builder
import scala.language.implicitConversions
- /**
- * These implicit classes allow one to convert scala.Int|scala.BigInt to
- * Chisel.UInt|Chisel.SInt by calling .asUInt|.asSInt on them, respectively.
- * The versions .asUInt(width)|.asSInt(width) are also available to explicitly
- * mark a width for the new literal.
- *
- * Also provides .asBool to scala.Boolean and .asUInt to String
- *
- * Note that, for stylistic reasons, one should avoid extracting immediately
- * after this call using apply, ie. 0.asUInt(1)(0) due to potential for
- * confusion (the 1 is a bit length and the 0 is a bit extraction position).
- * Prefer storing the result and then extracting from it.
- *
- * Implementation note: the empty parameter list (like `U()`) is necessary to prevent
- * interpreting calls that have a non-Width parameter as a chained apply, otherwise things like
- * `0.asUInt(16)` (instead of `16.W`) compile without error and produce undesired results.
- */
- implicit class fromBigIntToLiteral(bigint: BigInt) {
- /** Int to Bool conversion, allowing compact syntax like 1.B and 0.B
- */
- def B: Bool = bigint match { // scalastyle:ignore method.name
- case bigint if bigint == 0 => Bool.Lit(false)
- case bigint if bigint == 1 => Bool.Lit(true)
- case bigint => Builder.error(s"Cannot convert $bigint to Bool, must be 0 or 1"); Bool.Lit(false)
- }
- /** Int to UInt conversion, recommended style for constants.
- */
- def U: UInt = UInt.Lit(bigint, Width()) // scalastyle:ignore method.name
- /** Int to SInt conversion, recommended style for constants.
- */
- def S: SInt = SInt.Lit(bigint, Width()) // scalastyle:ignore method.name
- /** Int to UInt conversion with specified width, recommended style for constants.
- */
- def U(width: Width): UInt = UInt.Lit(bigint, width) // scalastyle:ignore method.name
- /** Int to SInt conversion with specified width, recommended style for constants.
- */
- def S(width: Width): SInt = SInt.Lit(bigint, width) // scalastyle:ignore method.name
-
- /** Int to UInt conversion, recommended style for variables.
- */
- def asUInt(): UInt = UInt.Lit(bigint, Width())
- /** Int to SInt conversion, recommended style for variables.
- */
- def asSInt(): SInt = SInt.Lit(bigint, Width())
- /** Int to UInt conversion with specified width, recommended style for variables.
- */
- def asUInt(width: Width): UInt = UInt.Lit(bigint, width)
- /** Int to SInt conversion with specified width, recommended style for variables.
- */
- def asSInt(width: Width): SInt = SInt.Lit(bigint, width)
- }
+ /**
+ * These implicit classes allow one to convert scala.Int|scala.BigInt to
+ * Chisel.UInt|Chisel.SInt by calling .asUInt|.asSInt on them, respectively.
+ * The versions .asUInt(width)|.asSInt(width) are also available to explicitly
+ * mark a width for the new literal.
+ *
+ * Also provides .asBool to scala.Boolean and .asUInt to String
+ *
+ * Note that, for stylistic reasons, one should avoid extracting immediately
+ * after this call using apply, ie. 0.asUInt(1)(0) due to potential for
+ * confusion (the 1 is a bit length and the 0 is a bit extraction position).
+ * Prefer storing the result and then extracting from it.
+ *
+ * Implementation note: the empty parameter list (like `U()`) is necessary to prevent
+ * interpreting calls that have a non-Width parameter as a chained apply, otherwise things like
+ * `0.asUInt(16)` (instead of `16.W`) compile without error and produce undesired results.
+ */
+ implicit class fromBigIntToLiteral(bigint: BigInt) {
+ /** Int to Bool conversion, allowing compact syntax like 1.B and 0.B
+ */
+ def B: Bool = bigint match { // scalastyle:ignore method.name
+ case bigint if bigint == 0 => Bool.Lit(false)
+ case bigint if bigint == 1 => Bool.Lit(true)
+ case bigint => Builder.error(s"Cannot convert $bigint to Bool, must be 0 or 1"); Bool.Lit(false)
+ }
+ /** Int to UInt conversion, recommended style for constants.
+ */
+ def U: UInt = UInt.Lit(bigint, Width()) // scalastyle:ignore method.name
+ /** Int to SInt conversion, recommended style for constants.
+ */
+ def S: SInt = SInt.Lit(bigint, Width()) // scalastyle:ignore method.name
+ /** Int to UInt conversion with specified width, recommended style for constants.
+ */
+ def U(width: Width): UInt = UInt.Lit(bigint, width) // scalastyle:ignore method.name
+ /** Int to SInt conversion with specified width, recommended style for constants.
+ */
+ def S(width: Width): SInt = SInt.Lit(bigint, width) // scalastyle:ignore method.name
- implicit class fromIntToLiteral(int: Int) extends fromBigIntToLiteral(int)
- implicit class fromLongToLiteral(long: Long) extends fromBigIntToLiteral(long)
-
- implicit class fromStringToLiteral(str: String) {
- /** String to UInt parse, recommended style for constants.
- */
- def U: UInt = str.asUInt() // scalastyle:ignore method.name
- /** String to UInt parse with specified width, recommended style for constants.
- */
- def U(width: Width): UInt = str.asUInt(width) // scalastyle:ignore method.name
-
- /** String to UInt parse, recommended style for variables.
- */
- def asUInt(): UInt = {
- val bigInt = parse(str)
- UInt.Lit(bigInt, Width(bigInt.bitLength max 1))
- }
- /** String to UInt parse with specified width, recommended style for variables.
- */
- def asUInt(width: Width): UInt = UInt.Lit(parse(str), width)
-
- protected def parse(n: String) = {
- val (base, num) = n.splitAt(1)
- val radix = base match {
- case "x" | "h" => 16
- case "d" => 10
- case "o" => 8
- case "b" => 2
- case _ => Builder.error(s"Invalid base $base"); 2
- }
- BigInt(num.filterNot(_ == '_'), radix)
- }
- }
+ /** Int to UInt conversion, recommended style for variables.
+ */
+ def asUInt(): UInt = UInt.Lit(bigint, Width())
+ /** Int to SInt conversion, recommended style for variables.
+ */
+ def asSInt(): SInt = SInt.Lit(bigint, Width())
+ /** Int to UInt conversion with specified width, recommended style for variables.
+ */
+ def asUInt(width: Width): UInt = UInt.Lit(bigint, width)
+ /** Int to SInt conversion with specified width, recommended style for variables.
+ */
+ def asSInt(width: Width): SInt = SInt.Lit(bigint, width)
+ }
- implicit class fromBooleanToLiteral(boolean: Boolean) {
- /** Boolean to Bool conversion, recommended style for constants.
- */
- def B: Bool = Bool.Lit(boolean) // scalastyle:ignore method.name
+ implicit class fromIntToLiteral(int: Int) extends fromBigIntToLiteral(int)
+ implicit class fromLongToLiteral(long: Long) extends fromBigIntToLiteral(long)
- /** Boolean to Bool conversion, recommended style for variables.
- */
- def asBool(): Bool = Bool.Lit(boolean)
+ implicit class fromStringToLiteral(str: String) {
+ /** String to UInt parse, recommended style for constants.
+ */
+ def U: UInt = str.asUInt() // scalastyle:ignore method.name
+ /** String to UInt parse with specified width, recommended style for constants.
+ */
+ def U(width: Width): UInt = str.asUInt(width) // scalastyle:ignore method.name
+
+ /** String to UInt parse, recommended style for variables.
+ */
+ def asUInt(): UInt = {
+ val bigInt = parse(str)
+ UInt.Lit(bigInt, Width(bigInt.bitLength max 1))
+ }
+ /** String to UInt parse with specified width, recommended style for variables.
+ */
+ def asUInt(width: Width): UInt = UInt.Lit(parse(str), width)
+
+ protected def parse(n: String): BigInt = {
+ val (base, num) = n.splitAt(1)
+ val radix = base match {
+ case "x" | "h" => 16
+ case "d" => 10
+ case "o" => 8
+ case "b" => 2
+ case _ => Builder.error(s"Invalid base $base"); 2
}
+ BigInt(num.filterNot(_ == '_'), radix)
+ }
+ }
- // 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 fromIntToBinaryPoint(int: Int) extends experimental.FixedPoint.Implicits.fromIntToBinaryPoint(int)
+ implicit class fromIntToBinaryPoint(int: Int) {
+ def BP: BinaryPoint = BinaryPoint(int) // scalastyle:ignore method.name
+ }
- implicit class fromIntToWidth(int: Int) {
- def W: Width = Width(int) // scalastyle:ignore method.name
- }
+ implicit class fromBooleanToLiteral(boolean: Boolean) {
+ /** Boolean to Bool conversion, recommended style for constants.
+ */
+ def B: Bool = Bool.Lit(boolean) // scalastyle:ignore method.name
+
+ /** Boolean to Bool conversion, recommended style for variables.
+ */
+ def asBool(): Bool = Bool.Lit(boolean)
+ }
+
+ // 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)
+
+ // 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) // scalastyle:ignore method.name
+ }
val WireInit = WireDefault