From 0bcce65d5e3001b1b7098aa2c1ccd60fcc2a6628 Mon Sep 17 00:00:00 2001 From: chick Date: Thu, 12 Dec 2019 12:06:15 -0800 Subject: - New trait HasBinaryPoint which provides literal values as double and big decimal - made .F and .I work for creating fixed point and interval lits from big decimal - Added NumObject trait which provides new math conversions - Made a Num object that extends NumObject - Add this trait to FixedPoint and Interval for backward compatibility - Removed code that is now in NumObject, keeping things DRY - Add tests to FixedPointSpec to show lit conversion to double and big decimal - Add tests to IntervalSpec to show lit conversion to double and big decimal - Add tests to LiteralExtractorSpec to show general math conversions between BigInts with binary points and double and big decimal --- .../src/main/scala/chisel3/Aggregate.scala | 2 +- chiselFrontend/src/main/scala/chisel3/Bits.scala | 160 +++++++++------------ chiselFrontend/src/main/scala/chisel3/Num.scala | 129 +++++++++++++++++ .../src/main/scala/chisel3/package.scala | 3 + 4 files changed, 200 insertions(+), 94 deletions(-) (limited to 'chiselFrontend') diff --git a/chiselFrontend/src/main/scala/chisel3/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/Aggregate.scala index 42b40ed9..8141fdba 100644 --- a/chiselFrontend/src/main/scala/chisel3/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/Aggregate.scala @@ -43,7 +43,7 @@ sealed abstract class Aggregate extends Data { } } - override def litOption: Option[BigInt] = ??? // TODO implement me + override def litOption: Option[BigInt] = None // TODO implement me /** Returns a Seq of the immediate contents of this Aggregate, in order. */ diff --git a/chiselFrontend/src/main/scala/chisel3/Bits.scala b/chiselFrontend/src/main/scala/chisel3/Bits.scala index 28d1690d..633636fd 100644 --- a/chiselFrontend/src/main/scala/chisel3/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/Bits.scala @@ -1179,6 +1179,43 @@ package experimental { import chisel3.internal.firrtl.BinaryPoint + /** Chisel types that have binary points support retrieving + * literal values as `Double` or `BigDecimal` + */ + trait HasBinaryPoint { self: Bits => + def binaryPoint: BinaryPoint + + /** Return the [[Double]] value of this instance if it is a Literal + * @note this method may return throw an exception if the literal value won't fit in a Double + */ + def litToDoubleOption: Option[Double] = { + litOption match { + case Some(bigInt: BigInt) => + Some(Num.toDouble(bigInt, binaryPoint)) + case _ => None + } + } + + /** Return the double value of this instance assuming it is a literal (convenience method) + */ + def litToDouble: Double = litToDoubleOption.get + + /** Return the [[BigDecimal]] value of this instance if it is a Literal + * @note this method may return throw an exception if the literal value won't fit in a BigDecimal + */ + def litToBigDecimalOption: Option[BigDecimal] = { + litOption match { + case Some(bigInt: BigInt) => + Some(Num.toBigDecimal(bigInt, binaryPoint)) + case _ => None + } + } + + /** Return the [[BigDecimal]] value of this instance assuming it is a literal (convenience method) + * @return + */ + def litToBigDecimal: BigDecimal = litToBigDecimalOption.get + } //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. @@ -1195,7 +1232,7 @@ package experimental { * @define constantWidth @note The width of the returned $coll is unchanged, i.e., `width of this`. */ sealed class FixedPoint private(width: Width, val binaryPoint: BinaryPoint) - extends Bits(width) with Num[FixedPoint] { + extends Bits(width) with Num[FixedPoint] with HasBinaryPoint { override def toString: String = { val bindingString = litToDoubleOption match { @@ -1218,16 +1255,6 @@ package experimental { case _ => this badConnect that } - /** Convert to a [[scala.Option]] of [[scala.Boolean]] */ - def litToDoubleOption: Option[Double] = litOption.map { intVal => - val multiplier = math.pow(2, binaryPoint.get) - intVal.toDouble / multiplier - } - - /** Convert to a [[scala.Option]] */ - def litToDouble: Double = litToDoubleOption.get - - /** Unary negation (expanding width) * * @return a hardware $coll equal to zero minus this $coll @@ -1519,7 +1546,7 @@ package experimental { * Factory and convenience methods for the FixedPoint class * IMPORTANT: The API provided here is experimental and may change in the future. */ - object FixedPoint { + object FixedPoint extends NumObject { import FixedPoint.Implicits._ @@ -1559,6 +1586,14 @@ package experimental { toBigInt(value, binaryPoint.get), width = width, binaryPoint = binaryPoint ) } + /** Create an FixedPoint literal with inferred width from BigDecimal. + * Use PrivateObject to force users to specify width and binaryPoint by name + */ + def fromBigDecimal(value: BigDecimal, width: Width, binaryPoint: BinaryPoint): FixedPoint = { + fromBigInt( + toBigInt(value, binaryPoint.get), width = width, binaryPoint = binaryPoint + ) + } /** Create an FixedPoint port with specified width and binary position. */ def apply(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = { @@ -1568,34 +1603,10 @@ package experimental { lit.bindLitArg(newLiteral) } - /** - * 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: Int): BigInt = { - val multiplier = math.pow(2, binaryPoint) - val result = BigInt(math.round(x * multiplier)) - result - } - - /** - * 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 = math.pow(2, binaryPoint) - val result = i.toDouble / multiplier - result - } object Implicits { - // implicit class fromDoubleToLiteral(val double: Double) extends AnyVal { implicit class fromDoubleToLiteral(double: Double) { def F(binaryPoint: BinaryPoint): FixedPoint = { FixedPoint.fromDouble(double, Width(), binaryPoint) @@ -1605,6 +1616,16 @@ package experimental { FixedPoint.fromDouble(double, width, binaryPoint) } } + + implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) { + def F(binaryPoint: BinaryPoint): FixedPoint = { + FixedPoint.fromBigDecimal(bigDecimal, Width(), binaryPoint) + } + + def F(width: Width, binaryPoint: BinaryPoint): FixedPoint = { + FixedPoint.fromBigDecimal(bigDecimal, width, binaryPoint) + } + } } } @@ -1627,7 +1648,7 @@ package experimental { * @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] { + extends Bits(range.getWidth) with Num[Interval] with HasBinaryPoint { override def toString: String = { val bindingString = litOption match { @@ -2071,7 +2092,7 @@ package experimental { * Factory and convenience methods for the Interval class * IMPORTANT: The API provided here is experimental and may change in the future. */ - object Interval { + object Interval extends NumObject { /** Create an Interval type with inferred width and binary point. */ def apply(): Interval = Interval(range"[?,?]") @@ -2155,78 +2176,31 @@ package experimental { case _ => } val lit = IntervalLit(value, width, binaryPoint) - val bound = firrtlir.Closed(Interval.toDouble(value, binaryPoint.asInstanceOf[KnownBinaryPoint].value)) + val bound = firrtlir.Closed(Interval.toBigDecimal(value, binaryPoint.asInstanceOf[KnownBinaryPoint].value)) val result = new Interval(IntervalRange(bound, bound, binaryPoint)) lit.bindLitArg(result) } protected[chisel3] def Lit(value: BigInt, range: IntervalRange): Interval = { val lit = IntervalLit(value, range.getWidth, range.binaryPoint) - val bigDecimal = BigDecimal(value) + val bigDecimal = BigDecimal(value) / (1 << lit.binaryPoint.get) val inRange = (range.lowerBound, range.upperBound) match { case (firrtlir.Closed(l), firrtlir.Closed(u)) => l <= bigDecimal && bigDecimal <= u - case (firrtlir.Closed(l), firrtlir.Open(u)) => l <= bigDecimal && bigDecimal <= u - case (firrtlir.Open(l), firrtlir.Closed(u)) => l <= bigDecimal && bigDecimal <= u - case (firrtlir.Open(l), firrtlir.Open(u)) => l <= bigDecimal && bigDecimal <= u + 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" + s"Error literal interval value $bigDecimal 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 + * This returns the smallest Interval literal that can legally fit in range, if possible * If the lower bound or binary point is not known then return None * * @param range use to figure low number @@ -2245,7 +2219,7 @@ package experimental { } /** - * This returns the largest number that can legally fit in range, if possible + * This returns the largest Interval literal that can legally fit in range, if possible * If the upper bound or binary point is not known then return None * * @param range use to figure low number diff --git a/chiselFrontend/src/main/scala/chisel3/Num.scala b/chiselFrontend/src/main/scala/chisel3/Num.scala index 8984697f..e4d61d94 100644 --- a/chiselFrontend/src/main/scala/chisel3/Num.scala +++ b/chiselFrontend/src/main/scala/chisel3/Num.scala @@ -2,6 +2,9 @@ package chisel3 +import chisel3.internal.ChiselException +import chisel3.internal.firrtl.{BinaryPoint, KnownBinaryPoint} + import scala.language.experimental.macros import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} @@ -177,3 +180,129 @@ trait Num[T <: Data] { def do_max(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = Mux(this < that, that, this.asInstanceOf[T]) } + +object Num extends NumObject + +/** NumbObject has a lot of convenience methods for converting between + * BigInts and Double and BigDecimal + * For backwards compatibility this is used with FixedPoint and Interval objects + * but is better used with the Num Object + * + */ +trait NumObject { + val MaxBitsBigIntToBigDecimal = 108 + val MaxBitsBigIntToDouble = 53 + + /** + * 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: Int): BigInt = { + val multiplier = math.pow(2, binaryPoint) + val result = BigInt(math.round(x * multiplier)) + result + } + + /** + * How to create a bigint from a big decimal with a specific binaryPoint + * @param x a BigDecimal value + * @param binaryPoint a binaryPoint that you would like to use + * @return + */ + def toBigInt(x: Double, binaryPoint: BinaryPoint): BigInt = { + binaryPoint match { + case KnownBinaryPoint(n) => toBigInt(x, n) + case x => + throw new ChiselException(s"Error converting Double $x to BigInt, binary point must be known, not $x") + } + } + + /** + * How to create a bigint from a big decimal with a specific binaryPoint (int) + * @param x a BigDecimal value + * @param binaryPoint a binaryPoint that you would like to use + * @return + */ + def toBigInt(x: BigDecimal, binaryPoint: Int): BigInt = { + val multiplier = math.pow(2, binaryPoint) + val result = (x * multiplier).rounded.toBigInt() + result + } + + /** + * How to create a bigint from a big decimal with a specific binaryPoint + * @param value a BigDecimal value + * @param binaryPoint a binaryPoint that you would like to use + * @return + */ + def toBigInt(value: BigDecimal, binaryPoint: BinaryPoint): BigInt = { + binaryPoint match { + case KnownBinaryPoint(n) => toBigInt(value, n) + case x => + throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x") + } + } + + /** + * 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 = { + if(i.bitLength >= 54) { + throw new ChiselException( + s"BigInt $i with bitlength ${i.bitLength} is too big, precision lost with > $MaxBitsBigIntToDouble bits" + ) + } + val multiplier = math.pow(2, binaryPoint) + val result = i.toDouble / multiplier + result + } + + /** + * converts a bigInt with the given binaryPoint into the double representation + * @param value a bigint + * @param binaryPoint the implied binaryPoint of @i + * @return + */ + def toDouble(value: BigInt, binaryPoint: BinaryPoint): Double = { + binaryPoint match { + case KnownBinaryPoint(n) => toDouble(value, n) + case x => + throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x") + } } + + /** + * converts a bigInt with the given binaryPoint into the BigDecimal representation + * @param value a bigint + * @param binaryPoint the implied binaryPoint of @i + * @return + */ + def toBigDecimal(value: BigInt, binaryPoint: Int): BigDecimal = { + if(value.bitLength > 108) { + throw new ChiselException( + s"BigInt $value with bitlength ${value.bitLength} is too big, precision lost with > $MaxBitsBigIntToBigDecimal bits" + ) + } + val multiplier = BigDecimal(1.0) / BigDecimal(math.pow(2, binaryPoint)) + val result = BigDecimal(value) * multiplier + result + } + + /** + * converts a bigInt with the given binaryPoint into the BigDecimal representation + * @param value a bigint + * @param binaryPoint the implied binaryPoint of @i + * @return + */ + def toBigDecimal(value: BigInt, binaryPoint: BinaryPoint): BigDecimal = { + binaryPoint match { + case KnownBinaryPoint(n) => toBigDecimal(value, n) + case x => + throw new ChiselException(s"Error converting BigDecimal $value to BigInt, binary point must be known, not $x") + } + } +} \ No newline at end of file diff --git a/chiselFrontend/src/main/scala/chisel3/package.scala b/chiselFrontend/src/main/scala/chisel3/package.scala index 3af21d57..65bfdeb7 100644 --- a/chiselFrontend/src/main/scala/chisel3/package.scala +++ b/chiselFrontend/src/main/scala/chisel3/package.scala @@ -115,6 +115,9 @@ package object chisel3 { // scalastyle:ignore package.object.name implicit class fromDoubleToLiteral(double: Double) extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double) + implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) + extends experimental.FixedPoint.Implicits.fromBigDecimalToLiteral(bigDecimal) + // Interval is experimental for now, but we alias the implicit conversion classes here // to minimize disruption with existing code. implicit class fromIntToLiteralInterval(int: Int) -- cgit v1.2.3 From 481736c3ebce29932b54ac72e01d6656e4995fca Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Thu, 23 Jan 2020 09:53:11 -0800 Subject: Minor changes - update comments, use MaxBitsBigIntToBigDecimal instead of '108'. (#1309) Co-authored-by: Chick Markley --- chiselFrontend/src/main/scala/chisel3/Bits.scala | 4 ++-- chiselFrontend/src/main/scala/chisel3/Num.scala | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'chiselFrontend') diff --git a/chiselFrontend/src/main/scala/chisel3/Bits.scala b/chiselFrontend/src/main/scala/chisel3/Bits.scala index 633636fd..57ce98d2 100644 --- a/chiselFrontend/src/main/scala/chisel3/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/Bits.scala @@ -1186,7 +1186,7 @@ package experimental { def binaryPoint: BinaryPoint /** Return the [[Double]] value of this instance if it is a Literal - * @note this method may return throw an exception if the literal value won't fit in a Double + * @note this method may throw an exception if the literal value won't fit in a Double */ def litToDoubleOption: Option[Double] = { litOption match { @@ -1201,7 +1201,7 @@ package experimental { def litToDouble: Double = litToDoubleOption.get /** Return the [[BigDecimal]] value of this instance if it is a Literal - * @note this method may return throw an exception if the literal value won't fit in a BigDecimal + * @note this method may throw an exception if the literal value won't fit in a BigDecimal */ def litToBigDecimalOption: Option[BigDecimal] = { litOption match { diff --git a/chiselFrontend/src/main/scala/chisel3/Num.scala b/chiselFrontend/src/main/scala/chisel3/Num.scala index e4d61d94..7a6b0744 100644 --- a/chiselFrontend/src/main/scala/chisel3/Num.scala +++ b/chiselFrontend/src/main/scala/chisel3/Num.scala @@ -282,7 +282,7 @@ trait NumObject { * @return */ def toBigDecimal(value: BigInt, binaryPoint: Int): BigDecimal = { - if(value.bitLength > 108) { + if(value.bitLength > MaxBitsBigIntToBigDecimal) { throw new ChiselException( s"BigInt $value with bitlength ${value.bitLength} is too big, precision lost with > $MaxBitsBigIntToBigDecimal bits" ) -- cgit v1.2.3 From 160e019e38c933112836cccbb38c5f397427cf7f Mon Sep 17 00:00:00 2001 From: Leway Colin Date: Sat, 25 Jan 2020 09:16:43 +0800 Subject: Remove redundancy code (#1296) * Remove redundancy code * Remove blank line * BitPat supports whitespace and underscores, presumably for human readability. The BitPat.parse factory though did not remove these from the returned count. This fixes that adds whitespace and underscores to the unit tests This is an updated vesion of Chisel PR #1069 Co-authored-by: Chick Markley Co-authored-by: Jim Lawson Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- chiselFrontend/src/main/scala/chisel3/RawModule.scala | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'chiselFrontend') diff --git a/chiselFrontend/src/main/scala/chisel3/RawModule.scala b/chiselFrontend/src/main/scala/chisel3/RawModule.scala index 4155ef4a..2b184a50 100644 --- a/chiselFrontend/src/main/scala/chisel3/RawModule.scala +++ b/chiselFrontend/src/main/scala/chisel3/RawModule.scala @@ -184,17 +184,6 @@ package internal { // Allow access to bindings from the compatibility package protected def _compatIoPortBound() = portsContains(io)// scalastyle:ignore method.name - protected override def nameIds(rootClass: Class[_]): HashMap[HasId, String] = { - val names = super.nameIds(rootClass) - - // Allow IO naming without reflection - names.put(io, "io") - names.put(clock, "clock") - names.put(reset, "reset") - - names - } - private[chisel3] override def namePorts(names: HashMap[HasId, String]): Unit = { for (port <- getModulePorts) { // This should already have been caught -- cgit v1.2.3 From f1c4395bd608234fef5a60d8851036d1acb2382f Mon Sep 17 00:00:00 2001 From: Leway Colin Date: Sat, 25 Jan 2020 09:42:59 +0800 Subject: Fixed code example typo in comment (#1294) Co-authored-by: Jim Lawson Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- chiselFrontend/src/main/scala/chisel3/Aggregate.scala | 6 +++--- chiselFrontend/src/main/scala/chisel3/Reg.scala | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'chiselFrontend') diff --git a/chiselFrontend/src/main/scala/chisel3/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/Aggregate.scala index 8141fdba..84e959a5 100644 --- a/chiselFrontend/src/main/scala/chisel3/Aggregate.scala +++ b/chiselFrontend/src/main/scala/chisel3/Aggregate.scala @@ -121,7 +121,7 @@ trait VecFactory extends SourceInfoDoc { * {{{ * val io = IO(new Bundle { * val in = Input(Vec(20, UInt(16.W))) - * val addr = UInt(5.W) + * val addr = Input(UInt(5.W)) * val out = Output(UInt(16.W)) * }) * io.out := io.in(io.addr) @@ -696,8 +696,8 @@ package experimental { * val outPacket = Output(new Packet) * }) * val reg = Reg(new Packet) - * reg <> inPacket - * outPacket <> reg + * reg <> io.inPacket + * io.outPacket <> reg * } * }}} */ diff --git a/chiselFrontend/src/main/scala/chisel3/Reg.scala b/chiselFrontend/src/main/scala/chisel3/Reg.scala index 51c59bdb..a3e6b2a0 100644 --- a/chiselFrontend/src/main/scala/chisel3/Reg.scala +++ b/chiselFrontend/src/main/scala/chisel3/Reg.scala @@ -108,13 +108,13 @@ object RegNext { * val x = Wire(UInt()) * val y = Wire(UInt(8.W)) * val r1 = RegInit(x) // width will be inferred - * val r2 = RegInit(y) // width will be inferred + * val r2 = RegInit(y) // width is set to 8 * }}} * * 3. [[Aggregate]] initializer - width will be set to match the aggregate * * {{{ - * class MyBundle { + * class MyBundle extends Bundle { * val unknown = UInt() * val known = UInt(8.W) * } -- cgit v1.2.3