diff options
| author | Richard Lin | 2017-06-26 18:35:46 -0700 |
|---|---|---|
| committer | GitHub | 2017-06-26 18:35:46 -0700 |
| commit | aaee58d374dc3f3a088856da13a6a59ecffb2cac (patch) | |
| tree | 790828de9a9fbb1dfd26635eebaf27668a4cc8df /chiselFrontend/src/main/scala/chisel3/core/Bits.scala | |
| parent | 91850ec917a432e9e3db588e7711c8a82801eb49 (diff) | |
Directions internals mega-refactor (#617)
Part 1 of mega-change in #578
Major notes:
- Input(...) and Output(...) now (effectively) recursively override their elements' directions
- Nodes given userDirection (Input, Output, Flip - what the user assigned to _that_ node) and actualDirection (Input, Output, None, but also Bidirectional and BidirectionalFlip for mostly Aggregates), because of the above (since a higher-level Input(...) can override the locally specified user direction).
- DataMirror (node reflection APIs) added to chisel3.experimental. This provides ways to query the user given direction of a node as well as the actual direction.
- checkSynthesizable replaced with requireIsHardware and requireIsChiselType and made available in chisel3.experimental.
Internal changes notes:
- toType moved into Emitter, this makes the implementation cleaner especially considering that Vec types can't be flipped in FIRRTL. This also more clearly separates Chisel frontend from FIRRTL emission.
- Direction separated from Bindings, both are now fields in Data, and all nodes are given hierarchical directions (Aggregates may be Bidirectional). The actualDirection at the Element (leaf) level should be the same as binding directions previously.
- Bindings are hierarchical, children (of a, for example, Bundle) have a ChildBinding that points to their parent. This is different than the previous scheme where Bindings only applied at the Element (leaf) level.
- Lots of small misc clean up.
Future PRs will address other parts of #578, including stricter direction checks that aren't a side-effect of this internal refactor, stricter checks and splitting of binding operations (Wire vs. WireInit), and node operations not introduced here (getType and deprecation of chiselCloneType). Since those shouldn't mess with internals, those should be much smaller.
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/core/Bits.scala')
| -rw-r--r-- | chiselFrontend/src/main/scala/chisel3/core/Bits.scala | 82 |
1 files changed, 39 insertions, 43 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala index 7de7be09..7f660188 100644 --- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala +++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala @@ -17,26 +17,16 @@ import chisel3.internal.firrtl.PrimOp._ /** Element is a leaf data type: it cannot contain other Data objects. Example * uses are for representing primitive data types, like integers and bits. */ -abstract class Element(private[core] val width: Width) extends Data { - /** - * Elements can actually be bound to the hardware graph and thus must store - * that binding information. - */ - private[this] var _binding: Binding = UnboundBinding(None) - // Define setter/getter pairing - // Can only bind something that has not yet been bound. - private[core] def binding_=(target: Binding): Unit = _binding match { - case UnboundBinding(_) => { - _binding = target - _binding +abstract class Element(private[chisel3] val width: Width) extends Data { + private[chisel3] override def bind(target: Binding, parentDirection: UserDirection) { + binding = target + val resolvedDirection = UserDirection.fromParent(parentDirection, userDirection) + direction = resolvedDirection match { + case UserDirection.Unspecified | UserDirection.Flip => ActualDirection.Unspecified + case UserDirection.Output => ActualDirection.Output + case UserDirection.Input => ActualDirection.Input } - case _ => throw Binding.AlreadyBoundException(_binding.toString) - // Other checks should have caught this. } - private[core] def binding = _binding - - /** Return the binding for some bits. */ - def dir: Direction = binding.direction.getOrElse(Direction.Unspecified) private[chisel3] final def allElements: Seq[Element] = Seq(this) def widthKnown: Boolean = width.known @@ -95,7 +85,8 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) if (isLit()) { (((litValue() >> x.toInt) & 1) == 1).asBool } else { - Binding.checkSynthesizable(this, s"'this' ($this)") + + requireIsHardware(this, "bits to be indexed") pushOp(DefPrim(sourceInfo, Bool(), BitsExtractOp, this.ref, ILit(x), ILit(x))) } } @@ -138,7 +129,7 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) if (isLit()) { ((litValue >> y) & ((BigInt(1) << w) - 1)).asUInt(w.W) } else { - Binding.checkSynthesizable(this, s"'this' ($this)") + requireIsHardware(this, "bits to be sliced") pushOp(DefPrim(sourceInfo, UInt(Width(w)), BitsExtractOp, this.ref, ILit(x), ILit(y))) } } @@ -150,25 +141,25 @@ sealed abstract class Bits(width: Width, override val litArg: Option[LitArg]) apply(x.toInt, y.toInt) private[core] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = { - Binding.checkSynthesizable(this, s"'this' ($this)") + requireIsHardware(this, "bits operated on") pushOp(DefPrim(sourceInfo, dest, op, this.ref)) } private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: BigInt): T = { - Binding.checkSynthesizable(this, s"'this' ($this)") + requireIsHardware(this, "bits operated on") pushOp(DefPrim(sourceInfo, dest, op, this.ref, ILit(other))) } private[core] def binop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp, other: Bits): T = { - Binding.checkSynthesizable(this, s"'this' ($this)") - Binding.checkSynthesizable(other, s"'other' ($other)") + requireIsHardware(this, "bits operated on") + requireIsHardware(other, "bits operated on") pushOp(DefPrim(sourceInfo, dest, op, this.ref, other.ref)) } private[core] def compop(sourceInfo: SourceInfo, op: PrimOp, other: Bits): Bool = { - Binding.checkSynthesizable(this, s"'this' ($this)") - Binding.checkSynthesizable(other, s"'other' ($other)") + requireIsHardware(this, "bits operated on") + requireIsHardware(other, "bits operated on") pushOp(DefPrim(sourceInfo, Bool(), op, this.ref, other.ref)) } private[core] def redop(sourceInfo: SourceInfo, op: PrimOp): Bool = { - Binding.checkSynthesizable(this, s"'this' ($this)") + requireIsHardware(this, "bits operated on") pushOp(DefPrim(sourceInfo, Bool(), op, this.ref)) } @@ -404,7 +395,6 @@ sealed class UInt private[core] (width: Width, lit: Option[ULit] = None) private[core] override def cloneTypeWidth(w: Width): this.type = new UInt(w).asInstanceOf[this.type] - private[chisel3] def toType = s"UInt$width" // TODO: refactor to share documentation with Num or add independent scaladoc final def unary_- (): UInt = macro SourceInfoTransform.noArg @@ -547,7 +537,7 @@ trait UIntFactory { val lit = ULit(value, width) val result = new UInt(lit.width, Some(lit)) // Bind result to being an Literal - result.binding = LitBinding() + result.bind(LitBinding()) result } @@ -572,7 +562,6 @@ sealed class SInt private[core] (width: Width, lit: Option[SLit] = None) private[core] override def cloneTypeWidth(w: Width): this.type = new SInt(w).asInstanceOf[this.type] - private[chisel3] def toType = s"SInt$width" final def unary_- (): SInt = macro SourceInfoTransform.noArg final def unary_-% (): SInt = macro SourceInfoTransform.noArg @@ -703,7 +692,7 @@ trait SIntFactory { val lit = SLit(value, width) val result = new SInt(lit.width, Some(lit)) // Bind result to being an Literal - result.binding = LitBinding() + result.bind(LitBinding()) result } } @@ -765,7 +754,7 @@ trait BoolFactory { protected[chisel3] def Lit(x: Boolean): Bool = { val result = new Bool(Some(ULit(if (x) 1 else 0, Width(1)))) // Bind result to being an Literal - result.binding = LitBinding() + result.bind(LitBinding()) result } } @@ -794,7 +783,6 @@ sealed class FixedPoint private (width: Width, val binaryPoint: BinaryPoint, lit private[core] override def cloneTypeWidth(w: Width): this.type = new FixedPoint(w, binaryPoint).asInstanceOf[this.type] - private[chisel3] def toType = s"Fixed$width$binaryPoint" override def connect (that: Data)(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): Unit = that match { case _: FixedPoint => super.connect(that) @@ -946,9 +934,6 @@ object FixedPoint { /** Create an FixedPoint type or port with fixed width. */ def apply(width: Width, binaryPoint: BinaryPoint): FixedPoint = new FixedPoint(width, binaryPoint) - /** Create an FixedPoint port with inferred width. */ - def apply(dir: Direction): FixedPoint = apply(dir, Width(), BinaryPoint()) - /** Create an FixedPoint literal with inferred width from BigInt. * Use PrivateObject to force users to specify width and binaryPoint by name */ @@ -991,11 +976,10 @@ object FixedPoint { } /** Create an FixedPoint port with specified width and binary position. */ - def apply(dir: Direction, width: Width, binaryPoint: BinaryPoint): FixedPoint = new FixedPoint(width, binaryPoint) def apply(value: BigInt, width: Width, binaryPoint: BinaryPoint): FixedPoint = { val lit = FPLit(value, width, binaryPoint) val newLiteral = new FixedPoint(lit.width, lit.binaryPoint, Some(lit)) - newLiteral.binding = LitBinding() + newLiteral.bind(LitBinding()) newLiteral } @@ -1043,8 +1027,6 @@ object FixedPoint { final class Analog private (width: Width) extends Element(width) { require(width.known, "Since Analog is only for use in BlackBoxes, width must be known") - private[chisel3] def toType = s"Analog$width" - private[core] override def typeEquivalent(that: Data): Boolean = that.isInstanceOf[Analog] && this.width == that.width @@ -1057,9 +1039,23 @@ final class Analog private (width: Width) extends Element(width) { // Define setter/getter pairing // Analog can only be bound to Ports and Wires (and Unbound) - private[core] override def binding_=(target: Binding): Unit = target match { - case (_: UnboundBinding | _: WireBinding | PortBinding(_, None)) => super.binding_=(target) - case _ => throwException("Only Wires and Ports can be of type Analog") + private[chisel3] override def bind(target: Binding, parentDirection: UserDirection) { + UserDirection.fromParent(parentDirection, userDirection) match { + case UserDirection.Unspecified | UserDirection.Flip => + case x => throwException(s"Analog may not have explicit direction, got '$x'") + } + val targetTopBinding = target match { + case target: TopBinding => target + case ChildBinding(parent) => parent.topBinding + } + + // Analog counts as different directions based on binding context + targetTopBinding match { + case WireBinding(_) => direction = ActualDirection.Unspecified // internal wire + case PortBinding(_) => direction = ActualDirection.Bidirectional(ActualDirection.Default) + case x => throwException(s"Analog can only be Ports and Wires, not '$x'") + } + binding = target } override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = |
