summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/core/Data.scala
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/core/Data.scala')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala306
1 files changed, 159 insertions, 147 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
index 580dabe0..41e09a5b 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
@@ -8,16 +8,65 @@ import chisel3.internal._
import chisel3.internal.Builder.{pushCommand, pushOp}
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo._
-import chisel3.internal.firrtl.PrimOp.AsUIntOp
-sealed abstract class Direction(name: String) {
- override def toString: String = name
- def flip: Direction
+/** User-specified directions.
+ */
+sealed abstract class UserDirection
+object UserDirection {
+ /** Default user direction, also meaning 'not-flipped'
+ */
+ case object Unspecified extends UserDirection
+ /** Node and its children are forced as output
+ */
+ case object Output extends UserDirection
+ /** Node and ites children are forced as inputs
+ */
+ case object Input extends UserDirection
+ /** Mainly for containers, children are flipped.
+ */
+ case object Flip extends UserDirection
+
+ def flip(dir: UserDirection) = dir match {
+ case Unspecified => Flip
+ case Flip => Unspecified
+ case Output => Input
+ case Input => Output
+ }
+
+ /** Returns the effective UserDirection of this node given the parent's effective UserDirection
+ * and the user-specified UserDirection of this node.
+ */
+ def fromParent(parentDirection: UserDirection, thisDirection: UserDirection) =
+ (parentDirection, thisDirection) match {
+ case (UserDirection.Output, _) => UserDirection.Output
+ case (UserDirection.Input, _) => UserDirection.Input
+ case (UserDirection.Unspecified, thisDirection) => thisDirection
+ case (UserDirection.Flip, thisDirection) => UserDirection.flip(thisDirection)
+ }
}
-object Direction {
- object Input extends Direction("input") { override def flip: Direction = Output }
- object Output extends Direction("output") { override def flip: Direction = Input }
- object Unspecified extends Direction("unspecified") { override def flip: Direction = Input }
+
+/** 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 {
+ /** 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
}
@deprecated("debug doesn't do anything in Chisel3 as no pruning happens in the frontend", "chisel3")
@@ -25,8 +74,17 @@ object debug { // scalastyle:ignore object.name
def apply (arg: Data): Data = arg
}
+/** Experimental hardware construction reflection API
+ */
object DataMirror {
def widthOf(target: Data): Width = target.width
+ def userDirectionOf(target: Data): UserDirection = target.userDirection
+ def directionOf(target: Data): ActualDirection = {
+ requireIsHardware(target, "node requested directionality on")
+ target.direction
+ }
+ // TODO: really not a reflection-style API, but a workaround for dir in the compatibility package
+ def isSynthesizable(target: Data) = target.hasBinding
}
/** Creates a clone of the super-type of the input elements. Super-type is defined as:
@@ -87,88 +145,24 @@ private[core] object cloneSupertype {
* 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 = {
- val target = source.chiselCloneType
- Data.setFirrtlDirection(target, Direction.Input)
- Binding.bind(target, InputBinder, "Error: Cannot set as input ")
+ def apply[T<:Data](source: T): T = {
+ val out = source.cloneType
+ out.userDirection = UserDirection.Input
+ out
}
}
object Output {
- def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = {
- val target = source.chiselCloneType
- Data.setFirrtlDirection(target, Direction.Output)
- Binding.bind(target, OutputBinder, "Error: Cannot set as output ")
+ def apply[T<:Data](source: T): T = {
+ val out = source.cloneType
+ out.userDirection = UserDirection.Output
+ out
}
}
object Flipped {
- def apply[T<:Data](source: T)(implicit compileOptions: CompileOptions): T = {
- val target = source.chiselCloneType
- Data.setFirrtlDirection(target, Data.getFirrtlDirection(source).flip)
- Binding.bind(target, FlippedBinder, "Error: Cannot flip ")
- }
-}
-
-object Data {
- /**
- * This function returns true if the FIRRTL type of this Data should be flipped
- * relative to other nodes.
- *
- * Note that the current scheme only applies Flip to Elements or Vec chains of
- * Elements.
- *
- * A Record is never marked flip, instead preferring its root fields to be marked
- *
- * The Vec check is due to the fact that flip must be factored out of the vec, ie:
- * must have flip field: Vec(UInt) instead of field: Vec(flip UInt)
- */
- private[chisel3] def isFlipped(target: Data): Boolean = target match {
- case (element: Element) => element.binding.direction == Some(Direction.Input)
- case (vec: Vec[Data @unchecked]) => isFlipped(vec.sample_element)
- case (record: Record) => false
- }
-
- /** This function returns the "firrtl" flipped-ness for the specified object.
- *
- * @param target the object for which we want the "firrtl" flipped-ness.
- */
- private[chisel3] def isFirrtlFlipped(target: Data): Boolean = {
- Data.getFirrtlDirection(target) == Direction.Input
- }
-
- /** This function gets the "firrtl" direction for the specified object.
- *
- * @param target the object for which we want to get the "firrtl" direction.
- */
- private[chisel3] def getFirrtlDirection(target: Data): Direction = target match {
- case (vec: Vec[Data @unchecked]) => vec.sample_element.firrtlDirection
- case _ => target.firrtlDirection
- }
-
- /** This function sets the "firrtl" direction for the specified object.
- *
- * @param target the object for which we want to set the "firrtl" direction.
- */
- private[chisel3] def setFirrtlDirection(target: Data, direction: Direction): Unit = target match {
- case (vec: Vec[Data @unchecked]) => vec.sample_element.firrtlDirection = direction
- case _ => target.firrtlDirection = direction
- }
-
- implicit class AddDirectionToData[T<:Data](val target: T) extends AnyVal {
- def asInput(implicit opts: CompileOptions): T = {
- if (opts.deprecateOldDirectionMethods)
- Builder.deprecated("Input(Data) should be used over Data.asInput")
- Input(target)
- }
- def asOutput(implicit opts: CompileOptions): T = {
- if (opts.deprecateOldDirectionMethods)
- Builder.deprecated("Output(Data) should be used over Data.asOutput")
- Output(target)
- }
- def flip()(implicit opts: CompileOptions): T = {
- if (opts.deprecateOldDirectionMethods)
- Builder.deprecated("Flipped(Data) should be used over Data.flip")
- Flipped(target)
- }
+ def apply[T<:Data](source: T): T = {
+ val out = source.cloneType
+ out.userDirection = UserDirection.flip(source.userDirection)
+ out
}
}
@@ -188,6 +182,76 @@ abstract class Data extends HasId {
}
}
+ // User-specified direction, local at this node only.
+ // Note that the actual direction of this node can differ from child and parent userDirection.
+ private var _userDirection: UserDirection = UserDirection.Unspecified
+ private[chisel3] def userDirection: UserDirection = _userDirection
+ private[core] def userDirection_=(direction: UserDirection) = {
+ if (_userDirection != UserDirection.Unspecified) {
+ this match {
+ // Anything flies in compatibility mode
+ case t: Record if !t.compileOptions.dontAssumeDirectionality =>
+ case _ => throw Binding.RebindingException(s"Attempted reassignment of user direction to $this")
+ }
+ }
+ _userDirection = direction
+ }
+
+ /** This overwrites a relative UserDirection 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[core] def _assignCompatibilityExplicitDirection: Unit = {
+ _userDirection match {
+ case UserDirection.Unspecified => _userDirection = UserDirection.Output
+ case UserDirection.Flip => _userDirection = UserDirection.Input
+ case UserDirection.Input | UserDirection.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
+ private[core] def hasBinding = _binding.isDefined
+ // Only valid after node is bound (synthesizable), crashes otherwise
+ private[core] def binding = _binding.get
+ protected def binding_=(target: Binding) {
+ if (_binding.isDefined) {
+ throw Binding.RebindingException(s"Attempted reassignment of binding to $this")
+ }
+ _binding = Some(target)
+ }
+
+ private[core] def topBinding: TopBinding = {
+ binding match {
+ case ChildBinding(parent) => parent.topBinding
+ case topBinding: TopBinding => topBinding
+ }
+ }
+
+ /** 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: UserDirection = UserDirection.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[core] def direction_=(actualDirection: ActualDirection) {
+ if (_direction.isDefined) {
+ throw Binding.RebindingException(s"Attempted reassignment of resolved direction to $this")
+ }
+ _direction = Some(actualDirection)
+ }
+
// 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
@@ -197,8 +261,8 @@ abstract class Data extends HasId {
throwException(s"cannot connect ${this} and ${that}")
private[chisel3] def connect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = {
if (connectCompileOptions.checkSynthesizable) {
- Binding.checkSynthesizable(this, s"'this' ($this)")
- Binding.checkSynthesizable(that, s"'that' ($that)")
+ requireIsHardware(this, "data to be connected")
+ requireIsHardware(that, "data to be connected")
try {
MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule)
} catch {
@@ -213,8 +277,8 @@ abstract class Data extends HasId {
}
private[chisel3] def bulkConnect(that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = {
if (connectCompileOptions.checkSynthesizable) {
- Binding.checkSynthesizable(this, s"'this' ($this)")
- Binding.checkSynthesizable(that, s"'that' ($that)")
+ requireIsHardware(this, s"data to be bulk-connected")
+ requireIsHardware(that, s"data to be bulk-connected")
try {
BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.forcedUserModule)
} catch {
@@ -235,8 +299,7 @@ abstract class Data extends HasId {
private[chisel3] def lref: Node = Node(this)
private[chisel3] def ref: Arg = if (isLit) litArg.get else lref
- private[chisel3] def toType: String
- private[core] def width: Width
+ private[chisel3] def width: Width
private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit
/** cloneType must be defined for any Chisel object extending Data.
@@ -252,21 +315,10 @@ abstract class Data extends HasId {
* then performs any fixups required to reconstruct the appropriate core state of the cloned object.
* @return a copy of the object with appropriate core state.
*/
- def chiselCloneType(implicit compileOptions: CompileOptions): this.type = {
- // TODO: refactor away allElements, handle this with Aggregate/Element match inside Bindings
-
- // Call the user-supplied cloneType method
- val clone = this.cloneType
- // In compatibility mode, simply return cloneType; otherwise, propagate
- // direction and flippedness.
- if (compileOptions.checkSynthesizable) {
- Data.setFirrtlDirection(clone, Data.getFirrtlDirection(this))
- //TODO(twigg): Do recursively for better error messages
- for((clone_elem, source_elem) <- clone.allElements zip this.allElements) {
- clone_elem.binding = UnboundBinding(source_elem.binding.direction)
- Data.setFirrtlDirection(clone_elem, Data.getFirrtlDirection(source_elem))
- }
- }
+ def chiselCloneType: this.type = {
+ val clone = this.cloneType // get a fresh object, without bindings
+ // Only the top-level direction needs to be fixed up, cloneType should do the rest
+ clone.userDirection = userDirection
clone
}
final def := (that: Data)(implicit sourceInfo: SourceInfo, connectionCompileOptions: CompileOptions): Unit = this.connect(that)(sourceInfo, connectionCompileOptions)
@@ -322,11 +374,6 @@ abstract class Data extends HasId {
def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt
- // firrtlDirection is the direction we report to firrtl.
- // It maintains the user-specified value (as opposed to the "actual" or applied/propagated value).
- // NOTE: This should only be used for emitting acceptable firrtl.
- // The Element.dir should be used for any tests involving direction.
- private var firrtlDirection: Direction = Direction.Unspecified
/** Default pretty printing */
def toPrintable: Printable
}
@@ -349,7 +396,7 @@ object Wire {
def apply[T <: Data](t: T, init: T)(implicit compileOptions: CompileOptions): T = {
implicit val noSourceInfo = UnlocatableSourceInfo
val x = apply(t)
- Binding.checkSynthesizable(init, s"'init' ($init)")
+ requireIsHardware(init, "wire initializer")
x := init
x
}
@@ -358,7 +405,7 @@ object Wire {
val x = t.chiselCloneType
// Bind each element of x to being a Wire
- Binding.bind(x, WireBinder(Builder.forcedUserModule), "Error: t")
+ x.bind(WireBinding(Builder.forcedUserModule))
pushCommand(DefWire(sourceInfo, x))
pushCommand(DefInvalid(sourceInfo, x.ref))
@@ -366,38 +413,3 @@ object Wire {
x
}
}
-
-object Clock {
- def apply(): Clock = new Clock
- def apply(dir: Direction)(implicit compileOptions: CompileOptions): Clock = {
- val result = apply()
- dir match {
- case Direction.Input => Input(result)
- case Direction.Output => Output(result)
- case Direction.Unspecified => result
- }
- }
-}
-
-// TODO: Document this.
-sealed class Clock extends Element(Width(1)) {
- def cloneType: this.type = Clock().asInstanceOf[this.type]
- private[chisel3] def toType = "Clock"
-
- private[core] def typeEquivalent(that: Data): Boolean =
- this.getClass == that.getClass
-
- override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match {
- case _: Clock => super.connect(that)(sourceInfo, connectCompileOptions)
- case _ => super.badConnect(that)(sourceInfo)
- }
-
- /** Not really supported */
- def toPrintable: Printable = PString("CLOCK")
-
- override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
- private[core] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): Unit = {
- this := that
- }
-}