From 687f3ddbbcd9217542a4bc0e2c256559d2c67a5b Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Sat, 1 Aug 2020 13:01:44 -0400 Subject: 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 * 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 Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- src/main/scala/firrtl/passes/CheckHighForm.scala | 34 ++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'src/main') 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 = { -- cgit v1.2.3