summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/internal
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/main/scala/chisel3/internal
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/main/scala/chisel3/internal')
-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
3 files changed, 509 insertions, 52 deletions
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
}