aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--README.md4
-rw-r--r--frontends/verilog/verilog_lexer.l2
-rw-r--r--frontends/verilog/verilog_parser.y7
-rw-r--r--passes/hierarchy/hierarchy.cc76
-rwxr-xr-xtests/various/sv_implicit_ports.sh124
6 files changed, 208 insertions, 6 deletions
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
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index ca23df3e8..9b43c250e 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_WILDCARD_CONNECT; }
+
[-+]?[=*]> {
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..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
+%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
@@ -1580,6 +1580,11 @@ cell_port:
node->children.back()->str = *$3;
delete $3;
free_attr($1);
+ } |
+ 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 d8a628448..fa4a8ea29 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,15 +983,71 @@ struct HierarchyPass : public Pass {
}
}
+ // Determine default values
+ dict<IdString, dict<IdString, Const>> defaults_db;
if (!nodefaults)
{
- dict<IdString, dict<IdString, Const>> 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");
+ }
+ // Process SV implicit wildcard port connections
+ std::set<Module*> blackbox_derivatives;
+ std::vector<Module*> design_modules = design->modules();
+ for (auto module : design_modules)
+ {
+ for (auto cell : module->cells())
+ {
+ if (!cell->get_bool_attribute(ID(wildcard_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());
+
+ // 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));
+ 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(wildcard_port_conns));
+ }
+ }
+
+ if (!nodefaults)
+ {
for (auto module : design->modules())
for (auto cell : module->cells())
{
@@ -1000,9 +1069,6 @@ struct HierarchyPass : public Pass {
}
}
- std::set<Module*> blackbox_derivatives;
- std::vector<Module*> design_modules = design->modules();
-
for (auto module : design_modules)
{
pool<Wire*> wand_wor_index;
diff --git a/tests/various/sv_implicit_ports.sh b/tests/various/sv_implicit_ports.sh
new file mode 100755
index 000000000..9a01447f7
--- /dev/null
+++ b/tests/various/sv_implicit_ports.sh
@@ -0,0 +1,124 @@
+#!/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" - <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+ assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ wire [7:0] b = 8'd42;
+ add add_i(.*);
+endmodule
+EOT
+
+# Generate block
+../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ generate
+ if (1) begin:ablock
+ wire [7:0] b = 8'd42;
+ add add_i(.*);
+ end
+ endgenerate
+endmodule
+EOT
+
+# Missing wire
+((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+ assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ add add_i(.*);
+endmodule
+EOT
+) 2>&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) <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+ assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ wire [6:0] b = 6'd42;
+ add add_i(.*);
+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" - <<EOT
+module add(input [7:0] a = 8'd00, input [7:0] b = 8'd01, output [7:0] q);
+assign q = a + b;
+endmodule
+
+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" - <<EOT
+module add #(parameter N=3) (input [N-1:0] a = 8'd00, input [N-1:0] b = 8'd01, output [N-1:0] q);
+assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ add #(.N(8)) add_i(.*);
+endmodule
+EOT
+
+# Parameterised blackbox module
+../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - <<EOT
+(* blackbox *)
+module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
+endmodule
+
+module top(input [7:0] a, b, output [7:0] q);
+ add #(.N(8)) add_i(.*);
+endmodule
+EOT
+
+# Parameterised blackbox module - incorrect width
+((../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - || true) <<EOT
+(* blackbox *)
+module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
+endmodule
+
+module top(input [7:0] a, b, output [7:0] q);
+ add #(.N(6)) add_i(.*);
+endmodule
+EOT
+) 2>&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" - <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+ assign q = a + b;
+endmodule
+
+module top(input [7:0] a, output [7:0] q);
+ add add_i(.b(8'd42), .*);
+endmodule
+EOT
+
+# Mixed implicit and explicit 2
+(../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
+module add(input [7:0] a, input [7:0] b, output [7:0] q);
+ assign q = a + b;
+endmodule
+
+module top(input [7:0] a, input [9:0] b, output [7:0] q);
+ add add_i(.b, .*);
+endmodule
+EOT
+) 2>&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null