diff --git a/CHANGELOG.md b/CHANGELOG.md index a367893..5704b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * Fixed module-level localparams being needlessly inlined when forming longest static prefixes, which could cause deep recursion and run out of memory on some designs +* Fixed overzealous removal of explicitly unconnected ports (e.g., `.a()`) * Fixed unneeded scoping of constant function calls used in type lookups * `/*/` is no longer interpreted as a self-closing block comment, e.g., `$display("a"/*/,"b"/* */);` previously printed "ab", but now prints "a" diff --git a/src/Convert/ResolveBindings.hs b/src/Convert/ResolveBindings.hs index a220d3e..e680e75 100644 --- a/src/Convert/ResolveBindings.hs +++ b/src/Convert/ResolveBindings.hs @@ -62,9 +62,13 @@ mapInstance parts (Instance m paramBindings x rs portBindings) = paramBindings' = map checkParam $ resolveBindings (msg "parameter overrides") paramNames paramBindings - portBindings' = filter ((/= Nil) . snd) $ - resolveBindings (msg "port connections") portNames $ - concatMap expandStar portBindings + portBindings' = resolveBindings (msg "port connections") portNames $ + concatMap expandStar $ + -- drop the trailing comma in positional port bindings + if length portNames + 1 == length portBindings + && last portBindings == ("", Nil) + then init portBindings + else portBindings expandStar :: PortBinding -> [PortBinding] expandStar ("*", Nil) = diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 9849d0a..57fe4d7 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -1672,12 +1672,20 @@ missingToken expected = do parseErrorM p $ "missing expected `" ++ expected ++ "`" checkPortBindings :: [PortBinding] -> ParseState [PortBinding] -checkPortBindings [] = return [] +-- empty port bindings should stay empty +checkPortBindings [("", Nil)] = return [] +-- drop the trailing comma in named port bindings +checkPortBindings bindings + | (_ : _, _) <- head bindings + , ("", Nil) <- last bindings + = checkPortBindings' $ init bindings +-- a trailing comma is indistinguishable from an explicit unconnected positional +-- binding, so this is passed-through cleanly and resolved downstream checkPortBindings bindings = - checkBindings "port connections" $ - if last bindings == ("", Nil) - then init bindings - else bindings + checkPortBindings' bindings + +checkPortBindings' :: [PortBinding] -> ParseState [PortBinding] +checkPortBindings' = checkBindings "port connections" checkParamBindings :: [ParamBinding] -> ParseState [ParamBinding] checkParamBindings = checkBindings "parameter overrides" diff --git a/test/error/binding_mix_port_trail.sv b/test/error/binding_mix_port_trail.sv new file mode 100644 index 0000000..c35c84c --- /dev/null +++ b/test/error/binding_mix_port_trail.sv @@ -0,0 +1,9 @@ +// pattern: illegal mix of ordered and named port connections +module example( + input a, b, c +); +endmodule +module top; + wire a, b, c; + example e(.a(1), .b(2), ,); +endmodule