From 50f86c11b2bb9e561f5a0cf10e053b1aa4918abd Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 08:24:01 +0000 Subject: [PATCH 1/7] sv: Add lexing and parsing of .* (wildcard port conns) Signed-off-by: David Shah --- frontends/verilog/verilog_lexer.l | 2 ++ frontends/verilog/verilog_parser.y | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index ca23df3e8..39520bd51 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -431,6 +431,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } +".*" { return TOK_AUTOCONNECT_ALL; } + [-+]?[=*]> { if (!specify_mode) REJECT; frontend_verilog_yylval.string = new std::string(yytext); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a30935e0a..cb413e13a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -138,7 +138,7 @@ struct specify_rise_fall { %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_AUTOCONNECT_ALL %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH @@ -1580,6 +1580,9 @@ cell_port: node->children.back()->str = *$3; delete $3; free_attr($1); + } | + attr TOK_AUTOCONNECT_ALL { + astbuf2->attributes[ID(autoconnect)] = AstNode::mkconst_int(1, false); }; always_comb_or_latch: From 5df591c02309c086229029808c21ab8721278888 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 09:04:54 +0000 Subject: [PATCH 2/7] hierarchy: Resolve SV wildcard port connections Signed-off-by: David Shah --- frontends/verilog/verilog_parser.y | 2 +- passes/hierarchy/hierarchy.cc | 65 ++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index cb413e13a..5ec8e66a6 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1582,7 +1582,7 @@ cell_port: free_attr($1); } | attr TOK_AUTOCONNECT_ALL { - astbuf2->attributes[ID(autoconnect)] = AstNode::mkconst_int(1, false); + astbuf2->attributes[ID(implicit_port_conns)] = AstNode::mkconst_int(1, false); }; always_comb_or_latch: diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index d8a628448..0704c2651 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod) return NULL; } +// Find a matching wire for an implicit port connection; traversing generate block scope +RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port) +{ + const std::string &cellname = cell->name.str(); + size_t idx = cellname.size(); + while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) { + Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1)); + if (found != nullptr) + return found; + } + return module->wire(port); +} + struct HierarchyPass : public Pass { HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } void help() YS_OVERRIDE @@ -970,6 +983,55 @@ struct HierarchyPass : public Pass { } } + // Process SV implicit port connections + std::set blackbox_derivatives; + std::vector design_modules = design->modules(); + + for (auto module : design_modules) + { + for (auto cell : module->cells()) + { + if (!cell->get_bool_attribute(ID(implicit_port_conns))) + continue; + Module *m = design->module(cell->type); + + if (m == nullptr) + log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n", + RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); + + // Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths + if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { + IdString new_m_name = m->derive(design, cell->parameters, true); + if (new_m_name.empty()) + continue; + if (new_m_name != m->name) { + m = design->module(new_m_name); + blackbox_derivatives.insert(m); + } + } + + auto old_connections = cell->connections(); + for (auto wire : m->wires()) { + // Find ports of the module that aren't explicitly connected + if (!wire->port_input && !wire->port_output) + continue; + if (old_connections.count(wire->name)) + continue; + // Make sure a wire of correct name exists in the parent + Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str()); + if (parent_wire == nullptr) + log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n", + RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); + if (parent_wire->width != wire->width) + log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n", + parent_wire->width, wire->width, + RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); + cell->setPort(wire->name, parent_wire); + } + cell->attributes.erase(ID(implicit_port_conns)); + } + } + if (!nodefaults) { dict> defaults_db; @@ -1000,9 +1062,6 @@ struct HierarchyPass : public Pass { } } - std::set blackbox_derivatives; - std::vector design_modules = design->modules(); - for (auto module : design_modules) { pool wand_wor_index; From a210675d71b30e97bad728d7f418c14ea0eb28ba Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 09:16:37 +0000 Subject: [PATCH 3/7] sv: Add tests for wildcard port connections Signed-off-by: David Shah --- tests/various/sv_implicit_ports.sh | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 tests/various/sv_implicit_ports.sh diff --git a/tests/various/sv_implicit_ports.sh b/tests/various/sv_implicit_ports.sh new file mode 100755 index 000000000..13d39cf8b --- /dev/null +++ b/tests/various/sv_implicit_ports.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +trap 'echo "ERROR in sv_implicit_ports.sh" >&2; exit 1' ERR + +# Simple case +../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <&1 | grep -F "ERROR: No matching wire for implicit port connection \`b' of cell top.add_i (add)." > /dev/null + +# Incorrectly sized wire +((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <&1 | grep -F "ERROR: Width mismatch between wire (7 bits) and port (8 bits) for implicit port connection \`b' of cell top.add_i (add)." > /dev/null From 7e741714df62338a2037d24721ef99ca8a0c6763 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 09:21:35 +0000 Subject: [PATCH 4/7] hierarchy: Correct handling of wildcard port connections with default values Signed-off-by: David Shah --- passes/hierarchy/hierarchy.cc | 21 ++++++++++++++------- tests/various/sv_implicit_ports.sh | 11 +++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 0704c2651..c298a6600 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -983,6 +983,15 @@ struct HierarchyPass : public Pass { } } + // Determine default values + dict> defaults_db; + if (!nodefaults) + { + for (auto module : design->modules()) + for (auto wire : module->wires()) + if (wire->port_input && wire->attributes.count("\\defaultvalue")) + defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue"); + } // Process SV implicit port connections std::set blackbox_derivatives; std::vector design_modules = design->modules(); @@ -1019,6 +1028,11 @@ struct HierarchyPass : public Pass { continue; // Make sure a wire of correct name exists in the parent Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str()); + + // Missing wires are OK when a default value is set + if (!nodefaults && parent_wire == nullptr && defaults_db.count(cell->type) && defaults_db.at(cell->type).count(wire->name)) + continue; + if (parent_wire == nullptr) log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n", RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); @@ -1034,13 +1048,6 @@ struct HierarchyPass : public Pass { if (!nodefaults) { - dict> defaults_db; - - for (auto module : design->modules()) - for (auto wire : module->wires()) - if (wire->port_input && wire->attributes.count("\\defaultvalue")) - defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue"); - for (auto module : design->modules()) for (auto cell : module->cells()) { diff --git a/tests/various/sv_implicit_ports.sh b/tests/various/sv_implicit_ports.sh index 13d39cf8b..2faac2e85 100755 --- a/tests/various/sv_implicit_ports.sh +++ b/tests/various/sv_implicit_ports.sh @@ -54,3 +54,14 @@ module top(input [7:0] a, output [7:0] q); endmodule EOT ) 2>&1 | grep -F "ERROR: Width mismatch between wire (7 bits) and port (8 bits) for implicit port connection \`b' of cell top.add_i (add)." > /dev/null + +# Defaults +../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - < Date: Fri, 22 Nov 2019 12:57:51 +0000 Subject: [PATCH 5/7] sv: More tests for wildcard port connections Signed-off-by: David Shah --- tests/various/sv_implicit_ports.sh | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/various/sv_implicit_ports.sh b/tests/various/sv_implicit_ports.sh index 2faac2e85..9a01447f7 100755 --- a/tests/various/sv_implicit_ports.sh +++ b/tests/various/sv_implicit_ports.sh @@ -65,3 +65,60 @@ module top(input [7:0] a, output [7:0] q); add add_i(.*); endmodule EOT + +# Parameterised module +../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <&1 | grep -F "ERROR: Width mismatch between wire (8 bits) and port (6 bits) for implicit port connection \`q' of cell top.add_i (add)." > /dev/null + +# Mixed implicit and explicit 1 +../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null From 4bfd2ef4f328b4a95918ed3e0d7a7e38406c4ae8 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 15:07:55 +0000 Subject: [PATCH 6/7] sv: Improve handling of wildcard port connections Signed-off-by: David Shah --- frontends/verilog/verilog_lexer.l | 2 +- frontends/verilog/verilog_parser.y | 8 +++++--- passes/hierarchy/hierarchy.cc | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 39520bd51..9b43c250e 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -431,7 +431,7 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } -".*" { return TOK_AUTOCONNECT_ALL; } +".*" { return TOK_WILDCARD_CONNECT; } [-+]?[=*]> { if (!specify_mode) REJECT; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 5ec8e66a6..2c7304cc4 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -138,7 +138,7 @@ struct specify_rise_fall { %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP -%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_AUTOCONNECT_ALL +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH @@ -1581,8 +1581,10 @@ cell_port: delete $3; free_attr($1); } | - attr TOK_AUTOCONNECT_ALL { - astbuf2->attributes[ID(implicit_port_conns)] = AstNode::mkconst_int(1, false); + attr TOK_WILDCARD_CONNECT { + if (!sv_mode) + frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); + astbuf2->attributes[ID(wildcard_port_conns)] = AstNode::mkconst_int(1, false); }; always_comb_or_latch: diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index c298a6600..fa4a8ea29 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -992,7 +992,7 @@ struct HierarchyPass : public Pass { if (wire->port_input && wire->attributes.count("\\defaultvalue")) defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue"); } - // Process SV implicit port connections + // Process SV implicit wildcard port connections std::set blackbox_derivatives; std::vector design_modules = design->modules(); @@ -1000,7 +1000,7 @@ struct HierarchyPass : public Pass { { for (auto cell : module->cells()) { - if (!cell->get_bool_attribute(ID(implicit_port_conns))) + if (!cell->get_bool_attribute(ID(wildcard_port_conns))) continue; Module *m = design->module(cell->type); @@ -1042,7 +1042,7 @@ struct HierarchyPass : public Pass { RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); cell->setPort(wire->name, parent_wire); } - cell->attributes.erase(ID(implicit_port_conns)); + cell->attributes.erase(ID(wildcard_port_conns)); } } From 0488492ad269df9641ab317eac5568353dd61076 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Nov 2019 15:32:46 +0000 Subject: [PATCH 7/7] Update CHANGELOG and README Signed-off-by: David Shah --- CHANGELOG | 1 + README.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 481ba266e..241fba9e8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -55,6 +55,7 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "check -mapped" - Added checking of SystemVerilog always block types (always_comb, always_latch and always_ff) + - Added support for SystemVerilog wildcard port connections (.*) - Added "xilinx_dffopt" pass - Added "scratchpad" pass - Added "abc9 -dff" diff --git a/README.md b/README.md index 77e9410da..327d407f9 100644 --- a/README.md +++ b/README.md @@ -387,6 +387,10 @@ Verilog Attributes and non-standard features according to the type of the always. These are checked for correctness in ``proc_dlatch``. +- The cell attribute ``wildcard_port_conns`` represents wildcard port + connections (SystemVerilog ``.*``). These are resolved to concrete + connections to matching wires in ``hierarchy``. + - In addition to the ``(* ... *)`` attribute syntax, Yosys supports the non-standard ``{* ... *}`` attribute syntax to set default attributes for everything that comes after the ``{* ... *}`` statement. (Reset