aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorSchuyler Eldridge2020-08-01 13:01:44 -0400
committerGitHub2020-08-01 17:01:44 +0000
commit687f3ddbbcd9217542a4bc0e2c256559d2c67a5b (patch)
tree056f4ef5c9f3aabf370599264a47f8831f8d8722 /src/main
parenta82958714c096eefebde16e0491b978135c1757e (diff)
Error on ExtModules w/ same defname, diff. ports (#1734)
* Use signed output in LargeParamExecutionTest Change the Verilog used in LargeParamExecutionTest to match its ExtModule specification. An ExtModule with an SInt port should map to a separate Verilog module with a signed port and this is disjoint from an ExtModule with a UInt port. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com> * Error on ExtModules w/ same defname, diff. ports Adds a high form check to ensure that external modules that have the same defname also have exactly the same ports. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/firrtl/passes/CheckHighForm.scala34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/main/scala/firrtl/passes/CheckHighForm.scala b/src/main/scala/firrtl/passes/CheckHighForm.scala
index fb5dd1ca..3ba2a3db 100644
--- a/src/main/scala/firrtl/passes/CheckHighForm.scala
+++ b/src/main/scala/firrtl/passes/CheckHighForm.scala
@@ -54,6 +54,8 @@ trait CheckHighFormLike { this: Pass =>
s"$info: Repeat definition of module $mname")
class DefnameConflictException(info: Info, mname: String, defname: String) extends PassException(
s"$info: defname $defname of extmodule $mname conflicts with an existing module")
+ class DefnameDifferentPortsException(info: Info, mname: String, defname: String) extends PassException(
+ s"""$info: ports of extmodule $mname with defname $defname are different for an extmodule with the same defname""")
class ModuleNotDefinedException(info: Info, mname: String, name: String) extends PassException(
s"$info: Module $name is not defined.")
class IncorrectNumArgsException(info: Info, mname: String, op: String, n: Int) extends PassException(
@@ -100,9 +102,37 @@ trait CheckHighFormLike { this: Pass =>
m => errors.append(new ModuleNameNotUniqueException(m.info, m.name))
}
+ /** Strip all widths from types */
+ def stripWidth(tpe: Type): Type = tpe match {
+ case a: GroundType => a.mapWidth(_ => UnknownWidth)
+ case a: AggregateType => a.mapType(stripWidth)
+ }
+
+ val extmoduleCollidingPorts = c.modules.collect {
+ case a: ExtModule => a
+ }.groupBy(a => (a.defname, a.params.nonEmpty)).map {
+ /* There are no parameters, so all ports must match exactly. */
+ case (k@ (_, false), a) =>
+ k -> a.map(_.copy(info=NoInfo)).map(_.ports.map(_.copy(info=NoInfo))).toSet
+ /* If there are parameters, then only port names must match because parameters could parameterize widths.
+ * This means that this check cannot produce false positives, but can have false negatives.
+ */
+ case (k@ (_, true), a) =>
+ k -> a.map(_.copy(info=NoInfo)).map(_.ports.map(_.copy(info=NoInfo).mapType(stripWidth))).toSet
+ }.filter(_._2.size > 1)
+
c.modules.collect {
- case ExtModule(info, name, _, defname, _) if (intModuleNames.contains(defname)) =>
- errors.append(new DefnameConflictException(info, name, defname))
+ case a: ExtModule =>
+ a match {
+ case ExtModule(info, name, _, defname, _) if (intModuleNames.contains(defname)) =>
+ errors.append(new DefnameConflictException(info, name, defname))
+ case _ =>
+ }
+ a match {
+ case ExtModule(info, name, _, defname, params) if extmoduleCollidingPorts.contains((defname, params.nonEmpty)) =>
+ errors.append(new DefnameDifferentPortsException(info, name, defname))
+ case _ =>
+ }
}
def checkHighFormPrimop(info: Info, mname: String, e: DoPrim): Unit = {