Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions frontends/verilog/verilog_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@
bool isInLocalScope(const std::string *name);
void rewriteGenForDeclInit(AstNode *loop);
void ensureAsgnExprAllowed(const parser::location_type loc, bool sv_mode);

// for header port renames (.alias(real))
dict<std::string,std::string> port_rename_assigns;
std::vector<std::string> port_rename_wires;

const AstNode *addIncOrDecStmt(std::unique_ptr<dict<IdString, std::unique_ptr<AstNode>>> stmt_attr,
std::unique_ptr<AstNode> lhs,
std::unique_ptr<dict<IdString, std::unique_ptr<AstNode>>> op_attr, AST::AstNodeType op,
Expand Down Expand Up @@ -700,12 +705,31 @@ module:
extra->current_ast_mod = mod;
extra->port_stubs.clear();
extra->port_counter = 0;
extra->port_rename_assigns.clear();
extra->port_rename_wires.clear();
mod->str = *$4;
append_attr(mod, std::move($1));
} module_para_opt module_args_opt TOK_SEMICOL module_body TOK_ENDMODULE opt_label {
if (extra->port_stubs.size() != 0)
err_at_loc(@7, "Missing details for module port `%s'.",
extra->port_stubs.begin()->first.c_str());
err_at_loc(@7, "Missing details for module port `%s'.", extra->port_stubs.begin()->first.c_str());

// inject alias wires and assignments for header renames
for (auto &alias : extra->port_rename_wires) {
auto w = std::make_unique<AstNode>(@7, AST_WIRE);
w->str = alias;
extra->ast_stack.back()->children.push_back(std::move(w));
}
for (auto &kv : extra->port_rename_assigns) {
const std::string &real = kv.first;
const std::string &alias = kv.second;
auto lhs = std::make_unique<AstNode>(@7, AST_IDENTIFIER);
auto rhs = std::make_unique<AstNode>(@7, AST_IDENTIFIER);
lhs->str = alias;
rhs->str = real;
auto asn = std::make_unique<AstNode>(@7, AST_ASSIGN, std::move(lhs), std::move(rhs));
extra->ast_stack.back()->children.push_back(std::move(asn));
}

SET_AST_NODE_LOC(extra->ast_stack.back(), @2, @$);
extra->ast_stack.pop_back();
log_assert(extra->ast_stack.size() == 1);
Expand Down Expand Up @@ -805,6 +829,13 @@ module_arg:
} module_arg_opt_assignment |
TOK_DOT TOK_DOT TOK_DOT {
extra->do_not_require_port_stubs = true;
} |
TOK_DOT TOK_ID TOK_LPAREN TOK_ID TOK_RPAREN {
// header‑side alias: .alias(real)
extra->port_rename_assigns[*$4] = *$2;
extra->port_rename_wires.push_back(*$4);
extra->port_stubs[*$2] = ++extra->port_counter;
extra->port_stubs[*$4] = extra->port_counter;
};

package:
Expand Down Expand Up @@ -2166,7 +2197,22 @@ wire_name:
err_at_loc(@1, "Module port `%s' is neither input nor output.", *$1);
if (node->is_reg && node->is_input && !node->is_output && !mode->sv)
err_at_loc(@1, "Input port `%s' is declared as register.", *$1);

node->port_id = extra->port_stubs[*$1];
// check if there is an alias with same port_id
for (auto it = extra->port_stubs.begin(); it != extra->port_stubs.end(); ) {
if (it->second == node->port_id && it->first != *$1) {
node->str = it->first;
it = extra->port_stubs.erase(it);
// flip mapping for outputs
if (node->is_output) {
extra->port_rename_assigns[node->str] = *$1;
}
break;
} else {
++it;
}
}
extra->port_stubs.erase(*$1);
} else {
if (node->is_input || node->is_output)
Expand Down
22 changes: 22 additions & 0 deletions tests/verilog/port_rename_equivalence.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Equivalence
read_verilog << EOF
module gold(input a, input b, output c);
assign c = a + b;
endmodule

module gate_header (
.a(x),
.b(y),
.c(z)
);
input x;
input y;
output z;

assign z = x + y;
endmodule
EOF

equiv_make gold gate_header equiv_header
equiv_simple
equiv_status -assert
12 changes: 12 additions & 0 deletions tests/verilog/port_rename_error_1.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Multiple names for the same inout port
logger -expect error "Missing details for module port" 1
read_verilog << EOF
module gate_multi_inout (
.i(a),
.o(a)
);
inout a;
endmodule
EOF
logger -check-expected
design -reset
12 changes: 12 additions & 0 deletions tests/verilog/port_rename_error_2.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Multiple names for the same input port
logger -expect error "Missing details for module port" 1
read_verilog << EOF
module gate_multi_inout (
.i(a),
.j(a)
);
input a;
endmodule
EOF
logger -check-expected
design -reset
15 changes: 15 additions & 0 deletions tests/verilog/port_rename_error_3.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Multiple names for an output port
logger -expect error "Missing details for module port" 1
read_verilog << EOF
module gate_multi_output (
a,
.c(b),
.b(b)
);
input a;
output b;
assign b = a;
endmodule
EOF
logger -check-expected
design -reset
16 changes: 16 additions & 0 deletions tests/verilog/port_rename_error_4.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Swapping names for two ports
logger -expect error "not declared in module header" 1
read_verilog << EOF
module gate_swap (
.a(b),
.b(a),
c
);
input a;
input b;
output c;
assign c = a & !b;
endmodule
EOF
logger -check-expected
design -reset
14 changes: 14 additions & 0 deletions tests/verilog/port_rename_error_5.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# ANSI-style renaming
logger -expect error "syntax error" 1
read_verilog << EOF
module gate_ansi (
input .alias_a(a),
output .alias_b(b)
);
wire a;
wire b;
assign b = a;
endmodule
EOF
logger -check-expected
design -reset
14 changes: 14 additions & 0 deletions tests/verilog/port_rename_pass_1.ys
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Partial aliasing
read_verilog << EOF
module gate_swap (
.a(a),
.b(b),
c
);
input a;
input b;
output c;
assign c = a & !b;
endmodule
EOF
design -reset
Loading