// SPDX-License-Identifier: Apache-2.0 import chisel3.internal.firrtl.BinaryPoint import java.util.{MissingFormatArgumentException, UnknownFormatConversionException} import scala.collection.mutable /** This package contains the main chisel3 API. */ package object chisel3 { import internal.chiselRuntimeDeprecated import internal.sourceinfo.DeprecatedSourceInfo import internal.firrtl.{Port, Width} import internal.Builder import scala.language.implicitConversions type ChiselEnum = experimental.ChiselEnum type EnumType = experimental.EnumType val suppressEnumCastWarning = experimental.suppressEnumCastWarning /** * These implicit classes allow one to convert [[scala.Int]] or [[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 { 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) /** Int to SInt conversion with specified width, recommended style for constants. */ def S(width: Width): SInt = SInt.Lit(bigint, width) /** Int to UInt conversion, recommended style for variables. */ def asUInt: UInt = UInt.Lit(bigint, Width()) @deprecated( "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5" ) def asUInt(dummy: Int*): UInt = asUInt /** Int to SInt conversion, recommended style for variables. */ def asSInt: SInt = SInt.Lit(bigint, Width()) @deprecated( "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5" ) def asSInt(dummy: Int*): SInt = asSInt /** 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 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 /** String to UInt parse with specified width, recommended style for constants. */ def U(width: Width): UInt = str.asUInt(width) /** String to UInt parse, recommended style for variables. */ def asUInt: UInt = { val bigInt = parse(str) UInt.Lit(bigInt, Width(bigInt.bitLength.max(1))) } @deprecated( "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5" ) def asUInt(dummy: Int*): UInt = asUInt /** 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) } } implicit class fromIntToBinaryPoint(int: Int) { def BP: BinaryPoint = BinaryPoint(int) } implicit class fromBooleanToLiteral(boolean: Boolean) { /** Boolean to Bool conversion, recommended style for constants. */ def B: Bool = Bool.Lit(boolean) /** Boolean to Bool conversion, recommended style for variables. */ def asBool: Bool = Bool.Lit(boolean) @deprecated( "Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5" ) def asBool(dummy: Int*): Bool = asBool } // Fixed Point is experimental for now, but we alias the implicit conversion classes here // to minimize disruption with existing code. implicit class fromDoubleToLiteral(double: Double) extends experimental.FixedPoint.Implicits.fromDoubleToLiteral(double) implicit class fromBigDecimalToLiteral(bigDecimal: BigDecimal) extends experimental.FixedPoint.Implicits.fromBigDecimalToLiteral(bigDecimal) // Interval is experimental for now, but we alias the implicit conversion classes here // to minimize disruption with existing code. implicit class fromIntToLiteralInterval(int: Int) extends experimental.Interval.Implicits.fromIntToLiteralInterval(int) implicit class fromLongToLiteralInterval(long: Long) extends experimental.Interval.Implicits.fromLongToLiteralInterval(long) implicit class fromBigIntToLiteralInterval(bigInt: BigInt) extends experimental.Interval.Implicits.fromBigIntToLiteralInterval(bigInt) implicit class fromDoubleToLiteralInterval(double: Double) extends experimental.Interval.Implicits.fromDoubleToLiteralInterval(double) implicit class fromBigDecimalToLiteralInterval(bigDecimal: BigDecimal) extends experimental.Interval.Implicits.fromBigDecimalToLiteralInterval(bigDecimal) implicit class fromIntToWidth(int: Int) { def W: Width = Width(int) } val WireInit = WireDefault object Vec extends VecFactory // Some possible regex replacements for the literal specifier deprecation: // (note: these are not guaranteed to handle all edge cases! check all replacements!) // Bool\((true|false)\) // => $1.B // UInt\(width\s*=\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\) // => UInt($1.W) // (UInt|SInt|Bits).width\((\d+|[_a-zA-Z][_0-9a-zA-Z]*)\) // => $1($2.W) // (U|S)Int\((-?\d+|0[xX][0-9a-fA-F]+)\) // => $2.$1 // UInt\((\d+|0[xX][0-9a-fA-F]+),\s*(?:width\s*=)?\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\) // => $1.U($2.W) // (UInt|SInt|Bool)\(([_a-zA-Z][_0-9a-zA-Z]*)\) // => $2.as$1 // (UInt|SInt)\(([_a-zA-Z][_0-9a-zA-Z]*),\s*(?:width\s*=)?\s*(\d+|[_a-zA-Z][_0-9a-zA-Z]*)\) // => $2.as$1($3.W) object Bits extends UIntFactory object UInt extends UIntFactory object SInt extends SIntFactory object Bool extends BoolFactory type InstanceId = internal.InstanceId @deprecated("MultiIOModule is now just Module", "Chisel 3.5") type MultiIOModule = chisel3.Module /** Implicit for custom Printable string interpolator */ implicit class PrintableHelper(val sc: StringContext) extends AnyVal { /** Custom string interpolator for generating Printables: p"..." * mimicks s"..." for non-Printable data) */ def p(args: Any*): Printable = { // P interpolator does not treat % differently - hence need to add % before sending to cf. val t = sc.parts.map(_.replaceAll("%", "%%")) StringContext(t: _*).cf(args: _*) } /** Custom string interpolator for generating formatted Printables : cf"..." * * Enhanced version of scala's `f` interpolator. * Each expression (argument) referenced within the string is * converted to a particular Printable depending * on the format specifier and type. * * ==== For Chisel types referenced within the String ==== * * - %n - Returns [[Name]] Printable. * - %N - Returns [[FullName]] Printable. * - %b,%d,%x,%c - Only applicable for types of [[Bits]] or dreived from it. - returns ([[Binary]],[[Decimal]], * [[Hexadecimal]],[[Character]]) Printable respectively. * - Default - If no specifier given call [[Data.toPrintable]] on the Chisel Type. * * ==== For [[Printable]] type: ==== * No explicit format specifier supported - just return the Printable. * * ==== For regular scala types ==== * Call String.format with the argument and specifier. * Default is %s if no specifier is given. * Wrap the result in [[PString]] Printable. * * ==== For the parts of the StringContext ==== * Remove format specifiers and if literal percents (need to be escaped with %) * are present convert them into [[Percent]] Printable. * Rest of the string will be wrapped in [[PString]] Printable. * * @example * {{{ * * val w1 = 20.U // Chisel UInt type (which extends Bits) * val f1 = 30.2 // Scala float type. * val pable = cf"w1 = $w1%x f1 = $f1%2.2f. This is 100%% clear" * * // pable is as follows * // Printables(List(PString(w1 = ), Hexadecimal(UInt<5>(20)), PString( f1 = ), PString(30.20), PString(. This is 100), Percent, PString( clear))) * }}} * * @throws UnknownFormatConversionException * if literal percent not escaped with % or if the format specifier is not supported * for the specific type * * @throws StringContext.InvalidEscapeException * if a `parts` string contains a backslash (`\`) character * that does not start a valid escape sequence. * * @throws IllegalArgumentException * if the number of `parts` in the enclosing `StringContext` does not exceed * the number of arguments `arg` by exactly 1. */ def cf(args: Any*): Printable = { // Handle literal % // Takes the part string - // - this is assumed to not have any format specifiers - already handled / removed before calling this function. // Only thing present is literal % if any which should ideally be with %%. // If not - then flag an error. // Return seq of Printables (either PString or Percent or both - nothing else def percentSplitter(s: String): Seq[Printable] = { if (s.isEmpty) Seq(PString("")) else { val pieces = s.split("%%").toList.flatMap { p => if (p.contains('%')) throw new UnknownFormatConversionException("Un-escaped % found") // Wrap in PString and intersperse the escaped percentages Seq(Percent, PString(p)) } if (pieces.isEmpty) Seq(Percent) else pieces.tail // Don't forget to drop the extra percent we put at the beginning } } def extractFormatSpecifier(part: String): (Option[String], String) = { // Check if part starts with a format specifier (with % - disambiguate with literal % checking the next character if needed to be %) // In the case of %f specifier there is a chance that we need more information - so capture till the 1st letter (a-zA-Z). // Example cf"This is $val%2.2f here" - parts - Seq("This is ","%2.2f here") - the format specifier here is %2.2f. val endFmtIdx = if (part.length > 1 && part(0) == '%' && part(1) != '%') part.indexWhere(_.isLetter) else -1 val (fmt, rest) = part.splitAt(endFmtIdx + 1) val fmtOpt = if (fmt.nonEmpty) Some(fmt) else None (fmtOpt, rest) } sc.checkLengths(args) // Enforce sc.parts.size == pargs.size + 1 val parts = sc.parts.map(StringContext.treatEscapes) // The 1st part is assumed never to contain a format specifier. // If the 1st part of a string is an argument - then the 1st part will be an empty String. // So we need to parse parts following the 1st one to get the format specifiers if any val partsAfterFirst = parts.tail // Align parts to their potential specifiers val pables = partsAfterFirst.zip(args).flatMap { case (part, arg) => { val (fmt, modP) = extractFormatSpecifier(part) val fmtArg: Printable = arg match { case d: Data => { fmt match { case Some("%n") => Name(d) case Some("%N") => FullName(d) case Some(fForm) if d.isInstanceOf[Bits] => FirrtlFormat(fForm.substring(1, 2), d) case Some(x) => { val msg = s"Illegal format specifier '$x' for Chisel Data type!\n" throw new UnknownFormatConversionException(msg) } case None => d.toPrintable } } case p: Printable => { fmt match { case Some(x) => { val msg = s"Illegal format specifier '$x' for Chisel Printable type!\n" throw new UnknownFormatConversionException(msg) } case None => p } } // Generic case - use String.format (for example %d,%2.2f etc on regular Scala types) case t => PString(fmt.getOrElse("%s").format(t)) } Seq(fmtArg) ++ percentSplitter(modP) } } Printables(percentSplitter(parts.head) ++ pables) } } implicit def string2Printable(str: String): Printable = PString(str) type ChiselException = internal.ChiselException // Debugger/Tester access to internal Chisel data structures and methods. def getDataElements(a: Aggregate): Seq[Element] = { a.allElements } @deprecated( "duplicated with DataMirror.fullModulePorts, this returns an internal API, will be removed in Chisel 3.6", "Chisel 3.5" ) def getModulePorts(m: Module): Seq[Port] = m.getPorts class BindingException(message: String) extends ChiselException(message) /** A function expected a Chisel type but got a hardware object */ case class ExpectedChiselTypeException(message: String) extends BindingException(message) /** A function expected a hardware object but got a Chisel type */ case class ExpectedHardwareException(message: String) extends BindingException(message) /** An aggregate had a mix of specified and unspecified directionality children */ case class MixedDirectionAggregateException(message: String) extends BindingException(message) /** Attempted to re-bind an already bound (directionality or hardware) object */ case class RebindingException(message: String) extends BindingException(message) // Connection exceptions. case class BiConnectException(message: String) extends ChiselException(message) case class MonoConnectException(message: String) extends ChiselException(message) }