1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
// See LICENSE for license details.
package chisel3.core
import chisel3.internal.ChiselException
import chisel3.internal.Builder.{forcedModule}
import chisel3.internal.firrtl.LitArg
object Binding {
class BindingException(message: String) extends ChiselException(message)
/** A function expected a Chisel type but got a hardware object
*/
case class ExpectedChiselTypeException(message: String) extends BindingException(message)
/**A function expected a hardware object but got a Chisel type
*/
case class ExpectedHardwareException(message: String) extends BindingException(message)
/** An aggregate had a mix of specified and unspecified directionality children
*/
case class MixedDirectionAggregateException(message: String) extends BindingException(message)
/** Attempted to re-bind an already bound (directionality or hardware) object
*/
case class RebindingException(message: String) extends BindingException(message)
}
/** Requires that a node is hardware ("bound")
*/
object requireIsHardware {
def apply(node: Data, msg: String = ""): Unit = {
node._parent match { // Compatibility layer hack
case Some(x: BaseModule) => x._compatAutoWrapPorts
case _ =>
}
if (!node.topBindingOpt.isDefined) {
val prefix = if (msg.nonEmpty) s"$msg " else ""
throw Binding.ExpectedHardwareException(s"$prefix'$node' must be hardware, " +
"not a bare Chisel type. Perhaps you forgot to wrap it in Wire(_) or IO(_)?")
}
}
}
/** Requires that a node is a chisel type (not hardware, "unbound")
*/
object requireIsChiselType {
def apply(node: Data, msg: String = ""): Unit = if (node.topBindingOpt.isDefined) {
val prefix = if (msg.nonEmpty) s"$msg " else ""
throw Binding.ExpectedChiselTypeException(s"$prefix'$node' must be a Chisel type, not hardware")
}
}
// 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): BindingDirection = {
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'")
}
case _ => Internal
}
}
}
// Location refers to 'where' in the Module hierarchy this lives
sealed trait Binding {
def location: Option[BaseModule]
}
// 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 TopBinding {
def location: Option[BaseModule] = None
}
// A constrained binding can only be read/written by specific modules
// Location will track where this Module is, and the bound object can be referenced in FIRRTL
sealed trait ConstrainedBinding extends TopBinding {
def enclosure: BaseModule
def location: Option[BaseModule] = Some(enclosure)
}
// A binding representing a data that cannot be (re)assigned to.
sealed trait ReadOnlyBinding extends TopBinding
// TODO(twigg): Ops between unenclosed nodes can also be unenclosed
// However, Chisel currently binds all op results to a module
case class OpBinding(enclosure: RawModule) extends ConstrainedBinding with ReadOnlyBinding
case class MemoryPortBinding(enclosure: RawModule) extends ConstrainedBinding
case class PortBinding(enclosure: BaseModule) extends ConstrainedBinding
case class RegBinding(enclosure: RawModule) extends ConstrainedBinding
case class WireBinding(enclosure: RawModule) extends ConstrainedBinding
case class ChildBinding(parent: Data) extends Binding {
def location: Option[BaseModule] = parent.topBinding.location
}
/** Special binding for Vec.sample_element */
case class SampleElementBinding[T <: Data](parent: Vec[T]) extends Binding {
def location = parent.topBinding.location
}
// A DontCare element has a specific Binding, somewhat like a literal.
// It is a source (RHS). It may only be connected/applied to sinks.
case class DontCareBinding() extends UnconstrainedBinding
sealed trait LitBinding extends UnconstrainedBinding with ReadOnlyBinding
// Literal binding attached to a element that is not part of a Bundle.
case class ElementLitBinding(litArg: LitArg) extends LitBinding
// Literal binding attached to the root of a Bundle, containing literal values of its children.
case class BundleLitBinding(litMap: Map[Data, LitArg]) extends LitBinding
|