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
|
// SPDX-License-Identifier: Apache-2.0
package firrtl.passes
import firrtl.Utils.{create_exps, flow, kind, toWrappedExpression}
import firrtl.ir._
import firrtl.Mappers._
import firrtl.options.Dependency
import firrtl._
import scala.collection.mutable
/** Makes changes to the Firrtl AST to make Verilog emission easier
*
* - For each instance, adds wires to connect to each port
* - Note that no Namespace is required because Uniquify ensures that there will be no
* collisions with the lowered names of instance ports
* - Also removes Attaches where a single Port OR Wire connects to 1 or more instance ports
* - These are expressed in the portCons of WDefInstConnectors
*
* @note The result of this pass is NOT legal Firrtl
*/
object VerilogPrep extends Pass {
override def prerequisites = firrtl.stage.Forms.LowFormMinimumOptimized ++
Seq(
Dependency[firrtl.transforms.BlackBoxSourceHelper],
Dependency[firrtl.transforms.FixAddingNegativeLiterals],
Dependency[firrtl.transforms.ReplaceTruncatingArithmetic],
Dependency[firrtl.transforms.InlineBitExtractionsTransform],
Dependency[firrtl.transforms.InlineAcrossCastsTransform],
Dependency[firrtl.transforms.LegalizeClocksAndAsyncResetsTransform],
Dependency[firrtl.transforms.FlattenRegUpdate],
Dependency(passes.VerilogModulusCleanup),
Dependency[firrtl.transforms.VerilogRename]
)
override def optionalPrerequisites = firrtl.stage.Forms.LowFormOptimized
override def optionalPrerequisiteOf = Seq.empty
override def invalidates(a: Transform) = false
type AttachSourceMap = Map[WrappedExpression, Expression]
// Finds attaches with only a single source (Port or Wire)
// - Creates a map of attached expressions to their source
// - Removes the Attach
private def collectAndRemoveAttach(m: DefModule): (DefModule, AttachSourceMap) = {
val sourceMap = mutable.HashMap.empty[WrappedExpression, Expression]
lazy val namespace = Namespace(m)
def onStmt(stmt: Statement): Statement = stmt.map(onStmt) match {
case attach: Attach =>
val wires = attach.exprs.groupBy(kind)
val sources = wires.getOrElse(PortKind, Seq.empty) ++ wires.getOrElse(WireKind, Seq.empty)
val instPorts = wires.getOrElse(InstanceKind, Seq.empty)
// Sanity check (Should be caught by CheckTypes)
assert(sources.size + instPorts.size == attach.exprs.size)
sources match {
case Seq() => // Zero sources, can add a wire to connect and remove
val name = namespace.newTemp
val wire = DefWire(NoInfo, name, instPorts.head.tpe)
val ref = WRef(wire)
for (inst <- instPorts) sourceMap(inst) = ref
wire // Replace the attach with new source wire definition
case Seq(source) => // One source can be removed
assert(!sourceMap.contains(source)) // should have been merged
for (inst <- instPorts) sourceMap(inst) = source
EmptyStmt
case moreThanOne =>
attach
}
case s => s
}
(m.map(onStmt), sourceMap.toMap)
}
def run(c: Circuit): Circuit = {
def lowerE(e: Expression): Expression = e match {
case (_: WRef | _: WSubField) if kind(e) == InstanceKind =>
WRef(LowerTypes.loweredName(e), e.tpe, kind(e), flow(e))
case _ => e.map(lowerE)
}
def lowerS(attachMap: AttachSourceMap)(s: Statement): Statement = s match {
case WDefInstance(info, name, module, tpe) =>
val portRefs = create_exps(WRef(name, tpe, ExpKind, SourceFlow))
val (portCons, wires) = portRefs.map { p =>
attachMap.get(p) match {
// If it has a source in attachMap use that
case Some(ref) => (p -> ref, None)
// If no source, create a wire corresponding to the port and connect it up
case None =>
val wire = DefWire(info, LowerTypes.loweredName(p), p.tpe)
(p -> WRef(wire), Some(wire))
}
}.unzip
val newInst = WDefInstanceConnector(info, name, module, tpe, portCons)
Block(wires.flatten :+ newInst)
case other => other.map(lowerS(attachMap)).map(lowerE)
}
val modulesx = c.modules.map { mod =>
val (modx, attachMap) = collectAndRemoveAttach(mod)
modx.map(lowerS(attachMap))
}
c.copy(modules = modulesx)
}
}
|