summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala111
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala91
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binder.scala64
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binding.scala239
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Bits.scala82
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala20
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Clock.scala34
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala8
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala306
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Mem.scala9
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Module.scala28
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala43
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Mux.scala8
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Reg.scala12
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/UserModule.scala18
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Builder.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala2
18 files changed, 487 insertions, 594 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index 3f81de9f..701cf892 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -15,11 +15,58 @@ import chisel3.internal.sourceinfo._
* of) other Data objects.
*/
sealed abstract class Aggregate extends Data {
+ private[chisel3] override def bind(target: Binding, parentDirection: UserDirection) {
+ binding = target
+
+ val resolvedDirection = UserDirection.fromParent(parentDirection, userDirection)
+ for (child <- getElements) {
+ child.bind(ChildBinding(this), resolvedDirection)
+ }
+
+ // Check that children obey the directionality rules.
+ val childDirections = getElements.map(_.direction).toSet
+ direction = if (childDirections == Set()) { // Sadly, Scala can't do set matching
+ // If empty, use my assigned direction
+ resolvedDirection match {
+ case UserDirection.Unspecified | UserDirection.Flip => ActualDirection.Unspecified
+ case UserDirection.Output => ActualDirection.Output
+ case UserDirection.Input => ActualDirection.Input
+ }
+ } else if (childDirections == Set(ActualDirection.Unspecified)) {
+ ActualDirection.Unspecified
+ } else if (childDirections == Set(ActualDirection.Input)) {
+ ActualDirection.Input
+ } else if (childDirections == Set(ActualDirection.Output)) {
+ ActualDirection.Output
+ } else if (childDirections subsetOf
+ Set(ActualDirection.Output, ActualDirection.Input,
+ ActualDirection.Bidirectional(ActualDirection.Default),
+ ActualDirection.Bidirectional(ActualDirection.Flipped))) {
+ resolvedDirection match {
+ case UserDirection.Unspecified => ActualDirection.Bidirectional(ActualDirection.Default)
+ case UserDirection.Flip => ActualDirection.Bidirectional(ActualDirection.Flipped)
+ case _ => throw new RuntimeException("Unexpected forced Input / Output")
+ }
+ } else {
+ this match {
+ // Anything flies in compatibility mode
+ case t: Record if !t.compileOptions.dontAssumeDirectionality => resolvedDirection match {
+ case UserDirection.Unspecified => ActualDirection.Bidirectional(ActualDirection.Default)
+ case UserDirection.Flip => ActualDirection.Bidirectional(ActualDirection.Flipped)
+ case _ => ActualDirection.Bidirectional(ActualDirection.Default)
+ }
+ case _ =>
+ val childWithDirections = getElements zip getElements.map(_.direction)
+ throw Binding.MixedDirectionAggregateException(s"Aggregate '$this' can't have elements that are both directioned and undirectioned: $childWithDirections")
+ }
+ }
+ }
+
/** Returns a Seq of the immediate contents of this Aggregate, in order.
*/
def getElements: Seq[Data]
- private[core] def width: Width = getElements.map(_.width).foldLeft(0.W)(_ + _)
+ private[chisel3] def width: Width = getElements.map(_.width).foldLeft(0.W)(_ + _)
private[core] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
pushCommand(BulkConnect(sourceInfo, this.lref, that.lref))
@@ -68,25 +115,21 @@ object Vec {
// Check that types are homogeneous. Width mismatch for Elements is safe.
require(!elts.isEmpty)
+ elts.foreach(requireIsHardware(_, "vec element"))
val vec = Wire(new Vec(cloneSupertype(elts, "Vec"), elts.length))
- def doConnect(sink: T, source: T) = {
- // TODO: this looks bad, and should feel bad. Replace with a better abstraction.
- // NOTE: Must use elts.head instead of vec.sample_element because vec.sample_element has
- // WireBinding which does not have a direction
- val hasDirectioned = elts.head match {
- case t: Aggregate => t.flatten.exists(_.dir != Direction.Unspecified)
- case t: Element => t.dir != Direction.Unspecified
- }
- if (hasDirectioned) {
- sink bulkConnect source
- } else {
- sink connect source
- }
- }
- for ((v, e) <- vec zip elts) {
- doConnect(v, e)
+ // TODO: try to remove the logic for this mess
+ elts.head.direction match {
+ case ActualDirection.Input | ActualDirection.Output | ActualDirection.Unspecified =>
+ // When internal wires are involved, driver / sink must be specified explicitly, otherwise
+ // the system is unable to infer which is driver / sink
+ (vec zip elts).foreach(x => x._1 := x._2)
+ case ActualDirection.Bidirectional(_) =>
+ // For bidirectional, must issue a bulk connect so subelements are resolved correctly.
+ // Bulk connecting two wires may not succeed because Chisel frontend does not infer
+ // directions.
+ (vec zip elts).foreach(x => x._1 <> x._2)
}
vec
}
@@ -186,7 +229,7 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
*
* Needed specifically for the case when the Vec is length 0.
*/
- private[core] val sample_element: T = gen
+ private[chisel3] val sample_element: T = gen
// allElements current includes sample_element
// This is somewhat weird although I think the best course of action here is
@@ -226,16 +269,25 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
override def apply(p: UInt): T = macro CompileOptionsTransform.pArg
def do_apply(p: UInt)(implicit compileOptions: CompileOptions): T = {
- Binding.checkSynthesizable(p ,s"'p' ($p)")
+ requireIsHardware(p, "vec index")
val port = gen
- val i = Vec.truncateIndex(p, length)(UnlocatableSourceInfo, compileOptions)
- port.setRef(this, i)
- // Bind each element of port to being whatever the base type is
- // Using the head element as the sample_element
- for((port_elem, model_elem) <- port.allElements zip sample_element.allElements) {
- port_elem.binding = model_elem.binding
+ // Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored.
+ // It may not be exactly equal to that value, but the results are the same.
+ val reconstructedResolvedDirection = direction match {
+ case ActualDirection.Input => UserDirection.Input
+ case ActualDirection.Output => UserDirection.Output
+ case ActualDirection.Bidirectional(ActualDirection.Default) | ActualDirection.Unspecified =>
+ UserDirection.Unspecified
+ case ActualDirection.Bidirectional(ActualDirection.Flipped) => UserDirection.Flip
}
+ // TODO port technically isn't directly child of this data structure, but the result of some
+ // muxes / demuxes. However, this does make access consistent with the top-level bindings.
+ // Perhaps there's a cleaner way of accomplishing this...
+ port.bind(ChildBinding(this), reconstructedResolvedDirection)
+
+ val i = Vec.truncateIndex(p, length)(UnlocatableSourceInfo, compileOptions)
+ port.setRef(this, i)
port
}
@@ -256,7 +308,6 @@ sealed class Vec[T <: Data] private (gen: => T, val length: Int)
new Vec(gen.cloneType, length).asInstanceOf[this.type]
}
- private[chisel3] def toType: String = s"${sample_element.toType}[$length]"
override def getElements: Seq[Data] =
(0 until length).map(apply(_))
@@ -384,14 +435,6 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
/** Name for Pretty Printing */
def className: String = this.getClass.getSimpleName
- private[chisel3] def toType = {
- def eltPort(elt: Data): String = {
- val flipStr: String = if(Data.isFirrtlFlipped(elt)) "flip " else ""
- s"${flipStr}${elt.getRef.name} : ${elt.toType}"
- }
- elements.toIndexedSeq.reverse.map(e => eltPort(e._2)).mkString("{", ", ", "}")
- }
-
private[core] override def typeEquivalent(that: Data): Boolean = that match {
case that: Record =>
this.getClass == that.getClass &&
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
index 0e5d4e8b..f2b2b7e1 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BiConnect.scala
@@ -138,15 +138,14 @@ object BiConnect {
// This function checks if element-level connection operation allowed.
// Then it either issues it or throws the appropriate exception.
def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, left: Element, right: Element, context_mod: UserModule): Unit = {
- import Direction.{Input, Output} // Using extensively so import these
+ import BindingDirection.{Internal, Input, Output} // Using extensively so import these
// If left or right have no location, assume in context module
// This can occur if one of them is a literal, unbound will error previously
- val left_mod: BaseModule = left.binding.location.getOrElse(context_mod)
- val right_mod: BaseModule = right.binding.location.getOrElse(context_mod)
+ val left_mod: BaseModule = left.topBinding.location.getOrElse(context_mod)
+ val right_mod: BaseModule = right.topBinding.location.getOrElse(context_mod)
- val left_direction: Option[Direction] = left.binding.direction
- val right_direction: Option[Direction] = right.binding.direction
- // None means internal
+ val left_direction = BindingDirection.from(left.topBinding, left.direction)
+ val right_direction = BindingDirection.from(right.topBinding, right.direction)
// CASE: Context is same module as left node and right node is in a child module
if( (left_mod == context_mod) &&
@@ -154,15 +153,15 @@ object BiConnect {
// Thus, right node better be a port node and thus have a direction hint
((left_direction, right_direction): @unchecked) match {
// CURRENT MOD CHILD MOD
- case (Some(Input), Some(Input)) => issueConnectL2R(left, right)
- case (None, Some(Input)) => issueConnectL2R(left, right)
+ case (Input, Input) => issueConnectL2R(left, right)
+ case (Internal, Input) => issueConnectL2R(left, right)
- case (Some(Output), Some(Output)) => issueConnectR2L(left, right)
- case (None, Some(Output)) => issueConnectR2L(left, right)
+ case (Output, Output) => issueConnectR2L(left, right)
+ case (Internal, Output) => issueConnectR2L(left, right)
- case (Some(Input), Some(Output)) => throw BothDriversException
- case (Some(Output), Some(Input)) => throw NeitherDriverException
- case (_, None) => throw UnknownRelationException
+ case (Input, Output) => throw BothDriversException
+ case (Output, Input) => throw NeitherDriverException
+ case (_, Internal) => throw UnknownRelationException
}
}
@@ -172,15 +171,15 @@ object BiConnect {
// Thus, left node better be a port node and thus have a direction hint
((left_direction, right_direction): @unchecked) match {
// CHILD MOD CURRENT MOD
- case (Some(Input), Some(Input)) => issueConnectR2L(left, right)
- case (Some(Input), None) => issueConnectR2L(left, right)
+ case (Input, Input) => issueConnectR2L(left, right)
+ case (Input, Internal) => issueConnectR2L(left, right)
- case (Some(Output), Some(Output)) => issueConnectL2R(left, right)
- case (Some(Output), None) => issueConnectL2R(left, right)
+ case (Output, Output) => issueConnectL2R(left, right)
+ case (Output, Internal) => issueConnectL2R(left, right)
- case (Some(Input), Some(Output)) => throw NeitherDriverException
- case (Some(Output), Some(Input)) => throw BothDriversException
- case (None, _) => throw UnknownRelationException
+ case (Input, Output) => throw NeitherDriverException
+ case (Output, Input) => throw BothDriversException
+ case (Internal, _) => throw UnknownRelationException
}
}
@@ -188,39 +187,17 @@ object BiConnect {
else if( (context_mod == left_mod) && (context_mod == right_mod) ) {
((left_direction, right_direction): @unchecked) match {
// CURRENT MOD CURRENT MOD
- case (Some(Input), Some(Output)) => issueConnectL2R(left, right)
- case (Some(Input), None) => issueConnectL2R(left, right)
- case (None, Some(Output)) => issueConnectL2R(left, right)
+ case (Input, Output) => issueConnectL2R(left, right)
+ case (Input, Internal) => issueConnectL2R(left, right)
+ case (Internal, Output) => issueConnectL2R(left, right)
- case (Some(Output), Some(Input)) => issueConnectR2L(left, right)
- case (Some(Output), None) => issueConnectR2L(left, right)
- case (None, Some(Input)) => issueConnectR2L(left, right)
+ case (Output, Input) => issueConnectR2L(left, right)
+ case (Output, Internal) => issueConnectR2L(left, right)
+ case (Internal, Input) => issueConnectR2L(left, right)
- case (Some(Input), Some(Input)) => {
- if (connectCompileOptions.dontAssumeDirectionality) {
- throw BothDriversException
- } else {
- (left.binding, right.binding) match {
- case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException
- case (PortBinding(_, _), _) => issueConnectL2R(left, right)
- case (_, PortBinding(_, _)) => issueConnectR2L(left, right)
- case _ => throw BothDriversException
- }
- }
- }
- case (Some(Output), Some(Output)) => {
- if (connectCompileOptions.dontAssumeDirectionality) {
- throw BothDriversException
- } else {
- (left.binding, right.binding) match {
- case (PortBinding(_, _), PortBinding(_, _)) => throw BothDriversException
- case (PortBinding(_, _), _) => issueConnectR2L(left, right)
- case (_, PortBinding(_, _)) => issueConnectL2R(left, right)
- case _ => throw BothDriversException
- }
- }
- }
- case (None, None) => {
+ case (Input, Input) => throw BothDriversException
+ case (Output, Output) => throw BothDriversException
+ case (Internal, Internal) => {
if (connectCompileOptions.dontAssumeDirectionality) {
throw UnknownDriverException
} else {
@@ -239,18 +216,18 @@ object BiConnect {
// Thus both nodes must be ports and have a direction hint
((left_direction, right_direction): @unchecked) match {
// CHILD MOD CHILD MOD
- case (Some(Input), Some(Output)) => issueConnectR2L(left, right)
- case (Some(Output), Some(Input)) => issueConnectL2R(left, right)
+ case (Input, Output) => issueConnectR2L(left, right)
+ case (Output, Input) => issueConnectL2R(left, right)
- case (Some(Input), Some(Input)) => throw NeitherDriverException
- case (Some(Output), Some(Output)) => throw BothDriversException
- case (_, None) =>
+ case (Input, Input) => throw NeitherDriverException
+ case (Output, Output) => throw BothDriversException
+ case (_, Internal) =>
if (connectCompileOptions.dontAssumeDirectionality) {
throw UnknownRelationException
} else {
issueConnectR2L(left, right)
}
- case (None, _) =>
+ case (Internal, _) =>
if (connectCompileOptions.dontAssumeDirectionality) {
throw UnknownRelationException
} else {
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala b/chiselFrontend/src/main/scala/chisel3/core/Binder.scala
deleted file mode 100644
index d872d7c6..00000000
--- a/chiselFrontend/src/main/scala/chisel3/core/Binder.scala
+++ /dev/null
@@ -1,64 +0,0 @@
-package chisel3.core
-
-/**
-* A Binder is a function from UnboundBinding to some Binding.
-*
-* These are used exclusively by Binding.bind and sealed in order to keep
-* all of them in one place. There are two flavors of Binders:
-* Non-terminal (returns another UnboundBinding): These are used to reformat an
-* UnboundBinding (like setting direction) before it is terminally bound.
-* Terminal (returns any other Binding): Due to the nature of Bindings, once a
-* Data is bound to anything but an UnboundBinding, it is forever locked to
-* being that type (as it now represents something in the hardware graph).
-*
-* Note that some Binders require extra arguments to be constructed, like the
-* enclosing Module.
-*/
-
-sealed trait Binder[Out <: Binding] extends Function1[UnboundBinding, Out]{
- def apply(in: UnboundBinding): Out
-}
-
-// THE NON-TERMINAL BINDERS
-// These 'rebind' to another unbound node of different direction!
-case object InputBinder extends Binder[UnboundBinding] {
- def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Input))
-}
-case object OutputBinder extends Binder[UnboundBinding] {
- def apply(in: UnboundBinding) = UnboundBinding(Some(Direction.Output))
-}
-case object FlippedBinder extends Binder[UnboundBinding] {
- def apply(in: UnboundBinding) = UnboundBinding(in.direction.map(_.flip))
- // TODO(twigg): flipping a None should probably be a warning/error
-}
-// The need for this should be transient.
-case object NoDirectionBinder extends Binder[UnboundBinding] {
- def apply(in: UnboundBinding) = UnboundBinding(None)
-}
-
-// THE TERMINAL BINDERS
-case object LitBinder extends Binder[LitBinding] {
- def apply(in: UnboundBinding) = LitBinding()
-}
-
-case class MemoryPortBinder(enclosure: UserModule) extends Binder[MemoryPortBinding] {
- def apply(in: UnboundBinding) = MemoryPortBinding(enclosure)
-}
-
-case class OpBinder(enclosure: UserModule) extends Binder[OpBinding] {
- def apply(in: UnboundBinding) = OpBinding(enclosure)
-}
-
-// Notice how PortBinder uses the direction of the UnboundNode
-case class PortBinder(enclosure: BaseModule) extends Binder[PortBinding] {
- def apply(in: UnboundBinding) = PortBinding(enclosure, in.direction)
-}
-
-case class RegBinder(enclosure: UserModule) extends Binder[RegBinding] {
- def apply(in: UnboundBinding) = RegBinding(enclosure)
-}
-
-case class WireBinder(enclosure: UserModule) extends Binder[WireBinding] {
- def apply(in: UnboundBinding) = WireBinding(enclosure)
-}
-
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
index 87e706b7..2b6f10f6 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
@@ -2,150 +2,69 @@ package chisel3.core
import chisel3.internal.Builder.{forcedModule}
-/**
- * The purpose of a Binding is to indicate what type of hardware 'entity' a
- * specific Data's leaf Elements is actually bound to. All Data starts as being
- * Unbound (and the whole point of cloneType is to return an unbound version).
- * Then, specific API calls take a Data, and return a bound version (either by
- * binding the original model or cloneType then binding the clone). For example,
- * Reg[T<:Data](...) returns a T bound to RegBinding.
- *
- * It is considered invariant that all Elements of a single Data are bound to
- * the same concrete type of Binding.
- *
- * These bindings can be checked (e.g. checkSynthesizable) to make sure certain
- * operations are valid. For example, arithemetic operations or connections can
- * only be executed between synthesizable nodes. These checks are to avoid
- * undefined reference errors.
- *
- * Bindings can carry information about the particular element in the graph it
- * represents like:
- * - For ports (and unbound), the 'direction'
- * - For (relevant) synthesizable nodes, the enclosing Module
- *
- * TODO(twigg): Enrich the bindings to carry more information like the hosting
- * module (when applicable), direction (when applicable), literal info (when
- * applicable). Can ensure applicable data only stored on relevant nodes. e.g.
- * literal info on LitBinding, direction info on UnboundBinding and PortBinding,
- * etc.
- *
- * TODO(twigg): Currently, bindings only apply at the Element level and an
- * Aggregate is considered bound via its elements. May be appropriate to allow
- * Aggregates to be bound along with the Elements. However, certain literal and
- * port direction information doesn't quite make sense in aggregates. This would
- * elegantly handle the empty Vec or Record problem though.
- *
- * TODO(twigg): Binding is currently done via allElements. It may be more
- * elegant if this was instead done as a more explicit tree walk as that allows
- * for better errors.
- */
-
object Binding {
- // Two bindings are 'compatible' if they are the same type.
- // Check currently kind of weird: just ensures same class
- private def compatible(a: Binding, b: Binding): Boolean = a.getClass == b.getClass
- private def compatible(nodes: Seq[Binding]): Boolean =
- if(nodes.size > 1)
- (for((a,b) <- nodes zip nodes.tail) yield compatible(a,b))
- .fold(true)(_&&_)
- else true
-
- case class BindingException(message: String) extends Exception(message)
- def AlreadyBoundException(binding: String) = BindingException(s": Already bound to $binding")
- def NotSynthesizableException = BindingException(s": Not bound to synthesizable node, currently only Type description")
- def MissingIOWrapperException = BindingException(": Missing IO() wrapper")
+ class BindingException(message: String) extends Exception(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)
+}
- // This recursively walks down the Data tree to look at all the leaf 'Element's
- // Will build up an error string in case something goes wrong
- // TODO(twigg): Make member function of Data.
- // Allows oddities like sample_element to be better hidden
- private def walkToBinding(target: Data, checker: Element=>Unit): Unit = target match {
- case (element: Element) => checker(element)
- case (vec: Vec[Data @unchecked]) => {
- try walkToBinding(vec.sample_element, checker)
- catch {
- case BindingException(message) => throw BindingException(s"(*)$message")
- }
- for(idx <- 0 until vec.length) {
- try walkToBinding(vec(idx), checker)
- catch {
- case BindingException(message) => throw BindingException(s"($idx)$message")
- }
- }
- }
- case (record: Record) => {
- for((field, subelem) <- record.elements) {
- try walkToBinding(subelem, checker)
- catch {
- case BindingException(message) => throw BindingException(s".$field$message")
- }
- }
+/** Requires that a node is hardware ("bound")
+ */
+object requireIsHardware {
+ def apply(node: Data, msg: String = "") = {
+ node._parent match { // Compatibility layer hack
+ case Some(x: BaseModule) => x._autoWrapPorts
+ case _ =>
}
- }
-
- // Use walkToBinding to actually rebind the node type
- def bind[T<:Data](target: T, binder: Binder[_<:Binding], error_prelude: String): target.type = {
- try walkToBinding(
- target,
- element => element.binding match {
- case unbound @ UnboundBinding(_) => {
- element.binding = binder(unbound)
- }
- case binding => throw AlreadyBoundException(binding.toString)
- }
- )
- catch {
- case BindingException(message) => throw BindingException(s"$error_prelude$message")
+ if (!node.hasBinding) {
+ val prefix = if (msg.nonEmpty) s"$msg " else ""
+ throw Binding.ExpectedHardwareException(s"$prefix'$node' must be hardware, not a bare Chisel type")
}
- target
}
+}
- // Excepts if any root element is already bound
- def checkUnbound(target: Data, error_prelude: String): Unit = {
- try walkToBinding(
- target,
- element => element.binding match {
- case unbound @ UnboundBinding(_) => {}
- case binding => throw AlreadyBoundException(binding.toString)
- }
- )
- catch {
- case BindingException(message) => throw BindingException(s"$error_prelude$message")
- }
+/** Requires that a node is a chisel type (not hardware, "unbound")
+ */
+object requireIsChiselType {
+ def apply(node: Data, msg: String = "") = if (node.hasBinding) {
+ val prefix = if (msg.nonEmpty) s"$msg " else ""
+ throw Binding.ExpectedChiselTypeException(s"$prefix'$node' must be a Chisel type, not hardware")
}
+}
- // Excepts if any root element is unbound and thus not on the hardware graph
- def checkSynthesizable(target: Data, error_prelude: String): Unit = {
- try walkToBinding(
- target,
- element => {
- // Compatibility mode to automatically wrap ports in IO
- // TODO: remove me, perhaps by removing Bindings checks from compatibility mode
- element._parent match {
- case Some(x: BaseModule) => x._autoWrapPorts
- case _ =>
- }
- // Actual binding check
- element.binding match {
- case SynthesizableBinding() => // OK
- case binding => {
- // Attempt to diagnose common bindings issues, like forgot to wrap IO(...)
- element._parent match {
- case Some(x: LegacyModule) =>
- // null check in case we try to access io before it is defined
- if ((x.io != null) && (x.io.flatten contains element)) {
- throw MissingIOWrapperException
- }
- case _ =>
- }
- // Fallback generic exception
- throw NotSynthesizableException
- }
- }
+// Element only direction used for the Binding system only.
+sealed abstract class BindingDirection
+object BindingDirection {
+ /** Internal type or wire
+ */
+ case object Internal extends BindingDirection
+ /** Module port with output direction
+ */
+ case object Output extends BindingDirection
+ /** Module port with input direction
+ */
+ case object Input extends BindingDirection
+
+ /** Determine the BindingDirection of an Element given its top binding and resolved direction.
+ */
+ def from(binding: TopBinding, direction: ActualDirection) = {
+ binding match {
+ case PortBinding(_) => direction match {
+ case ActualDirection.Output => Output
+ case ActualDirection.Input => Input
+ case dir => throw new RuntimeException(s"Unexpected port element direction '$dir'")
}
- )
- catch {
- case BindingException(message) => throw BindingException(s"$error_prelude$message")
+ case _ => Internal
}
}
}
@@ -153,52 +72,32 @@ object Binding {
// Location refers to 'where' in the Module hierarchy this lives
sealed trait Binding {
def location: Option[BaseModule]
- def direction: Option[Direction]
}
+// Top-level binding representing hardware, not a pointer to another binding (like ChildBinding)
+sealed trait TopBinding extends Binding
// Constrained-ness refers to whether 'bound by Module boundaries'
// An unconstrained binding, like a literal, can be read by everyone
-sealed trait UnconstrainedBinding extends Binding {
+sealed trait UnconstrainedBinding extends TopBinding {
def location = None
}
// A constrained binding can only be read/written by specific modules
// Location will track where this Module is
-sealed trait ConstrainedBinding extends Binding {
+sealed trait ConstrainedBinding extends TopBinding {
def enclosure: BaseModule
def location = Some(enclosure)
}
-// An undirectioned binding means the element represents an internal node
-// with no meaningful concept of a direction
-sealed trait UndirectionedBinding extends Binding { def direction = None }
-
-// This is the default binding, represents data not yet positioned in the graph
-case class UnboundBinding(direction: Option[Direction])
- extends Binding with UnconstrainedBinding
-
-
-// A synthesizable binding is 'bound into' the hardware graph
-object SynthesizableBinding {
- def unapply(target: Binding): Boolean = target.isInstanceOf[SynthesizableBinding]
- // Type check OK because Binding and SynthesizableBinding is sealed
-}
-sealed trait SynthesizableBinding extends Binding
-case class LitBinding() // will eventually have literal info
- extends SynthesizableBinding with UnconstrainedBinding with UndirectionedBinding
-
-case class MemoryPortBinding(enclosure: UserModule)
- extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding
-
+// TODO literal info here
+case class LitBinding() extends UnconstrainedBinding
// TODO(twigg): Ops between unenclosed nodes can also be unenclosed
// However, Chisel currently binds all op results to a module
-case class OpBinding(enclosure: UserModule)
- extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding
-
-case class PortBinding(enclosure: BaseModule, direction: Option[Direction])
- extends SynthesizableBinding with ConstrainedBinding
-
-case class RegBinding(enclosure: UserModule)
- extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding
-
-case class WireBinding(enclosure: UserModule)
- extends SynthesizableBinding with ConstrainedBinding with UndirectionedBinding
+case class OpBinding(enclosure: UserModule) extends ConstrainedBinding
+case class MemoryPortBinding(enclosure: UserModule) extends ConstrainedBinding
+case class PortBinding(enclosure: BaseModule) extends ConstrainedBinding
+case class RegBinding(enclosure: UserModule) extends ConstrainedBinding
+case class WireBinding(enclosure: UserModule) extends ConstrainedBinding
+
+case class ChildBinding(parent: Data) extends Binding {
+ def location = parent.binding.location
+}
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 =
diff --git a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
index cd072ba9..6d8e85a4 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/BlackBox.scala
@@ -74,13 +74,7 @@ abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Para
id._onModuleClose
}
- val firrtlPorts = for (port <- getModulePorts) yield {
- // Port definitions need to know input or output at top-level.
- // By FIRRTL semantics, 'flipped' becomes an Input
- val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output
- Port(port, direction)
- }
-
+ val firrtlPorts = getModulePorts map {port => Port(port, port.userDirection)}
val component = DefBlackBox(this, name, firrtlPorts, params)
_component = Some(component)
component
@@ -132,7 +126,7 @@ abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Para
*/
abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param])(implicit compileOptions: CompileOptions) extends BaseBlackBox {
def io: Record
-
+
// Allow access to bindings from the compatibility package
protected def _ioPortBound() = portsContains(io)
@@ -165,19 +159,13 @@ abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param
id._onModuleClose
}
- val firrtlPorts = for ((_, port) <- namedPorts) yield {
- // Port definitions need to know input or output at top-level.
- // By FIRRTL semantics, 'flipped' becomes an Input
- val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output
- Port(port, direction)
- }
-
+ val firrtlPorts = namedPorts map {namedPort => Port(namedPort._2, namedPort._2.userDirection)}
val component = DefBlackBox(this, name, firrtlPorts, params)
_component = Some(component)
component
}
- private[core] def initializeInParent() {
+ private[core] def initializeInParent() {
for ((_, port) <- io.elements) {
pushCommand(DefInvalid(UnlocatableSourceInfo, port.ref))
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala b/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala
index ad4050f3..07546406 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/ChiselAnnotation.scala
@@ -2,6 +2,8 @@
package chisel3.core
+import scala.language.existentials
+
import chisel3.internal.{Builder, InstanceId}
import firrtl.Transform
import firrtl.annotations.{Annotation, CircuitName, ComponentName, ModuleName}
@@ -56,7 +58,7 @@ object dontTouch { // scalastyle:ignore object.name
*/
def apply[T <: Data](data: T)(implicit compileOptions: CompileOptions): T = {
if (compileOptions.checkSynthesizable) {
- Binding.checkSynthesizable(data, s"$data")
+ requireIsHardware(data, "Data marked dontTouch")
}
// TODO unify with firrtl.transforms.DontTouchAnnotation
val anno = ChiselAnnotation(data, classOf[firrtl.Transform], "DONTtouch!")
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Clock.scala b/chiselFrontend/src/main/scala/chisel3/core/Clock.scala
new file mode 100644
index 00000000..f682310b
--- /dev/null
+++ b/chiselFrontend/src/main/scala/chisel3/core/Clock.scala
@@ -0,0 +1,34 @@
+// See LICENSE for license details.
+
+package chisel3.core
+
+import chisel3.internal.Builder.{pushOp}
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo._
+import chisel3.internal.firrtl.PrimOp.AsUIntOp
+
+object Clock {
+ def apply(): Clock = new Clock
+}
+
+// TODO: Document this.
+sealed class Clock extends Element(Width(1)) {
+ def cloneType: this.type = Clock().asInstanceOf[this.type]
+
+ 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
+ }
+}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
index 803e6c0f..55e6d18c 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala
@@ -16,9 +16,6 @@ trait CompileOptions {
val dontTryConnectionsSwapped: Boolean
// If connection directionality is not explicit, do not use heuristics to attempt to determine it.
val dontAssumeDirectionality: Boolean
- // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used
- // instead of Flipped, Input, or Output.
- val deprecateOldDirectionMethods: Boolean
// Check that referenced Data have actually been declared.
val checkSynthesizable: Boolean
}
@@ -46,9 +43,6 @@ object ExplicitCompileOptions {
val dontTryConnectionsSwapped: Boolean,
// If connection directionality is not explicit, do not use heuristics to attempt to determine it.
val dontAssumeDirectionality: Boolean,
- // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used
- // instead of Flipped, Input, or Output.
- val deprecateOldDirectionMethods: Boolean,
// Check that referenced Data have actually been declared.
val checkSynthesizable: Boolean
) extends CompileOptions
@@ -61,7 +55,6 @@ object ExplicitCompileOptions {
declaredTypeMustBeUnbound = false,
dontTryConnectionsSwapped = false,
dontAssumeDirectionality = false,
- deprecateOldDirectionMethods = false,
checkSynthesizable = false
)
@@ -72,7 +65,6 @@ object ExplicitCompileOptions {
declaredTypeMustBeUnbound = true,
dontTryConnectionsSwapped = true,
dontAssumeDirectionality = true,
- deprecateOldDirectionMethods = true,
checkSynthesizable = true
)
}
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
- }
-}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
index 03c484b0..47d48061 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Mem.scala
@@ -21,8 +21,6 @@ object Mem {
def apply[T <: Data](size: Int, t: T): Mem[T] = macro MemTransform.apply[T]
def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Mem[T] = {
val mt = t.chiselCloneType
- Binding.bind(mt, NoDirectionBinder, "Error: fresh t")
- // TODO(twigg): Remove need for this Binding
val mem = new Mem(mt, size)
pushCommand(DefMemory(sourceInfo, mem, mt, size))
@@ -87,7 +85,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId {
}
private def makePort(sourceInfo: SourceInfo, idx: UInt, dir: MemPortDirection)(implicit compileOptions: CompileOptions): T = {
- Binding.checkSynthesizable(idx, s"'idx' ($idx)")
+ requireIsHardware(idx, "memory port index")
val i = Vec.truncateIndex(idx, length)(sourceInfo, compileOptions)
val port = pushCommand(
@@ -95,7 +93,7 @@ sealed abstract class MemBase[T <: Data](t: T, val length: Int) extends HasId {
t.chiselCloneType, Node(this), dir, i.ref, Node(Builder.forcedClock))
).id
// Bind each element of port to being a MemoryPort
- Binding.bind(port, MemoryPortBinder(Builder.forcedUserModule), "Error: Fresh t")
+ port.bind(MemoryPortBinding(Builder.forcedUserModule))
port
}
}
@@ -124,9 +122,6 @@ object SyncReadMem {
def do_apply[T <: Data](size: Int, t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SyncReadMem[T] = {
val mt = t.chiselCloneType
- Binding.bind(mt, NoDirectionBinder, "Error: fresh t")
- // TODO(twigg): Remove need for this Binding
-
val mem = new SyncReadMem(mt, size)
pushCommand(DefSeqMemory(sourceInfo, mem, mt, size))
mem
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Module.scala b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
index b512ed75..0f081daf 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Module.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Module.scala
@@ -219,8 +219,34 @@ abstract class BaseModule extends HasId {
*/
protected def IO[T<:Data](iodef: T): iodef.type = {
require(!_closed, "Can't add more ports after module close")
+ requireIsChiselType(iodef, "io type")
+
+ // Compatibility code: Chisel2 did not require explicit direction on nodes
+ // (unspecified treated as output, and flip on nothing was input).
+ // This sets assigns the explicit directions required by newer semantics on
+ // Bundles defined in compatibility mode.
+ // This recursively walks the tree, and assigns directions if no explicit
+ // direction given by upper-levels (override Input / Output) AND element is
+ // directly inside a compatibility Bundle determined by compile options.
+ def assignCompatDir(data: Data, insideCompat: Boolean): Unit = {
+ data match {
+ case data: Element if insideCompat => data._assignCompatibilityExplicitDirection
+ case data: Element => // Not inside a compatibility Bundle, nothing to be done
+ case data: Aggregate => data.userDirection match {
+ // Recurse into children to ensure explicit direction set somewhere
+ case UserDirection.Unspecified | UserDirection.Flip => data match {
+ case data: Record if (!data.compileOptions.dontAssumeDirectionality) =>
+ data.getElements.foreach(assignCompatDir(_, true))
+ case _ => data.getElements.foreach(assignCompatDir(_, false))
+ }
+ case UserDirection.Input | UserDirection.Output => // forced assign, nothing to do
+ }
+ }
+ }
+ assignCompatDir(iodef, false)
+
// Bind each element of the iodef to being a Port
- Binding.bind(iodef, PortBinder(this), "Error: iodef")
+ iodef.bind(PortBinding(this))
_ports += iodef
iodef
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
index 80e96ce7..3c34785f 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/MonoConnect.scala
@@ -120,24 +120,23 @@ object MonoConnect {
// This function checks if element-level connection operation allowed.
// Then it either issues it or throws the appropriate exception.
def elemConnect(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions, sink: Element, source: Element, context_mod: UserModule): Unit = {
- import Direction.{Input, Output} // Using extensively so import these
+ import BindingDirection.{Internal, Input, Output} // Using extensively so import these
// If source has no location, assume in context module
// This can occur if is a literal, unbound will error previously
val sink_mod: BaseModule = sink.binding.location.getOrElse(throw UnwritableSinkException)
val source_mod: BaseModule = source.binding.location.getOrElse(context_mod)
- val sink_direction: Option[Direction] = sink.binding.direction
- val source_direction: Option[Direction] = source.binding.direction
- // None means internal
+ val sink_direction = BindingDirection.from(sink.topBinding, sink.direction)
+ val source_direction = BindingDirection.from(source.topBinding, source.direction)
// CASE: Context is same module that both left node and right node are in
if( (context_mod == sink_mod) && (context_mod == source_mod) ) {
((sink_direction, source_direction): @unchecked) match {
// SINK SOURCE
// CURRENT MOD CURRENT MOD
- case (Some(Output), _) => issueConnect(sink, source)
- case (None, _) => issueConnect(sink, source)
- case (Some(Input), _) => throw UnwritableSinkException
+ case (Output, _) => issueConnect(sink, source)
+ case (Internal, _) => issueConnect(sink, source)
+ case (Input, _) => throw UnwritableSinkException
}
}
@@ -148,19 +147,19 @@ object MonoConnect {
((sink_direction, source_direction): @unchecked) match {
// SINK SOURCE
// CURRENT MOD CHILD MOD
- case (None, Some(Output)) => issueConnect(sink, source)
- case (None, Some(Input)) => issueConnect(sink, source)
- case (Some(Output), Some(Output)) => issueConnect(sink, source)
- case (Some(Output), Some(Input)) => issueConnect(sink, source)
- case (_, None) => {
+ case (Internal, Output) => issueConnect(sink, source)
+ case (Internal, Input) => issueConnect(sink, source)
+ case (Output, Output) => issueConnect(sink, source)
+ case (Output, Input) => issueConnect(sink, source)
+ case (_, Internal) => {
if (!(connectCompileOptions.dontAssumeDirectionality)) {
issueConnect(sink, source)
} else {
throw UnreadableSourceException
}
}
- case (Some(Input), Some(Output)) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink)
- case (Some(Input), _) => throw UnwritableSinkException
+ case (Input, Output) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink)
+ case (Input, _) => throw UnwritableSinkException
}
}
@@ -171,9 +170,9 @@ object MonoConnect {
((sink_direction, source_direction): @unchecked) match {
// SINK SOURCE
// CHILD MOD CURRENT MOD
- case (Some(Input), _) => issueConnect(sink, source)
- case (Some(Output), _) => throw UnwritableSinkException
- case (None, _) => throw UnwritableSinkException
+ case (Input, _) => issueConnect(sink, source)
+ case (Output, _) => throw UnwritableSinkException
+ case (Internal, _) => throw UnwritableSinkException
}
}
@@ -187,17 +186,17 @@ object MonoConnect {
((sink_direction, source_direction): @unchecked) match {
// SINK SOURCE
// CHILD MOD CHILD MOD
- case (Some(Input), Some(Input)) => issueConnect(sink, source)
- case (Some(Input), Some(Output)) => issueConnect(sink, source)
- case (Some(Output), _) => throw UnwritableSinkException
- case (_, None) => {
+ case (Input, Input) => issueConnect(sink, source)
+ case (Input, Output) => issueConnect(sink, source)
+ case (Output, _) => throw UnwritableSinkException
+ case (_, Internal) => {
if (!(connectCompileOptions.dontAssumeDirectionality)) {
issueConnect(sink, source)
} else {
throw UnreadableSourceException
}
}
- case (None, _) => throw UnwritableSinkException
+ case (Internal, _) => throw UnwritableSinkException
}
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Mux.scala b/chiselFrontend/src/main/scala/chisel3/core/Mux.scala
index f01c59ca..e4ef001f 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Mux.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Mux.scala
@@ -26,10 +26,10 @@ object Mux {
def do_apply[T <: Data](cond: Bool, con: T, alt: T)(implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions): T = {
- Binding.checkSynthesizable(cond, s"'cond' ($cond)")
- Binding.checkSynthesizable(con, s"'con' ($con)")
- Binding.checkSynthesizable(alt, s"'alt' ($alt)")
+ requireIsHardware(cond, "mux condition")
+ requireIsHardware(con, "mux true value")
+ requireIsHardware(alt, "mux false value")
val d = cloneSupertype(Seq(con, alt), "Mux")
pushOp(DefPrim(sourceInfo, d, MultiplexOp, cond.ref, con.ref, alt.ref))
}
-} \ No newline at end of file
+}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala
index 12d0a939..3fdb3398 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Reg.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Reg.scala
@@ -17,12 +17,12 @@ object Reg {
*/
def apply[T <: Data](t: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
if (compileOptions.declaredTypeMustBeUnbound) {
- Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?")
+ requireIsChiselType(t, "reg type")
}
val reg = t.chiselCloneType
val clock = Node(Builder.forcedClock)
- Binding.bind(reg, RegBinder(Builder.forcedUserModule), "Error: t")
+ reg.bind(RegBinding(Builder.forcedUserModule))
pushCommand(DefReg(sourceInfo, reg, clock))
reg
}
@@ -40,7 +40,6 @@ object RegNext {
}).asInstanceOf[T]
val reg = Reg(model)
- Binding.checkSynthesizable(next, s"'next' ($next)") // TODO: move into connect?
reg := next
reg
@@ -57,7 +56,6 @@ object RegNext {
}).asInstanceOf[T]
val reg = RegInit(model, init) // TODO: this makes NO sense
- Binding.checkSynthesizable(next, s"'next' ($next)") // TODO: move into connect?
reg := next
reg
@@ -84,14 +82,14 @@ object RegInit {
*/
def apply[T <: Data](t: T, init: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
if (compileOptions.declaredTypeMustBeUnbound) {
- Binding.checkUnbound(t, s"t ($t) must be unbound Type. Try using cloneType?")
+ requireIsChiselType(t, "reg type")
}
val reg = t.chiselCloneType
val clock = Node(Builder.forcedClock)
val reset = Node(Builder.forcedReset)
- Binding.bind(reg, RegBinder(Builder.forcedUserModule), "Error: t")
- Binding.checkSynthesizable(init, s"'init' ($init)")
+ reg.bind(RegBinding(Builder.forcedUserModule))
+ requireIsHardware(init, "reg initializer")
pushCommand(DefRegInit(sourceInfo, reg, clock, reset, init.ref))
reg
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala
index 666be4d0..5207ef04 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/UserModule.scala
@@ -64,21 +64,17 @@ abstract class UserModule(implicit moduleCompileOptions: CompileOptions)
id._onModuleClose
}
- val firrtlPorts = for (port <- getModulePorts) yield {
- // Port definitions need to know input or output at top-level. 'flipped' means Input.
- val direction = if(Data.isFirrtlFlipped(port)) Direction.Input else Direction.Output
- firrtl.Port(port, direction)
- }
+ val firrtlPorts = getModulePorts map {port => Port(port, port.userDirection)}
_firrtlPorts = Some(firrtlPorts)
// Generate IO invalidation commands to initialize outputs as unused
val invalidateCommands = getModulePorts map {port => DefInvalid(UnlocatableSourceInfo, port.ref)}
-
+
val component = DefModule(this, name, firrtlPorts, invalidateCommands ++ getCommands)
_component = Some(component)
component
}
-
+
// There is no initialization to be done by default.
private[core] def initializeInParent() {}
}
@@ -100,7 +96,7 @@ abstract class ImplicitModule(implicit moduleCompileOptions: CompileOptions)
private[core] override def initializeInParent() {
implicit val sourceInfo = UnlocatableSourceInfo
-
+
for (port <- getModulePorts) {
pushCommand(DefInvalid(sourceInfo, port.ref))
}
@@ -122,7 +118,7 @@ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions)
// These are to be phased out
protected var override_clock: Option[Clock] = None
protected var override_reset: Option[Bool] = None
-
+
// _clock and _reset can be clock and reset in these 2ary constructors
// once chisel2 compatibility issues are resolved
@deprecated("Module constructor with override_clock and override_reset deprecated, use withClockAndReset", "chisel3")
@@ -132,7 +128,7 @@ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions)
this.override_clock = override_clock
this.override_reset = override_reset
}
-
+
@deprecated("Module constructor with override _clock deprecated, use withClock", "chisel3")
def this(_clock: Clock)(implicit moduleCompileOptions: CompileOptions) = this(Option(_clock), None)(moduleCompileOptions)
@deprecated("Module constructor with override _reset deprecated, use withReset", "chisel3")
@@ -174,7 +170,7 @@ abstract class LegacyModule(implicit moduleCompileOptions: CompileOptions)
// Don't generate source info referencing parents inside a module, since this interferes with
// module de-duplication in FIRRTL emission.
implicit val sourceInfo = UnlocatableSourceInfo
-
+
pushCommand(DefInvalid(sourceInfo, io.ref))
override_clock match {
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
index 73556750..1d7a45e0 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Builder.scala
@@ -215,7 +215,7 @@ private[chisel3] object Builder {
}
def pushOp[T <: Data](cmd: DefPrim[T]): T = {
// Bind each element of the returned Data to being a Op
- Binding.bind(cmd.id, OpBinder(forcedUserModule), "Error: During op creation, fresh result")
+ cmd.id.bind(OpBinding(forcedUserModule))
pushCommand(cmd).id
}
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
index 18df7f51..cca368ef 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -266,7 +266,7 @@ case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends C
case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
-case class Port(id: Data, dir: Direction)
+case class Port(id: Data, dir: UserDirection)
case class Printf(sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Command
abstract class Component extends Arg {
def id: BaseModule