aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/verilog/verilog_parser.y
diff options
context:
space:
mode:
authorRupert Swarbrick <rswarbrick@gmail.com>2020-05-21 17:36:29 +0100
committerZachary Snow <zachary.j.snow@gmail.com>2021-07-16 09:31:39 -0400
commit414154dd275b8cf9f0ffa071d12fc20fd6fee503 (patch)
treee5ee5f5f106219322b4b4091a2ec2a6e801ead83 /frontends/verilog/verilog_parser.y
parent2db41375141dd8098edac134e09b962a5b0821ab (diff)
downloadyosys-414154dd275b8cf9f0ffa071d12fc20fd6fee503.tar.gz
yosys-414154dd275b8cf9f0ffa071d12fc20fd6fee503.tar.bz2
yosys-414154dd275b8cf9f0ffa071d12fc20fd6fee503.zip
Add support for parsing the SystemVerilog 'bind' construct
This doesn't do anything useful yet: the patch just adds support for the syntax to the lexer and parser and adds some tests to check the syntax parses properly. This generates AST nodes, but doesn't yet generate RTLIL. Since our existing hierarchical_identifier parser doesn't allow bit selects (so you can't do something like foo[1].bar[2].baz), I've also not added support for a trailing bit select (the "constant_bit_select" non-terminal in "bind_target_instance" in the spec). If we turn out to need this in future, we'll want to augment hierarchical_identifier and its other users too. Note that you can't easily use the BNF from the spec: bind_directive ::= "bind" bind_target_scope [ : bind_target_instance_list] bind_instantiation ; | "bind" bind_target_instance bind_instantiation ; even if you fix the lookahead problem, because code like this matches both branches in the BNF: bind a b b_i (.*); The problem is that 'a' could either be a module name or a degenerate hierarchical reference. This seems to be a genuine syntactic ambiguity, which the spec resolves (p739) by saying that we have to wait until resolution time (the hierarchy pass) and take whatever is defined, treating 'a' as an instance name if it names both an instance and a module. To keep the parser simple, it currently accepts this invalid syntax: bind a.b : c d e (.*); This is invalid because we're in the first branch of the BNF above, so the "a.b" term should match bind_target_scope: a module or interface identifier, not an arbitrary hierarchical identifier. This will fail in the hierarchy pass (when it's implemented in a future patch).
Diffstat (limited to 'frontends/verilog/verilog_parser.y')
-rw-r--r--frontends/verilog/verilog_parser.y77
1 files changed, 74 insertions, 3 deletions
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;