// SPDX-License-Identifier: Apache-2.0 package chisel3 import chisel3.internal.ChiselException import chisel3.internal.firrtl.{BinaryPoint, KnownBinaryPoint} import scala.language.experimental.macros import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform} // REVIEW TODO: Further discussion needed on what Num actually is. /** Abstract trait defining operations available on numeric-like hardware data types. * * @tparam T the underlying type of the number * @groupdesc Arithmetic Arithmetic hardware operators * @groupdesc Comparison Comparison hardware operators * @groupdesc Logical Logical hardware operators * @define coll numeric-like type * @define numType hardware type * @define canHaveHighCost can result in significant cycle time and area costs * @define canGenerateA This method generates a * @define singleCycleMul @note $canGenerateA fully combinational multiplier which $canHaveHighCost. * @define singleCycleDiv @note $canGenerateA fully combinational divider which $canHaveHighCost. * @define maxWidth @note The width of the returned $numType is `max(width of this, width of that)`. * @define maxWidthPlusOne @note The width of the returned $numType is `max(width of this, width of that) + 1`. * @define sumWidth @note The width of the returned $numType is `width of this` + `width of that`. * @define unchangedWidth @note The width of the returned $numType is unchanged, i.e., the `width of this`. */ trait Num[T <: Data] { self: Num[T] => // def << (b: T): T // def >> (b: T): T //def unary_-(): T // REVIEW TODO: double check ops conventions against FIRRTL /** Addition operator * * @param that a $numType * @return the sum of this $coll and `that` * $maxWidth * @group Arithmetic */ final def +(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_+(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Multiplication operator * * @param that a $numType * @return the product of this $coll and `that` * $sumWidth * $singleCycleMul * @group Arithmetic */ final def *(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_*(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Division operator * * @param that a $numType * @return the quotient of this $coll divided by `that` * $singleCycleDiv * @todo full rules * @group Arithmetic */ final def /(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_/(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Modulo operator * * @param that a $numType * @return the remainder of this $coll divided by `that` * $singleCycleDiv * @group Arithmetic */ final def %(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_%(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Subtraction operator * * @param that a $numType * @return the difference of this $coll less `that` * $maxWidthPlusOne * @group Arithmetic */ final def -(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_-(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Less than operator * * @param that a $numType * @return a hardware [[Bool]] asserted if this $coll is less than `that` * @group Comparison */ final def <(that: T): Bool = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_<(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool /** Less than or equal to operator * * @param that a $numType * @return a hardware [[Bool]] asserted if this $coll is less than or equal to `that` * @group Comparison */ final def <=(that: T): Bool = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_<=(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool /** Greater than operator * * @param that a hardware component * @return a hardware [[Bool]] asserted if this $coll is greater than `that` * @group Comparison */ final def >(that: T): Bool = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_>(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool /** Greater than or equal to operator * * @param that a hardware component * @return a hardware [[Bool]] asserted if this $coll is greather than or equal to `that` * @group Comparison */ final def >=(that: T): Bool = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_>=(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool /** Absolute value operator * * @return a $numType with a value equal to the absolute value of this $coll * $unchangedWidth * @group Arithmetic */ final def abs: T = macro SourceInfoTransform.noArg @deprecated( "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5" ) final def abs(dummy: Int*): T = macro SourceInfoTransform.noArgDummy /** @group SourceInfoTransformMacro */ def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T /** Minimum operator * * @param that a hardware $coll * @return a $numType with a value equal to the minimum value of this $coll and `that` * $maxWidth * @group Arithmetic */ final def min(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ def do_min(that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = Mux(this < that, this.asInstanceOf[T], that) /** Maximum operator * * @param that a $numType * @return a $numType with a value equal to the minimum value of this $coll and `that` * $maxWidth * @group Arithmetic */ final def max(that: T): T = macro SourceInfoTransform.thatArg /** @group SourceInfoTransformMacro */ 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 > MaxBitsBigIntToBigDecimal) { 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") } } }