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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
// See LICENSE for license details.
package chisel3.core
import scala.collection.mutable.ArrayBuffer
import scala.language.experimental.macros
import chisel3.internal._
import chisel3.internal.Builder._
import chisel3.internal.firrtl._
import chisel3.internal.firrtl.{Command => _, _}
import chisel3.internal.sourceinfo.{InstTransform, SourceInfo, UnlocatableSourceInfo}
object Module {
/** A wrapper method that all Module instantiations must be wrapped in
* (necessary to help Chisel track internal state).
*
* @param m the Module being created
*
* @return the input module `m` with Chisel metadata properly set
*/
def apply[T <: Module](bc: => T): T = macro InstTransform.apply[T]
def do_apply[T <: Module](bc: => T)(implicit sourceInfo: SourceInfo): T = {
// Don't generate source info referencing parents inside a module, sincce this interferes with
// module de-duplication in FIRRTL emission.
val childSourceInfo = UnlocatableSourceInfo
val parent: Option[Module] = Builder.currentModule
val m = bc.setRefs() // This will set currentModule!
m._commands.prepend(DefInvalid(childSourceInfo, m.io.ref)) // init module outputs
Builder.currentModule = parent // Back to parent!
val ports = m.computePorts
Builder.components += Component(m, m.name, ports, m._commands)
// Avoid referencing 'parent' in top module
if(!Builder.currentModule.isEmpty) {
pushCommand(DefInstance(sourceInfo, m, ports))
m.setupInParent(childSourceInfo)
}
m
}
}
/** Abstract base class for Modules, which behave much like Verilog modules.
* These may contain both logic and state which are written in the Module
* body (constructor).
*
* @note Module instantiations must be wrapped in a Module() call.
*/
abstract class Module(
override_clock: Option[Clock]=None, override_reset: Option[Bool]=None)
extends HasId {
// _clock and _reset can be clock and reset in these 2ary constructors
// once chisel2 compatibility issues are resolved
def this(_clock: Clock) = this(Option(_clock), None)
def this(_reset: Bool) = this(None, Option(_reset))
def this(_clock: Clock, _reset: Bool) = this(Option(_clock), Option(_reset))
// This function binds the iodef as a port in the hardware graph
private[chisel3] def Port[T<:Data](iodef: T): iodef.type = {
// Bind each element of the iodef to being a Port
Binding.bind(iodef, PortBinder(this), "Error: iodef")
iodef
}
private[core] var ioDefined: Boolean = false
/**
* This must wrap the datatype used to set the io field of any Module.
* i.e. All concrete modules must have defined io in this form:
* [lazy] val io[: io type] = IO(...[: io type])
*
* Items in [] are optional.
*
* The granted iodef WILL NOT be cloned (to allow for more seamless use of
* anonymous Bundles in the IO) and thus CANNOT have been bound to any logic.
* This will error if any node is bound (e.g. due to logic in a Bundle
* constructor, which is considered improper).
*
* TODO(twigg): Specifically walk the Data definition to call out which nodes
* are problematic.
*/
def IO[T<:Data](iodef: T): iodef.type = {
require(!ioDefined, "Another IO definition for this module was already declared!")
ioDefined = true
Port(iodef)
}
private[core] val _namespace = Builder.globalNamespace.child
private[chisel3] val _commands = ArrayBuffer[Command]()
private[core] val _ids = ArrayBuffer[HasId]()
Builder.currentModule = Some(this)
/** Desired name of this module. */
def desiredName = this.getClass.getName.split('.').last
/** Legalized name of this module. */
final val name = Builder.globalNamespace.name(desiredName)
/** IO for this Module. At the Scala level (pre-FIRRTL transformations),
* connections in and out of a Module may only go through `io` elements.
*/
def io: Bundle
val clock = Port(Input(Clock()))
val reset = Port(Input(Bool()))
private[chisel3] def addId(d: HasId) { _ids += d }
private[core] def ports: Seq[(String,Data)] = Vector(
("clk", clock), ("reset", reset), ("io", io)
)
private[core] def computePorts: Seq[firrtl.Port] = {
// If we're auto-wrapping IO definitions, do so now.
if (compileOptions.autoIOWrap && !ioDefined) {
IO(io)
}
for ((name, port) <- ports) 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
firrtl.Port(port, direction)
}
}
private[core] def setupInParent(implicit sourceInfo: SourceInfo): this.type = {
_parent match {
case Some(p) => {
pushCommand(DefInvalid(sourceInfo, io.ref)) // init instance inputs
clock := override_clock.getOrElse(p.clock)
reset := override_reset.getOrElse(p.reset)
this
}
case None => this
}
}
private[core] def setRefs(): this.type = {
for ((name, port) <- ports) {
port.setRef(ModuleIO(this, _namespace.name(name)))
}
// Suggest names to nodes using runtime reflection
def getValNames(c: Class[_]): Set[String] = {
if (c == classOf[Module]) Set()
else getValNames(c.getSuperclass) ++ c.getDeclaredFields.map(_.getName)
}
val valNames = getValNames(this.getClass)
def isPublicVal(m: java.lang.reflect.Method) =
m.getParameterTypes.isEmpty && valNames.contains(m.getName)
/** Recursively suggests names to supported "container" classes
* Arbitrary nestings of supported classes are allowed so long as the
* innermost element is of type HasId
* Currently supported:
* - Iterable
* - Option
* (Note that Map is Iterable[Tuple2[_,_]] and thus excluded)
*/
def nameRecursively(prefix: String, nameMe: Any): Unit =
nameMe match {
case (id: HasId) => id.suggestName(prefix)
case Some(elt) => nameRecursively(prefix, elt)
case (iter: Iterable[_]) if iter.hasDefiniteSize =>
for ((elt, i) <- iter.zipWithIndex) {
nameRecursively(s"${prefix}_${i}", elt)
}
case _ => // Do nothing
}
val methods = getClass.getMethods.sortWith(_.getName > _.getName)
for (m <- methods if isPublicVal(m)) {
nameRecursively(m.getName, m.invoke(this))
}
// For Module instances we haven't named, suggest the name of the Module
_ids foreach {
case m: Module => m.suggestName(m.name)
case _ =>
}
// All suggestions are in, force names to every node.
_ids.foreach(_.forceName(default="T", _namespace))
_ids.foreach(_._onModuleClose)
this
}
// For debuggers/testers
lazy val getPorts = computePorts
}
|