aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontends/ast/ast.cc1
-rw-r--r--frontends/ast/ast.h3
-rw-r--r--frontends/ast/genrtlil.cc5
-rw-r--r--frontends/verilog/verilog_lexer.l1
-rw-r--r--frontends/verilog/verilog_parser.y77
-rw-r--r--tests/bind/.gitignore2
-rw-r--r--tests/bind/basic.sv20
-rw-r--r--tests/bind/basic.ys1
-rw-r--r--tests/bind/cell_list.sv26
-rw-r--r--tests/bind/cell_list.ys1
-rw-r--r--tests/bind/hier.sv20
-rw-r--r--tests/bind/hier.ys1
-rw-r--r--tests/bind/inst_list.sv24
-rw-r--r--tests/bind/inst_list.ys1
-rw-r--r--tests/bind/param.sv26
-rw-r--r--tests/bind/param.ys1
-rwxr-xr-xtests/bind/run-test.sh20
-rw-r--r--tests/bind/toplevel.sv20
-rw-r--r--tests/bind/toplevel.ys1
19 files changed, 247 insertions, 4 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index f33b76785..e42cf0348 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -177,6 +177,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_STRUCT)
X(AST_UNION)
X(AST_STRUCT_ITEM)
+ X(AST_BIND)
#undef X
default:
log_abort();
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 60c7de32d..57ce5605f 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -160,7 +160,8 @@ namespace AST
AST_TYPEDEF,
AST_STRUCT,
AST_UNION,
- AST_STRUCT_ITEM
+ AST_STRUCT_ITEM,
+ AST_BIND
};
struct AstSrcLocType {
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 29d0bddef..7fa751e24 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1963,6 +1963,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
} break;
+ case AST_BIND: {
+ // The bind construct. Currently unimplemented: just ignore it.
+ break;
+ }
+
case AST_FCALL: {
if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq")
{
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 55e8b48b9..54fb65240 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -260,6 +260,7 @@ static bool isUserType(std::string &s)
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
+"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 9558b0e87..de463b47d 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -299,6 +299,7 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN
%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN
%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN
+%token TOK_BIND
%type <ast> range range_or_multirange non_opt_range non_opt_multirange
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
@@ -364,6 +365,7 @@ design:
typedef_decl design |
package design |
interface design |
+ bind_directive design |
%empty;
attr:
@@ -636,7 +638,67 @@ interface_body:
interface_body_stmt:
param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
- modport_stmt;
+ modport_stmt | bind_directive;
+
+bind_directive:
+ TOK_BIND {
+ AstNode *bnode = new AstNode(AST_BIND);
+ ast_stack.back()->children.push_back(bnode);
+ ast_stack.push_back(bnode);
+ }
+ bind_target {
+ // bind_target should have added at least one child
+ log_assert(ast_stack.back()->children.size() >= 1);
+ }
+ TOK_ID {
+ // The single_cell parser in cell_list_no_array uses astbuf1 as
+ // a sort of template for constructing cells.
+ astbuf1 = new AstNode(AST_CELL);
+ astbuf1->children.push_back(new AstNode(AST_CELLTYPE));
+ astbuf1->children[0]->str = *$5;
+ delete $5;
+ }
+ cell_parameter_list_opt cell_list_no_array ';' {
+ // cell_list should have added at least one more child
+ log_assert(ast_stack.back()->children.size() >= 2);
+ delete astbuf1;
+ ast_stack.pop_back();
+ };
+
+// bind_target matches the target of the bind (everything before
+// bind_instantiation in the IEEE 1800 spec).
+//
+// We can't use the BNF from the spec directly because it's ambiguous:
+// something like "bind foo bar_i (.*)" can either be interpreted with "foo" as
+// a module or interface identifier (matching bind_target_scope in the spec) or
+// by considering foo as a degenerate hierarchical identifier with no '.'
+// characters, followed by no bit select (which matches bind_target_instance in
+// the spec).
+//
+// Instead, we resolve everything as an instance name and then deal with the
+// ambiguity when converting to RTLIL / in the hierarchy pass.
+bind_target:
+ bind_target_instance opt_bind_target_instance_list;
+
+// An optional list of target instances for a bind statement, introduced by a
+// colon.
+opt_bind_target_instance_list:
+ ':' bind_target_instance_list |
+ %empty;
+
+bind_target_instance_list:
+ bind_target_instance |
+ bind_target_instance_list ',' bind_target_instance;
+
+// A single target instance for a bind statement. The top of ast_stack will be
+// the bind node where we should add it.
+bind_target_instance:
+ hierarchical_id {
+ auto *node = new AstNode(AST_IDENTIFIER);
+ node->str = *$1;
+ delete $1;
+ ast_stack.back()->children.push_back(node);
+ };
mintypmax_expr:
expr { delete $1; } |
@@ -813,7 +875,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
- enum_decl | struct_decl |
+ enum_decl | struct_decl | bind_directive |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
@@ -1975,6 +2037,9 @@ cell_list:
cell_list ',' single_cell;
single_cell:
+ single_cell_no_array | single_cell_arraylist;
+
+single_cell_no_array:
TOK_ID {
astbuf2 = astbuf1->clone();
if (astbuf2->type != AST_PRIMITIVE)
@@ -1983,7 +2048,9 @@ single_cell:
ast_stack.back()->children.push_back(astbuf2);
} '(' cell_port_list ')' {
SET_AST_NODE_LOC(astbuf2, @1, @$);
- } |
+ }
+
+single_cell_arraylist:
TOK_ID non_opt_range {
astbuf2 = astbuf1->clone();
if (astbuf2->type != AST_PRIMITIVE)
@@ -1994,6 +2061,10 @@ single_cell:
SET_AST_NODE_LOC(astbuf2, @1, @$);
};
+cell_list_no_array:
+ single_cell_no_array |
+ cell_list_no_array ',' single_cell_no_array;
+
prim_list:
single_prim |
prim_list ',' single_prim;
diff --git a/tests/bind/.gitignore b/tests/bind/.gitignore
new file mode 100644
index 000000000..8355de9dc
--- /dev/null
+++ b/tests/bind/.gitignore
@@ -0,0 +1,2 @@
+*.log
+run-test.mk
diff --git a/tests/bind/basic.sv b/tests/bind/basic.sv
new file mode 100644
index 000000000..ce0d04c48
--- /dev/null
+++ b/tests/bind/basic.sv
@@ -0,0 +1,20 @@
+// A basic example of the bind construct
+
+module foo (input logic a, input logic b, output logic c);
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ assign c = a ^ b;
+endmodule
+
+module top ();
+ logic u, v, w;
+ foo foo_i (.a (u), .b (v), .c (w));
+
+ bind foo bar bound_i (.*);
+
+ always_comb begin
+ assert(w == u ^ v);
+ end
+endmodule
diff --git a/tests/bind/basic.ys b/tests/bind/basic.ys
new file mode 100644
index 000000000..266fa4e48
--- /dev/null
+++ b/tests/bind/basic.ys
@@ -0,0 +1 @@
+read_verilog -sv basic.sv
diff --git a/tests/bind/cell_list.sv b/tests/bind/cell_list.sv
new file mode 100644
index 000000000..c0da13d29
--- /dev/null
+++ b/tests/bind/cell_list.sv
@@ -0,0 +1,26 @@
+// An example of specifying multiple bind instances in a single directive. This
+// also uses explicit bound names.
+
+module foo (input logic a0, input logic b0, output logic c0,
+ input logic a1, input logic b1, output logic c1);
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ assign c = a ^ b;
+endmodule
+
+module top ();
+ logic u0, v0, w0;
+ logic u1, v1, w1;
+
+ foo foo0 (.a0 (u0), .b0 (v0), .c0 (w0),
+ .a1 (u1), .b1 (v1), .c1 (w1));
+
+ bind foo bar bar0 (.a(a0), .b(b0), .c(c0)), bar1 (.a(a1), .b(b1), .c(c1));
+
+ always_comb begin
+ assert(w0 == u0 ^ v0);
+ assert(w1 == u1 ^ v1);
+ end
+endmodule
diff --git a/tests/bind/cell_list.ys b/tests/bind/cell_list.ys
new file mode 100644
index 000000000..9afd9a941
--- /dev/null
+++ b/tests/bind/cell_list.ys
@@ -0,0 +1 @@
+read_verilog -sv cell_list.sv
diff --git a/tests/bind/hier.sv b/tests/bind/hier.sv
new file mode 100644
index 000000000..fd3bc62b8
--- /dev/null
+++ b/tests/bind/hier.sv
@@ -0,0 +1,20 @@
+// An example of the bind construct using a hierarchical reference starting with $root
+
+module foo (input logic a, input logic b, output logic c);
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ assign c = a ^ b;
+endmodule
+
+module top ();
+ logic u, v, w;
+ foo foo_i (.a (u), .b (v), .c (w));
+
+ always_comb begin
+ assert(w == u ^ v);
+ end
+endmodule
+
+bind $root.top.foo_i bar bound_i (.*);
diff --git a/tests/bind/hier.ys b/tests/bind/hier.ys
new file mode 100644
index 000000000..c19fba100
--- /dev/null
+++ b/tests/bind/hier.ys
@@ -0,0 +1 @@
+read_verilog -sv hier.sv
diff --git a/tests/bind/inst_list.sv b/tests/bind/inst_list.sv
new file mode 100644
index 000000000..e0077caec
--- /dev/null
+++ b/tests/bind/inst_list.sv
@@ -0,0 +1,24 @@
+// An example of specifying multiple bind targets with an instance list
+
+module foo (input logic a, input logic b, output logic c);
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ assign c = a ^ b;
+endmodule
+
+module top ();
+ logic u0, v0, w0;
+ logic u1, v1, w1;
+
+ foo foo0 (.a (u0), .b (v0), .c (w0));
+ foo foo1 (.a (u1), .b (v1), .c (w1));
+
+ bind foo : foo0, foo1 bar bound_i (.*);
+
+ always_comb begin
+ assert(w0 == u0 ^ v0);
+ assert(w1 == u1 ^ v1);
+ end
+endmodule
diff --git a/tests/bind/inst_list.ys b/tests/bind/inst_list.ys
new file mode 100644
index 000000000..ac1385b83
--- /dev/null
+++ b/tests/bind/inst_list.ys
@@ -0,0 +1 @@
+read_verilog -sv inst_list.sv
diff --git a/tests/bind/param.sv b/tests/bind/param.sv
new file mode 100644
index 000000000..c7793527a
--- /dev/null
+++ b/tests/bind/param.sv
@@ -0,0 +1,26 @@
+// An example showing how parameters get inferred when binding
+
+module foo (input logic a, input logic b, output logic c);
+ parameter doit = 1;
+
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ parameter doit = 1;
+
+ assign c = doit ? a ^ b : 0;
+endmodule
+
+module top (input u0, input v0, output w0,
+ input u1, input v1, output w1);
+ foo #(.doit (0)) foo0 (.a (u0), .b (v0), .c (w0));
+ foo #(.doit (1)) foo1 (.a (u1), .b (v1), .c (w1));
+
+ bind foo bar #(.doit (doit)) bound_i (.*);
+
+ always_comb begin
+ assert (w0 == '0);
+ assert (w1 == u1 ^ v1);
+ end
+endmodule
diff --git a/tests/bind/param.ys b/tests/bind/param.ys
new file mode 100644
index 000000000..a43d05759
--- /dev/null
+++ b/tests/bind/param.ys
@@ -0,0 +1 @@
+read_verilog -sv param.sv
diff --git a/tests/bind/run-test.sh b/tests/bind/run-test.sh
new file mode 100755
index 000000000..ea56b70f0
--- /dev/null
+++ b/tests/bind/run-test.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+set -e
+{
+echo "all::"
+for x in *.ys; do
+ echo "all:: run-$x"
+ echo "run-$x:"
+ echo " @echo 'Running $x..'"
+ echo " @../../yosys -ql ${x%.ys}.log $x"
+done
+for s in *.sh; do
+ if [ "$s" != "run-test.sh" ]; then
+ echo "all:: run-$s"
+ echo "run-$s:"
+ echo " @echo 'Running $s..'"
+ echo " @bash $s"
+ fi
+done
+} > run-test.mk
+exec ${MAKE:-make} -f run-test.mk
diff --git a/tests/bind/toplevel.sv b/tests/bind/toplevel.sv
new file mode 100644
index 000000000..328edcf67
--- /dev/null
+++ b/tests/bind/toplevel.sv
@@ -0,0 +1,20 @@
+// The bind construct occurring at top-level in the script
+
+module foo (input logic a, input logic b, output logic c);
+ // Magic happens here...
+endmodule
+
+module bar (input a, input b, output c);
+ assign c = a ^ b;
+endmodule
+
+module top ();
+ logic u, v, w;
+ foo foo_i (.a (u), .b (v), .c (w));
+
+ always_comb begin
+ assert(w == u ^ v);
+ end
+endmodule
+
+bind top.foo_i bar bound_i (.*);
diff --git a/tests/bind/toplevel.ys b/tests/bind/toplevel.ys
new file mode 100644
index 000000000..11c0ada19
--- /dev/null
+++ b/tests/bind/toplevel.ys
@@ -0,0 +1 @@
+read_verilog -sv toplevel.sv