diff options
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/Data.scala')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/Data.scala | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/Data.scala b/chiselFrontend/src/main/scala/chisel3/Data.scala new file mode 100644 index 00000000..7534c01a --- /dev/null +++ b/chiselFrontend/src/main/scala/chisel3/Data.scala @@ -0,0 +1,761 @@ +// See LICENSE for license details. + +package chisel3 + +import scala.language.experimental.macros + +import chisel3.experimental.{Analog, DataMirror, FixedPoint} +import chisel3.internal.Builder.pushCommand +import chisel3.internal._ +import chisel3.internal.firrtl._ +import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, UnlocatableSourceInfo, DeprecatedSourceInfo} + +/** User-specified directions. + */ +sealed abstract class SpecifiedDirection +object SpecifiedDirection { + /** Default user direction, also meaning 'not-flipped' + */ + case object Unspecified extends SpecifiedDirection + /** Node and its children are forced as output + */ + case object Output extends SpecifiedDirection + /** Node and its children are forced as inputs + */ + case object Input extends SpecifiedDirection + /** Mainly for containers, children are flipped. + */ + case object Flip extends SpecifiedDirection + + def flip(dir: SpecifiedDirection): SpecifiedDirection = dir match { + case Unspecified => Flip + case Flip => Unspecified + case Output => Input + case Input => Output + } + + /** Returns the effective SpecifiedDirection of this node given the parent's effective SpecifiedDirection + * and the user-specified SpecifiedDirection of this node. + */ + def fromParent(parentDirection: SpecifiedDirection, thisDirection: SpecifiedDirection): SpecifiedDirection = + (parentDirection, thisDirection) match { + case (SpecifiedDirection.Output, _) => SpecifiedDirection.Output + case (SpecifiedDirection.Input, _) => SpecifiedDirection.Input + case (SpecifiedDirection.Unspecified, thisDirection) => thisDirection + case (SpecifiedDirection.Flip, thisDirection) => SpecifiedDirection.flip(thisDirection) + } +} + +/** Resolved directions for both leaf and container nodes, only visible after + * a node is bound (since higher-level specifications like Input and Output + * can override directions). + */ +sealed abstract class ActualDirection + +object ActualDirection { + /** The object does not exist / is empty and hence has no direction + */ + case object Empty extends ActualDirection + + /** Undirectioned, struct-like + */ + case object Unspecified extends ActualDirection + /** Output element, or container with all outputs (even if forced) + */ + case object Output extends ActualDirection + /** Input element, or container with all inputs (even if forced) + */ + case object Input extends ActualDirection + + sealed abstract class BidirectionalDirection + case object Default extends BidirectionalDirection + case object Flipped extends BidirectionalDirection + + case class Bidirectional(dir: BidirectionalDirection) extends ActualDirection + + def fromSpecified(direction: SpecifiedDirection): ActualDirection = direction match { + case SpecifiedDirection.Unspecified | SpecifiedDirection.Flip => ActualDirection.Unspecified + case SpecifiedDirection.Output => ActualDirection.Output + case SpecifiedDirection.Input => ActualDirection.Input + } + + /** Determine the actual binding of a container given directions of its children. + * Returns None in the case of mixed specified / unspecified directionality. + */ + def fromChildren(childDirections: Set[ActualDirection], containerDirection: SpecifiedDirection): + Option[ActualDirection] = { + if (childDirections == Set()) { // Sadly, Scala can't do set matching + ActualDirection.fromSpecified(containerDirection) match { + case ActualDirection.Unspecified => Some(ActualDirection.Empty) // empty direction if relative / no direction + case dir => Some(dir) // use assigned direction if specified + } + } else if (childDirections == Set(ActualDirection.Unspecified)) { + Some(ActualDirection.Unspecified) + } else if (childDirections == Set(ActualDirection.Input)) { + Some(ActualDirection.Input) + } else if (childDirections == Set(ActualDirection.Output)) { + Some(ActualDirection.Output) + } else if (childDirections subsetOf + Set(ActualDirection.Output, ActualDirection.Input, + ActualDirection.Bidirectional(ActualDirection.Default), + ActualDirection.Bidirectional(ActualDirection.Flipped))) { + containerDirection match { + case SpecifiedDirection.Unspecified => Some(ActualDirection.Bidirectional(ActualDirection.Default)) + case SpecifiedDirection.Flip => Some(ActualDirection.Bidirectional(ActualDirection.Flipped)) + case _ => throw new RuntimeException("Unexpected forced Input / Output") + } + } else { + None + } + } +} + +object debug { // scalastyle:ignore object.name + @chiselRuntimeDeprecated + @deprecated("debug doesn't do anything in Chisel3 as no pruning happens in the frontend", "chisel3") + def apply (arg: Data): Data = arg +} + +package experimental { + + /** Experimental hardware construction reflection API + */ + object DataMirror { + def widthOf(target: Data): Width = target.width + def specifiedDirectionOf(target: Data): SpecifiedDirection = target.specifiedDirection + def directionOf(target: Data): ActualDirection = { + requireIsHardware(target, "node requested directionality on") + target.direction + } + + // Returns the top-level module ports + // TODO: maybe move to something like Driver or DriverUtils, since this is mainly for interacting + // with compiled artifacts (vs. elaboration-time reflection)? + def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts + + // Returns all module ports with underscore-qualified names + def fullModulePorts(target: BaseModule): Seq[(String, Data)] = { + def getPortNames(name: String, data: Data): Seq[(String, Data)] = Seq(name -> data) ++ (data match { + case _: Element => Seq() + case r: Record => r.elements.toSeq flatMap { case (eltName, elt) => getPortNames(s"${name}_${eltName}", elt) } + case v: Vec[_] => v.zipWithIndex flatMap { case (elt, index) => getPortNames(s"${name}_${index}", elt) } + }) + modulePorts(target).flatMap { case (name, data) => + getPortNames(name, data).toList + } + } + + // Internal reflection-style APIs, subject to change and removal whenever. + object internal { // scalastyle:ignore object.name + def isSynthesizable(target: Data): Boolean = target.isSynthesizable + // For those odd cases where you need to care about object reference and uniqueness + def chiselTypeClone[T<:Data](target: Data): T = { + target.cloneTypeFull.asInstanceOf[T] + } + } + } +} + +/** Creates a clone of the super-type of the input elements. Super-type is defined as: + * - for Bits type of the same class: the cloned type of the largest width + * - Bools are treated as UInts + * - For other types of the same class are are the same: clone of any of the elements + * - Otherwise: fail + */ +//scalastyle:off cyclomatic.complexity +private[chisel3] object cloneSupertype { + def apply[T <: Data](elts: Seq[T], createdType: String)(implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions): T = { + require(!elts.isEmpty, s"can't create $createdType with no inputs") + + val filteredElts = elts.filter(_ != DontCare) + require(!filteredElts.isEmpty, s"can't create $createdType with only DontCare inputs") + + if (filteredElts.head.isInstanceOf[Bits]) { + val model: T = filteredElts reduce { (elt1: T, elt2: T) => ((elt1, elt2) match { + case (elt1: Bool, elt2: Bool) => elt1 + case (elt1: Bool, elt2: UInt) => elt2 // TODO: what happens with zero width UInts? + case (elt1: UInt, elt2: Bool) => elt1 // TODO: what happens with zero width UInts? + case (elt1: UInt, elt2: UInt) => + // TODO: perhaps redefine Widths to allow >= op? + if (elt1.width == (elt1.width max elt2.width)) elt1 else elt2 + case (elt1: SInt, elt2: SInt) => if (elt1.width == (elt1.width max elt2.width)) elt1 else elt2 + case (elt1: FixedPoint, elt2: FixedPoint) => { + (elt1.binaryPoint, elt2.binaryPoint, elt1.width, elt2.width) match { + case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), KnownWidth(w1), KnownWidth(w2)) => + val maxBinaryPoint = bp1 max bp2 + val maxIntegerWidth = (w1 - bp1) max (w2 - bp2) + FixedPoint((maxIntegerWidth + maxBinaryPoint).W, (maxBinaryPoint).BP) + case (KnownBinaryPoint(bp1), KnownBinaryPoint(bp2), _, _) => + FixedPoint(Width(), (bp1 max bp2).BP) + case _ => FixedPoint() + } + } + case (elt1, elt2) => + throw new AssertionError( + s"can't create $createdType with heterogeneous types ${elt1.getClass} and ${elt2.getClass}") + }).asInstanceOf[T] } + model.cloneTypeFull + } + else { + for (elt <- filteredElts.tail) { + require(elt.getClass == filteredElts.head.getClass, + s"can't create $createdType with heterogeneous types ${filteredElts.head.getClass} and ${elt.getClass}") + require(elt typeEquivalent filteredElts.head, + s"can't create $createdType with non-equivalent types ${filteredElts.head} and ${elt}") + } + filteredElts.head.cloneTypeFull + } + } +} + +/** Returns the chisel type of a hardware object, allowing other hardware to be constructed from it. + */ +object chiselTypeOf { + def apply[T <: Data](target: T): T = { + requireIsHardware(target) + target.cloneTypeFull.asInstanceOf[T] + } +} + +/** +* Input, Output, and Flipped are used to define the directions of Module IOs. +* +* Note that they currently clone their source argument, including its bindings. +* +* Thus, an error will be thrown if these are used on bound Data +*/ +object Input { + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] + out.specifiedDirection = SpecifiedDirection.Input + out + } +} +object Output { + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] + out.specifiedDirection = SpecifiedDirection.Output + out + } +} +object Flipped { + def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = { + if (compileOptions.checkSynthesizable) { + requireIsChiselType(source) + } + val out = source.cloneType.asInstanceOf[T] + out.specifiedDirection = SpecifiedDirection.flip(source.specifiedDirection) + out + } +} + +/** This forms the root of the type system for wire data types. The data value + * must be representable as some number (need not be known at Chisel compile + * time) of bits, and must have methods to pack / unpack structured data to / + * from bits. + * + * @groupdesc Connect Utilities for connecting hardware components + * @define coll data + */ +abstract class Data extends HasId with NamedComponent with SourceInfoDoc { // scalastyle:ignore number.of.methods + // This is a bad API that punches through object boundaries. + @deprecated("pending removal once all instances replaced", "chisel3") + private[chisel3] def flatten: IndexedSeq[Element] = { + this match { + case elt: Aggregate => elt.getElements.toIndexedSeq flatMap {_.flatten} + case elt: Element => IndexedSeq(elt) + case elt => throwException(s"Cannot flatten type ${elt.getClass}") + } + } + + // User-specified direction, local at this node only. + // Note that the actual direction of this node can differ from child and parent specifiedDirection. + private var _specifiedDirection: SpecifiedDirection = SpecifiedDirection.Unspecified + private[chisel3] def specifiedDirection: SpecifiedDirection = _specifiedDirection + private[chisel3] def specifiedDirection_=(direction: SpecifiedDirection) = { + if (_specifiedDirection != SpecifiedDirection.Unspecified) { + this match { + // Anything flies in compatibility mode + case t: Record if !t.compileOptions.dontAssumeDirectionality => + case _ => throw RebindingException(s"Attempted reassignment of user-specified direction to $this") + } + } + _specifiedDirection = direction + } + + /** This overwrites a relative SpecifiedDirection with an explicit one, and is used to implement + * the compatibility layer where, at the elements, Flip is Input and unspecified is Output. + * DO NOT USE OUTSIDE THIS PURPOSE. THIS OPERATION IS DANGEROUS! + */ + private[chisel3] def _assignCompatibilityExplicitDirection: Unit = { // scalastyle:off method.name + (this, _specifiedDirection) match { + case (_: Analog, _) => // nothing to do + case (_, SpecifiedDirection.Unspecified) => _specifiedDirection = SpecifiedDirection.Output + case (_, SpecifiedDirection.Flip) => _specifiedDirection = SpecifiedDirection.Input + case (_, SpecifiedDirection.Input | SpecifiedDirection.Output) => // nothing to do + } + } + + // Binding stores information about this node's position in the hardware graph. + // This information is supplemental (more than is necessary to generate FIRRTL) and is used to + // perform checks in Chisel, where more informative error messages are possible. + private var _binding: Option[Binding] = None + // Only valid after node is bound (synthesizable), crashes otherwise + protected[chisel3] def binding: Option[Binding] = _binding + protected def binding_=(target: Binding) { + if (_binding.isDefined) { + throw RebindingException(s"Attempted reassignment of binding to $this") + } + _binding = Some(target) + } + + // Similar to topBindingOpt except it explicitly excludes SampleElements which are bound but not + // hardware + private[chisel3] final def isSynthesizable: Boolean = _binding.map { + case ChildBinding(parent) => parent.isSynthesizable + case _: TopBinding => true + case _: SampleElementBinding[_] => false + }.getOrElse(false) + + private[chisel3] def topBindingOpt: Option[TopBinding] = _binding.flatMap { + case ChildBinding(parent) => parent.topBindingOpt + case bindingVal: TopBinding => Some(bindingVal) + case SampleElementBinding(parent) => parent.topBindingOpt + } + + private[chisel3] def topBinding: TopBinding = topBindingOpt.get + + /** Binds this node to the hardware graph. + * parentDirection is the direction of the parent node, or Unspecified (default) if the target + * node is the top-level. + * binding and direction are valid after this call completes. + */ + private[chisel3] def bind(target: Binding, parentDirection: SpecifiedDirection = SpecifiedDirection.Unspecified) + + // Both _direction and _resolvedUserDirection are saved versions of computed variables (for + // efficiency, avoid expensive recomputation of frequent operations). + // Both are only valid after binding is set. + + // Direction of this node, accounting for parents (force Input / Output) and children. + private var _direction: Option[ActualDirection] = None + + private[chisel3] def direction: ActualDirection = _direction.get + private[chisel3] def direction_=(actualDirection: ActualDirection) { + if (_direction.isDefined) { + throw RebindingException(s"Attempted reassignment of resolved direction to $this") + } + _direction = Some(actualDirection) + } + + // User-friendly representation of the binding as a helper function for toString. + // Provides a unhelpful fallback for literals, which should have custom rendering per + // Data-subtype. + // TODO Is this okay for sample_element? It *shouldn't* be visible to users + protected def bindingToString: String = topBindingOpt match { + case None => "" + case Some(OpBinding(enclosure)) => s"(OpResult in ${enclosure.desiredName})" + case Some(MemoryPortBinding(enclosure)) => s"(MemPort in ${enclosure.desiredName})" + case Some(PortBinding(enclosure)) if !enclosure.isClosed => s"(IO in unelaborated ${enclosure.desiredName})" + case Some(PortBinding(enclosure)) if enclosure.isClosed => + DataMirror.fullModulePorts(enclosure).find(_._2 eq this) match { + case Some((name, _)) => s"(IO $name in ${enclosure.desiredName})" + case None => s"(IO (unknown) in ${enclosure.desiredName})" + } + case Some(RegBinding(enclosure)) => s"(Reg in ${enclosure.desiredName})" + case Some(WireBinding(enclosure)) => s"(Wire in ${enclosure.desiredName})" + case Some(DontCareBinding()) => s"(DontCare)" + case Some(ElementLitBinding(litArg)) => s"(unhandled literal)" + case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)" + } + + // Return ALL elements at root of this type. + // Contasts with flatten, which returns just Bits + // TODO: refactor away this, this is outside the scope of Data + private[chisel3] def allElements: Seq[Element] + + private[chisel3] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = + throwException(s"cannot connect ${this} and ${that}") + private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit + if (connectCompileOptions.checkSynthesizable) { + requireIsHardware(this, "data to be connected") + requireIsHardware(that, "data to be connected") + this.topBinding match { + case _: ReadOnlyBinding => throwException(s"Cannot reassign to read-only $this") + case _ => // fine + } + try { + MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule) + } catch { + case MonoConnectException(message) => + throwException( + s"Connection between sink ($this) and source ($that) failed @$message" + ) + } + } else { + this legacyConnect that + } + } + private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit + if (connectCompileOptions.checkSynthesizable) { + requireIsHardware(this, s"data to be bulk-connected") + requireIsHardware(that, s"data to be bulk-connected") + (this.topBinding, that.topBinding) match { + case (_: ReadOnlyBinding, _: ReadOnlyBinding) => throwException(s"Both $this and $that are read-only") + // DontCare cannot be a sink (LHS) + case (_: DontCareBinding, _) => throw BiConnect.DontCareCantBeSink + case _ => // fine + } + try { + BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule) + } catch { + case BiConnectException(message) => + throwException( + s"Connection between left ($this) and source ($that) failed @$message" + ) + } + } else { + this legacyConnect that + } + } + + /** Whether this Data has the same model ("data type") as that Data. + * Data subtypes should overload this with checks against their own type. + */ + private[chisel3] def typeEquivalent(that: Data): Boolean + + // Internal API: returns a ref that can be assigned to, if consistent with the binding + private[chisel3] def lref: Node = { + requireIsHardware(this) + topBindingOpt match { + case Some(binding: ReadOnlyBinding) => throwException(s"internal error: attempted to generate LHS ref to ReadOnlyBinding $binding") // scalastyle:ignore line.size.limit + case Some(binding: TopBinding) => Node(this) + case opt => throwException(s"internal error: unknown binding $opt in generating LHS ref") + } + } + + + // Internal API: returns a ref, if bound. Literals should override this as needed. + private[chisel3] def ref: Arg = { + requireIsHardware(this) + topBindingOpt match { + case Some(binding: LitBinding) => throwException(s"internal error: can't handle literal binding $binding") + case Some(binding: TopBinding) => Node(this) + case opt => throwException(s"internal error: unknown binding $opt in generating LHS ref") + } + } + + private[chisel3] def width: Width + private[chisel3] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit + + /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...). + * + * cloneType must be defined for any Chisel object extending Data. + * It is responsible for constructing a basic copy of the object being cloned. + * + * @return a copy of the object. + */ + def cloneType: this.type + + /** Internal API; Chisel users should look at chisel3.chiselTypeOf(...). + * + * Returns a copy of this data type, with hardware bindings (if any) removed. + * Directionality data is still preserved. + */ + private[chisel3] def cloneTypeFull: this.type = { + val clone = this.cloneType.asInstanceOf[this.type] // get a fresh object, without bindings + // Only the top-level direction needs to be fixed up, cloneType should do the rest + clone.specifiedDirection = specifiedDirection + clone + } + + /** Connect this $coll to that $coll mono-directionally and element-wise. + * + * This uses the [[MonoConnect]] algorithm. + * + * @param that the $coll to connect to + * @group Connect + */ + final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit + + /** Connect this $coll to that $coll bi-directionally and element-wise. + * + * This uses the [[BiConnect]] algorithm. + * + * @param that the $coll to connect to + * @group Connect + */ + final def <> (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.bulkConnect(that)(sourceInfo, connectionCompileOptions) // scalastyle:ignore line.size.limit + + @chiselRuntimeDeprecated + @deprecated("litArg is deprecated, use litOption or litTo*Option", "chisel3.2") + def litArg(): Option[LitArg] = topBindingOpt match { + case Some(ElementLitBinding(litArg)) => Some(litArg) + case Some(BundleLitBinding(litMap)) => None // this API does not support Bundle literals + case _ => None + } + + def isLit(): Boolean = litArg.isDefined + + /** + * If this is a literal that is representable as bits, returns the value as a BigInt. + * If not a literal, or not representable as bits (for example, is or contains Analog), returns None. + */ + def litOption(): Option[BigInt] + + /** + * Returns the literal value if this is a literal that is representable as bits, otherwise crashes. + */ + def litValue(): BigInt = litOption.get + + /** Returns the width, in bits, if currently known. */ + final def getWidth: Int = + if (isWidthKnown) width.get else throwException(s"Width of $this is unknown!") + /** Returns whether the width is currently known. */ + final def isWidthKnown: Boolean = width.known + /** Returns Some(width) if the width is known, else None. */ + final def widthOption: Option[Int] = if (isWidthKnown) Some(getWidth) else None + + /** Packs the value of this object as plain Bits. + * + * This performs the inverse operation of fromBits(Bits). + */ + @chiselRuntimeDeprecated + @deprecated("Best alternative, .asUInt()", "chisel3") + def toBits(implicit compileOptions: CompileOptions): UInt = do_asUInt(DeprecatedSourceInfo, compileOptions) + + /** Does a reinterpret cast of the bits in this node into the format that provides. + * Returns a new Wire of that type. Does not modify existing nodes. + * + * x.asTypeOf(that) performs the inverse operation of x := that.toBits. + * + * @note bit widths are NOT checked, may pad or drop bits from input + * @note that should have known widths + */ + def asTypeOf[T <: Data](that: T): T = macro SourceInfoTransform.thatArg + + /** @group SourceInfoTransformMacro */ + def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + val thatCloned = Wire(that.cloneTypeFull) + thatCloned.connectFromBits(this.asUInt()) + thatCloned + } + + /** Assigns this node from Bits type. Internal implementation for asTypeOf. + */ + private[chisel3] def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, + compileOptions: CompileOptions): Unit + + /** Reinterpret cast to UInt. + * + * @note value not guaranteed to be preserved: for example, a SInt of width + * 3 and value -1 (0b111) would become an UInt with value 7 + * @note Aggregates are recursively packed with the first element appearing + * in the least-significant bits of the result. + */ + final def asUInt(): UInt = macro SourceInfoTransform.noArg + + /** @group SourceInfoTransformMacro */ + def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt + + /** Default pretty printing */ + def toPrintable: Printable +} + +trait WireFactory { + /** Construct a [[Wire]] from a type template + * @param t The template from which to construct this wire + */ + def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + if (compileOptions.declaredTypeMustBeUnbound) { + requireIsChiselType(t, "wire type") + } + val x = t.cloneTypeFull + + // Bind each element of x to being a Wire + x.bind(WireBinding(Builder.forcedUserModule)) + + pushCommand(DefWire(sourceInfo, x)) + if (!compileOptions.explicitInvalidate) { + pushCommand(DefInvalid(sourceInfo, x.ref)) + } + + x + } +} + +/** Utility for constructing hardware wires + * + * The width of a `Wire` (inferred or not) is copied from the type template + * {{{ + * val w0 = Wire(UInt()) // width is inferred + * val w1 = Wire(UInt(8.W)) // width is set to 8 + * + * val w2 = Wire(Vec(4, UInt())) // width is inferred + * val w3 = Wire(Vec(4, UInt(8.W))) // width of each element is set to 8 + * + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val w4 = Wire(new MyBundle) + * // Width of w4.unknown is inferred + * // Width of w4.known is set to 8 + * }}} + * + */ +object Wire extends WireFactory { + + @chiselRuntimeDeprecated + @deprecated("Wire(init=init) is deprecated, use WireDefault(init) instead", "chisel3") + def apply[T <: Data](dummy: Int = 0, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = + WireDefault(init) + + @chiselRuntimeDeprecated + @deprecated("Wire(t, init) is deprecated, use WireDefault(t, init) instead", "chisel3") + def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = + WireDefault(t, init) + + @chiselRuntimeDeprecated + @deprecated("Wire(t, init) is deprecated, use WireDefault(t, init) instead", "chisel3") + def apply[T <: Data](t: T, init: DontCare.type)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = + WireDefault(t, init) +} + +/** Utility for constructing hardware wires with a default connection + * + * The two forms of `WireDefault` differ in how the type and width of the resulting [[Wire]] are + * specified. + * + * ==Single Argument== + * The single argument form uses the argument to specify both the type and default connection. For + * non-literal [[Bits]], the width of the [[Wire]] will be inferred. For literal [[Bits]] and all + * non-Bits arguments, the type will be copied from the argument. See the following examples for + * more details: + * + * 1. Literal [[Bits]] initializer: width will be set to match + * {{{ + * val w1 = WireDefault(1.U) // width will be inferred to be 1 + * val w2 = WireDefault(1.U(8.W)) // width is set to 8 + * }}} + * + * 2. Non-Literal [[Element]] initializer - width will be inferred + * {{{ + * val x = Wire(UInt()) + * val y = Wire(UInt(8.W)) + * val w1 = WireDefault(x) // width will be inferred + * val w2 = WireDefault(y) // width will be inferred + * }}} + * + * 3. [[Aggregate]] initializer - width will be set to match the aggregate + * + * {{{ + * class MyBundle { + * val unknown = UInt() + * val known = UInt(8.W) + * } + * val w1 = Wire(new MyBundle) + * val w2 = WireDefault(w1) + * // Width of w2.unknown is inferred + * // Width of w2.known is set to 8 + * }}} + * + * ==Double Argument== + * The double argument form allows the type of the [[Wire]] and the default connection to be + * specified independently. + * + * The width inference semantics for `WireDefault` with two arguments match those of [[Wire]]. The + * first argument to `WireDefault` is the type template which defines the width of the `Wire` in + * exactly the same way as the only argument to [[Wire]]. + * + * More explicitly, you can reason about `WireDefault` with multiple arguments as if it were defined + * as: + * {{{ + * def WireDefault[T <: Data](t: T, init: T): T = { + * val x = Wire(t) + * x := init + * x + * } + * }}} + * + * @note The `Default` in `WireDefault` refers to a `default` connection. This is in contrast to + * [[RegInit]] where the `Init` refers to a value on reset. + */ +object WireDefault { + + private def applyImpl[T <: Data](t: T, init: Data)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { // scalastyle:ignore line.size.limit + implicit val noSourceInfo = UnlocatableSourceInfo + val x = Wire(t) + requireIsHardware(init, "wire initializer") + x := init + x + } + + /** Construct a [[Wire]] with a type template and a [[chisel3.DontCare]] default + * @param t The type template used to construct this [[Wire]] + * @param init The default connection to this [[Wire]], can only be [[DontCare]] + * @note This is really just a specialized form of `apply[T <: Data](t: T, init: T): T` with [[DontCare]] as `init` + */ + def apply[T <: Data](t: T, init: DontCare.type)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { // scalastyle:ignore line.size.limit + applyImpl(t, init) + } + + /** Construct a [[Wire]] with a type template and a default connection + * @param t The type template used to construct this [[Wire]] + * @param init The hardware value that will serve as the default value + */ + def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + applyImpl(t, init) + } + + /** Construct a [[Wire]] with a default connection + * @param init The hardware value that will serve as a type template and default value + */ + def apply[T <: Data](init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = { + val model = (init match { + // If init is a literal without forced width OR any non-literal, let width be inferred + case init: Bits if !init.litIsForcedWidth.getOrElse(false) => init.cloneTypeWidth(Width()) + case _ => init.cloneTypeFull + }).asInstanceOf[T] + apply(model, init) + } +} + +package internal { + /** RHS (source) for Invalidate API. + * Causes connection logic to emit a DefInvalid when connected to an output port (or wire). + */ + private[chisel3] object InternalDontCare extends Element { + // This object should be initialized before we execute any user code that refers to it, + // otherwise this "Chisel" object will end up on the UserModule's id list. + // We make it private to chisel3 so it has to be accessed through the package object. + + private[chisel3] override val width: Width = UnknownWidth() + + bind(DontCareBinding(), SpecifiedDirection.Output) + override def cloneType: this.type = DontCare + + override def toString: String = "DontCare()" + + override def litOption: Option[BigInt] = None + + def toPrintable: Printable = PString("DONTCARE") + + private[chisel3] def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = { // scalastyle:ignore line.size.limit + Builder.error("connectFromBits: DontCare cannot be a connection sink (LHS)") + } + + def do_asUInt(implicit sourceInfo: chisel3.internal.sourceinfo.SourceInfo, compileOptions: CompileOptions): UInt = { // scalastyle:ignore line.size.limit + Builder.error("DontCare does not have a UInt representation") + 0.U + } + // DontCare's only match themselves. + private[chisel3] def typeEquivalent(that: Data): Boolean = that == DontCare + } +} |
