Fix false ASSIGNIN on interface input ports driven from outside (#7322)
This commit is contained in:
parent
fbc3b3618d
commit
e0963bd587
|
|
@ -241,6 +241,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
std::map<const AstNode*, const AstClass*>
|
||||
m_containingClassp; // Containing class cache for containingClass() function
|
||||
std::unordered_set<AstVar*> m_aliasedVars; // Variables referenced in alias
|
||||
std::unordered_set<const AstVar*> m_curModVars; // Variables declared in current module
|
||||
|
||||
static constexpr int ENUM_LOOKUP_BITS = 16; // Maximum # bits to make enum lookup table
|
||||
|
||||
|
|
@ -2835,7 +2836,18 @@ class WidthVisitor final : public VNVisitor {
|
|||
&& (!m_ftaskp || !m_ftaskp->isConstructor())
|
||||
&& !VN_IS(m_procedurep, InitialAutomatic) && !VN_IS(m_procedurep, InitialStatic)
|
||||
&& !VN_IS(nodep->abovep(), AssignForce) && !VN_IS(nodep->abovep(), Release)) {
|
||||
nodep->v3warn(ASSIGNIN, "Assigning to input/const variable: " << nodep->prettyNameQ());
|
||||
// Skip ASSIGNIN for continuous assignments to net-type input ports
|
||||
// via hierarchical reference. Net ports allow multiple continuous
|
||||
// drivers (IEEE 1800-2023 23.3.3.3). Input ports default to net
|
||||
// when port kind is omitted (23.2.2.3, PORT type).
|
||||
const bool hierRef = !m_curModVars.count(nodep->varp());
|
||||
const bool netPort
|
||||
= nodep->varp()->isNet() || nodep->varp()->varType() == VVarType::PORT;
|
||||
const bool contAssign = VN_IS(nodep->abovep(), AssignW);
|
||||
if (!(hierRef && netPort && contAssign)) {
|
||||
nodep->v3warn(ASSIGNIN,
|
||||
"Assigning to input/const variable: " << nodep->prettyNameQ());
|
||||
}
|
||||
} else if (nodep->access().isWriteOrRW() && nodep->varp()->isConst() && !m_paramsOnly
|
||||
&& (!m_ftaskp || !m_ftaskp->isConstructor())
|
||||
&& !VN_IS(m_procedurep, InitialAutomatic)
|
||||
|
|
@ -7374,6 +7386,9 @@ class WidthVisitor final : public VNVisitor {
|
|||
} else {
|
||||
VL_RESTORER(m_modep);
|
||||
m_modep = nodep;
|
||||
// Collect local variables for ASSIGNIN hierarchical reference check
|
||||
m_curModVars.clear();
|
||||
nodep->foreach([this](const AstVar* varp) { m_curModVars.insert(varp); });
|
||||
userIterateChildren(nodep, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1437,16 +1437,16 @@ port<nodep>: // ==IEEE: port
|
|||
{ $$ = $3; VARDTYPE($2); VARIOANSI();
|
||||
if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } }
|
||||
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
|
||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||
{ $$ = $4; VARDECL(VAR); VARDTYPE($3); VARIOANSI();
|
||||
addNextNull($$, VARDONEP($$, $5, $6)); }
|
||||
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||
{ $$ = $4; VARDECL(VAR); VARDTYPE($3); VARIOANSI();
|
||||
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||
{ $$ = $4; VARDECL(VAR); VARDTYPE($3); VARIOANSI();
|
||||
addNextNull($$, VARDONEP($$, $5, $6)); }
|
||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||
{ $$ = $4; VARDECL(VAR); VARDTYPE($3); VARIOANSI();
|
||||
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
||||
| portDirNetE signing portSig variable_dimensionListE sigAttrListE
|
||||
{ $$ = $3;
|
||||
|
|
@ -1955,10 +1955,10 @@ port_declaration<nodep>: // ==IEEE: port_declaration
|
|||
/*mid*/ { VARDTYPE($3); }
|
||||
/*cont*/ list_of_variable_decl_assignments { $$ = $5; }
|
||||
| port_directionReset port_declNetE yVAR data_type
|
||||
/*mid*/ { VARDTYPE($4); }
|
||||
/*mid*/ { VARDECL(VAR); VARDTYPE($4); }
|
||||
/*cont*/ list_of_variable_decl_assignments { $$ = $6; }
|
||||
| port_directionReset port_declNetE yVAR implicit_typeE
|
||||
/*mid*/ { VARDTYPE($4); }
|
||||
/*mid*/ { VARDECL(VAR); VARDTYPE($4); }
|
||||
/*cont*/ list_of_variable_decl_assignments { $$ = $6; }
|
||||
| port_directionReset port_declNetE signingE rangeList
|
||||
/*mid*/ { AstNodeDType* const dtp = GRAMMARP->addRange(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(timing_loop=True, verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
// Driving input ports from the instantiating scope via continuous assign
|
||||
// is legal when port kind defaults to net (IEEE 1800-2023 23.2.2.3).
|
||||
// All three forms below default to net for input ports.
|
||||
|
||||
// Scenario 1: bare input (defaults to net)
|
||||
interface bare_if (input clk);
|
||||
logic data;
|
||||
endinterface
|
||||
|
||||
// Scenario 2: input with explicit data type (still net for input)
|
||||
interface logic_if (input logic clk);
|
||||
logic data;
|
||||
endinterface
|
||||
|
||||
// Scenario 3: input with explicit net kind
|
||||
interface wire_if (input wire clk);
|
||||
logic data;
|
||||
endinterface
|
||||
|
||||
module consumer (bare_if cif);
|
||||
logic sampled;
|
||||
always @(posedge cif.clk) sampled <= cif.data;
|
||||
endmodule
|
||||
|
||||
module t;
|
||||
logic clk = 0;
|
||||
always #5 clk = ~clk;
|
||||
integer cyc = 0;
|
||||
|
||||
bare_if bif(.clk());
|
||||
assign bif.clk = clk;
|
||||
assign bif.data = 1'b1;
|
||||
|
||||
logic_if lif(.clk());
|
||||
assign lif.clk = clk;
|
||||
assign lif.data = 1'b1;
|
||||
|
||||
wire_if wif(.clk());
|
||||
assign wif.clk = clk;
|
||||
assign wif.data = 1'b1;
|
||||
|
||||
consumer cons(.cif(bif));
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 10) begin
|
||||
`checkh(bif.clk, clk);
|
||||
`checkh(bif.data, 1'b1);
|
||||
`checkh(lif.clk, clk);
|
||||
`checkh(lif.data, 1'b1);
|
||||
`checkh(wif.clk, clk);
|
||||
`checkh(wif.data, 1'b1);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
%Error-ASSIGNIN: t/t_interface_input_port_assign_bad.v:16:10: Assigning to input/const variable: 'clk'
|
||||
: ... note: In instance 't'
|
||||
16 | assign clk = 1'b0;
|
||||
| ^~~
|
||||
... For error description see https://verilator.org/warn/ASSIGNIN?v=latest
|
||||
%Error-ASSIGNIN: t/t_interface_input_port_assign_bad.v:23:14: Assigning to input/const variable: 'clk'
|
||||
: ... note: In instance 't'
|
||||
23 | assign vif.clk = sig;
|
||||
| ^~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=test.vlt_all, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 PlanV GmbH
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Case 1: Assigning to explicit var input port from OUTSIDE (illegal).
|
||||
// Only 'input var' ports are variable kind (IEEE 1800-2023 23.2.2.3).
|
||||
// Variable input ports cannot be assigned (IEEE 1800-2023 23.3.3.2).
|
||||
interface var_if (input var logic clk);
|
||||
endinterface
|
||||
|
||||
// Case 2: Assigning to net-type input port from INSIDE (illegal).
|
||||
// Internal assign creates a second driver within the port's own scope.
|
||||
interface internal_if (input wire clk);
|
||||
assign clk = 1'b0; // ASSIGNIN: internal assign to net input
|
||||
endinterface
|
||||
|
||||
module t;
|
||||
logic sig;
|
||||
internal_if iif(.clk(sig));
|
||||
var_if vif(.clk());
|
||||
assign vif.clk = sig; // ASSIGNIN: external assign to var input
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_interface_input_port_assign.v"
|
||||
|
||||
test.compile(timing_loop=True, verilator_flags2=['--timing'], v_flags2=['-fno-inline'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -10,11 +10,11 @@
|
|||
]},
|
||||
{"type":"MODULE","name":"mh6","addr":"(K)","loc":"d,26:8,26:11","origName":"mh6","verilogName":"mh6","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"VAR","name":"x_input_var_logic","addr":"(L)","loc":"d,26:23,26:40","dtypep":"(J)","origName":"x_input_var_logic","verilogName":"x_input_var_logic","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
{"type":"VAR","name":"x_input_var_logic","addr":"(L)","loc":"d,26:23,26:40","dtypep":"(J)","origName":"x_input_var_logic","verilogName":"x_input_var_logic","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
]},
|
||||
{"type":"MODULE","name":"mh7","addr":"(M)","loc":"d,28:8,28:11","origName":"mh7","verilogName":"mh7","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"VAR","name":"x_input_var_integer","addr":"(N)","loc":"d,28:31,28:50","dtypep":"(G)","origName":"x_input_var_integer","verilogName":"x_input_var_integer","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"integer","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
{"type":"VAR","name":"x_input_var_integer","addr":"(N)","loc":"d,28:31,28:50","dtypep":"(G)","origName":"x_input_var_integer","verilogName":"x_input_var_integer","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"integer","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
]},
|
||||
{"type":"MODULE","name":"mh8","addr":"(O)","loc":"d,30:8,30:11","origName":"mh8","verilogName":"mh8","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
]},
|
||||
{"type":"MODULE","name":"mh9","addr":"(Q)","loc":"d,32:8,32:11","origName":"mh9","verilogName":"mh9","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"VAR","name":"x_output_var_logic","addr":"(R)","loc":"d,32:24,32:42","dtypep":"(J)","origName":"x_output_var_logic","verilogName":"x_output_var_logic","isPrimaryIO":true,"direction":"OUTPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
{"type":"VAR","name":"x_output_var_logic","addr":"(R)","loc":"d,32:24,32:42","dtypep":"(J)","origName":"x_output_var_logic","verilogName":"x_output_var_logic","isPrimaryIO":true,"direction":"OUTPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
]},
|
||||
{"type":"MODULE","name":"mh10","addr":"(S)","loc":"d,34:8,34:12","origName":"mh10","verilogName":"mh10","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
|
|
@ -42,12 +42,12 @@
|
|||
]},
|
||||
{"type":"MODULE","name":"mh17","addr":"(DB)","loc":"d,50:8,50:12","origName":"mh17","verilogName":"mh17","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"VAR","name":"x_input_var_integer","addr":"(EB)","loc":"d,50:31,50:50","dtypep":"(G)","origName":"x_input_var_integer","verilogName":"x_input_var_integer","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"integer","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"x_input_var_integer","addr":"(EB)","loc":"d,50:31,50:50","dtypep":"(G)","origName":"x_input_var_integer","verilogName":"x_input_var_integer","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"integer","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"y_input_wire_logic","addr":"(FB)","loc":"d,50:57,50:75","dtypep":"(J)","origName":"y_input_wire_logic","verilogName":"y_input_wire_logic","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
]},
|
||||
{"type":"MODULE","name":"mh18","addr":"(GB)","loc":"d,52:8,52:12","origName":"mh18","verilogName":"mh18","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
"stmtsp": [
|
||||
{"type":"VAR","name":"x_output_var_logic","addr":"(HB)","loc":"d,52:24,52:42","dtypep":"(J)","origName":"x_output_var_logic","verilogName":"x_output_var_logic","isPrimaryIO":true,"direction":"OUTPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"x_output_var_logic","addr":"(HB)","loc":"d,52:24,52:42","dtypep":"(J)","origName":"x_output_var_logic","verilogName":"x_output_var_logic","isPrimaryIO":true,"direction":"OUTPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"VAR","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []},
|
||||
{"type":"VAR","name":"y_input_wire_logic","addr":"(IB)","loc":"d,52:50,52:68","dtypep":"(J)","origName":"y_input_wire_logic","verilogName":"y_input_wire_logic","isPrimaryIO":true,"direction":"INPUT","isSigPublic":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}
|
||||
]},
|
||||
{"type":"MODULE","name":"mh19","addr":"(JB)","loc":"d,54:8,54:12","origName":"mh19","verilogName":"mh19","level":1,"timeunit":"1ps","inlinesp": [],
|
||||
|
|
|
|||
Loading…
Reference in New Issue