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
|
// SPDX-License-Identifier: Apache-2.0
package firrtl.annotations.analysis
import firrtl.annotations._
import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
import firrtl.Utils.throwInternalError
import scala.collection.mutable
/** Used by [[firrtl.annotations.transforms.EliminateTargetPaths]] to eliminate target paths
* Calculates needed modifications to a circuit's module/instance hierarchy
*/
case class DuplicationHelper(existingModules: Set[String]) {
// Maps instances to the module it instantiates (an ofModule)
type InstanceOfModuleMap = mutable.LinkedHashMap[Instance, OfModule]
// Maps a module to the instance/ofModules it instantiates
type ModuleHasInstanceOfModuleMap = mutable.LinkedHashMap[String, InstanceOfModuleMap]
// Maps original module names to new duplicated modules and their encapsulated instance/ofModules
type DupMap = mutable.LinkedHashMap[String, ModuleHasInstanceOfModuleMap]
// Internal state to keep track of how paths duplicate
private val dupMap = new DupMap()
// Internal record of which paths are renamed to which new names, in the case of a collision
private val cachedNames = mutable.LinkedHashMap[(String, Seq[(Instance, OfModule)]), String]() ++
existingModules.map(m => (m, Nil) -> m)
// Internal record of all paths to ensure unique name generation
private val allModules = mutable.LinkedHashSet[String]() ++ existingModules
/** Updates internal state (dupMap) to calculate instance hierarchy modifications so t's tokens in an instance can be
* expressed as a tokens in a module (e.g. uniquify/duplicate the instance path in t's tokens)
* @param t An instance-resolved component
*/
def expandHierarchy(t: IsMember): Unit = {
val path = t.asPath
path.reverse.tails.map { _.reverse }.foreach { duplicate(t.module, _) }
}
/** Updates dupMap with how original module names map to new duplicated module names
* @param top Root module of a component
* @param path Path down instance hierarchy of a component
*/
private def duplicate(top: String, path: Seq[(Instance, OfModule)]): Unit = {
val (originalModule, instance, ofModule) = path.size match {
case 0 => return
case 1 => (top, path.head._1, path.head._2)
case _ => (path(path.length - 2)._2.value, path.last._1, path.last._2)
}
val originalModuleToDupedModule = dupMap.getOrElseUpdate(originalModule, new ModuleHasInstanceOfModuleMap())
val dupedModule = getModuleName(top, path.dropRight(1))
val dupedModuleToInstances = originalModuleToDupedModule.getOrElseUpdate(dupedModule, new InstanceOfModuleMap())
val dupedInstanceModule = getModuleName(top, path)
dupedModuleToInstances += ((instance, OfModule(dupedInstanceModule)))
val originalInstanceModuleToDupedModule = dupMap.getOrElseUpdate(ofModule.value, new ModuleHasInstanceOfModuleMap())
originalInstanceModuleToDupedModule.getOrElseUpdate(dupedInstanceModule, new InstanceOfModuleMap())
}
/** Deterministic name-creation of a duplicated module
* @param top
* @param path
* @return
*/
def getModuleName(top: String, path: Seq[(Instance, OfModule)]): String = {
cachedNames.get((top, path)) match {
case None => // Need a new name
val prefix = path.last._2.value + "___"
val postfix = top + "_" + path.map { case (i, m) => i.value }.mkString("_")
val ns = mutable.HashSet(allModules.toSeq: _*)
val finalName = firrtl.Namespace.findValidPrefix(prefix, Seq(postfix), ns) + postfix
allModules += finalName
cachedNames((top, path)) = finalName
finalName
case Some(newName) => newName
}
}
/** Return the duplicated module (formerly originalOfModule) instantiated by instance in newModule (formerly
* originalModule)
* @param originalModule original encapsulating module
* @param newModule new name of encapsulating module
* @param instance instance name being declared in encapsulating module
* @param originalOfModule original module being instantiated in originalModule
* @return
*/
def getNewOfModule(
originalModule: String,
newModule: String,
instance: Instance,
originalOfModule: OfModule
): OfModule = {
dupMap.get(originalModule) match {
case None => // No duplication, can return originalOfModule
originalOfModule
case Some(newDupedModules) =>
newDupedModules.get(newModule) match {
case None if newModule != originalModule => throwInternalError("BAD")
case None => // No duplication, can return originalOfModule
originalOfModule
case Some(newDupedModule) =>
newDupedModule.get(instance) match {
case None => // Not duped, can return originalOfModule
originalOfModule
case Some(newOfModule) =>
newOfModule
}
}
}
}
/** Returns the names of this module's duplicated (including the original name)
* @param module
* @return
*/
def getDuplicates(module: String): Set[String] = {
dupMap.get(module).map(_.keys.toSet[String]).getOrElse(Set.empty[String]) ++ Set(module)
}
/** Rewrites t with new module/instance hierarchy calculated after repeated calls to [[expandHierarchy]]
* @param t A target
* @return t rewritten, is a seq because if the t.module has been duplicated, it must now refer to multiple modules
*/
def makePathless(t: IsMember): Seq[IsMember] = {
val top = t.module
val path = t.asPath
val newTops = getDuplicates(top)
newTops.map { newTop =>
val newPath = mutable.ArrayBuffer[TargetToken]()
path.foldLeft((top, newTop)) {
case ((originalModule, newModule), (instance, ofModule)) =>
val newOfModule = getNewOfModule(originalModule, newModule, instance, ofModule)
newPath ++= Seq(instance, newOfModule)
(ofModule.value, newOfModule.value)
}
val module = if (newPath.nonEmpty) newPath.last.value.toString else newTop
t.notPath match {
case Seq() => ModuleTarget(t.circuit, module)
case Instance(i) +: OfModule(m) +: Seq() => ModuleTarget(t.circuit, module)
case Ref(r) +: components => ReferenceTarget(t.circuit, module, Nil, r, components)
}
}.toSeq
}
}
|