aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/verilog
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/verilog')
-rw-r--r--frontends/verilog/verilog_lexer.l11
-rw-r--r--frontends/verilog/verilog_parser.y169
2 files changed, 145 insertions, 35 deletions
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 83921bf0b..f9118e142 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -135,6 +135,9 @@ YOSYS_NAMESPACE_END
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
}
+"`protect"[^\n]* /* ignore `protect*/
+"`endprotect"[^\n]* /* ignore `endprotect*/
+
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
}
@@ -150,6 +153,9 @@ YOSYS_NAMESPACE_END
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
+"interface" { SV_KEYWORD(TOK_INTERFACE); }
+"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); }
+"modport" { SV_KEYWORD(TOK_MODPORT); }
"parameter" { return TOK_PARAMETER; }
"localparam" { return TOK_LOCALPARAM; }
"defparam" { return TOK_DEFPARAM; }
@@ -295,6 +301,11 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
+[a-zA-Z_$][a-zA-Z0-9_$\.]* {
+ frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
+ return TOK_ID;
+}
+
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
static bool printed_warning = false;
if (!printed_warning) {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 16cac1460..51e112ed3 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -35,6 +35,7 @@
%{
#include <list>
+#include <stack>
#include <string.h>
#include "frontends/verilog/verilog_frontend.h"
#include "kernel/log.h"
@@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
int port_counter;
std::map<std::string, int> port_stubs;
- std::map<std::string, AstNode*> attr_list, default_attr_list;
+ std::map<std::string, AstNode*> *attr_list, default_attr_list;
+ std::stack<std::map<std::string, AstNode*> *> attr_list_stack;
std::map<std::string, AstNode*> *albuf;
std::vector<AstNode*> ast_stack;
struct AstNode *astbuf1, *astbuf2, *astbuf3;
@@ -61,6 +63,7 @@ namespace VERILOG_FRONTEND {
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
+ bool current_modport_input, current_modport_output;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@@ -106,6 +109,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%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
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
@@ -123,7 +127,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id
-%type <boolean> opt_signed unique_case_attr
+%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
// operator precedence from low to high
@@ -168,19 +172,23 @@ design:
param_decl design |
localparam_decl design |
package design |
+ interface design |
/* empty */;
attr:
{
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
- attr_list[it.first] = it.second->clone();
+ (*attr_list)[it.first] = it.second->clone();
} attr_opt {
- std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>;
- al->swap(attr_list);
- $$ = al;
+ $$ = attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
};
attr_opt:
@@ -189,15 +197,20 @@ attr_opt:
defattr:
DEFATTR_BEGIN {
+ if (attr_list != nullptr)
+ attr_list_stack.push(attr_list);
+ attr_list = new std::map<std::string, AstNode*>;
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
- for (auto &it : attr_list)
- delete it.second;
- attr_list.clear();
} opt_attr_list {
- default_attr_list = attr_list;
- attr_list.clear();
+ attr_list->swap(default_attr_list);
+ delete attr_list;
+ if (!attr_list_stack.empty()) {
+ attr_list = attr_list_stack.top();
+ attr_list_stack.pop();
+ } else
+ attr_list = nullptr;
} DEFATTR_END;
opt_attr_list:
@@ -209,15 +222,15 @@ attr_list:
attr_assign:
hierarchical_id {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = AstNode::mkconst_int(1, false);
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = AstNode::mkconst_int(1, false);
delete $1;
} |
hierarchical_id '=' expr {
- if (attr_list.count(*$1) != 0)
- delete attr_list[*$1];
- attr_list[*$1] = $3;
+ if (attr_list->count(*$1) != 0)
+ delete (*attr_list)[*$1];
+ (*attr_list)[*$1] = $3;
delete $1;
};
@@ -302,7 +315,7 @@ module_arg_opt_assignment:
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2));
} else
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value.");
} |
/* empty */;
@@ -320,6 +333,21 @@ module_arg:
}
delete $1;
} module_arg_opt_assignment |
+ TOK_ID {
+ astbuf1 = new AstNode(AST_INTERFACEPORT);
+ astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE));
+ astbuf1->children[0]->str = *$1;
+ delete $1;
+ } TOK_ID { /* SV interfaces */
+ if (!sv_mode)
+ frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str());
+ astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type.
+ astbuf2->str = *$3;
+ delete $3;
+ astbuf2->port_id = ++port_counter;
+ ast_stack.back()->children.push_back(astbuf2);
+ delete astbuf1; // really only needed if multiple instances of same type.
+ } module_arg_opt_assignment |
attr wire_type range TOK_ID {
AstNode *node = $2;
node->str = *$4;
@@ -357,6 +385,33 @@ package_body:
package_body_stmt:
localparam_decl;
+interface:
+ TOK_INTERFACE TOK_ID {
+ do_not_require_port_stubs = false;
+ AstNode *intf = new AstNode(AST_INTERFACE);
+ ast_stack.back()->children.push_back(intf);
+ ast_stack.push_back(intf);
+ current_ast_mod = intf;
+ port_stubs.clear();
+ port_counter = 0;
+ intf->str = *$2;
+ delete $2;
+ } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE {
+ if (port_stubs.size() != 0)
+ frontend_verilog_yyerror("Missing details for module port `%s'.",
+ port_stubs.begin()->first.c_str());
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 1);
+ current_ast_mod = NULL;
+ };
+
+interface_body:
+ interface_body interface_body_stmt |;
+
+interface_body_stmt:
+ param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt |
+ modport_stmt;
+
non_opt_delay:
'#' TOK_ID { delete $2; } |
'#' TOK_CONSTVAL { delete $2; } |
@@ -627,7 +682,7 @@ task_func_port:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -635,7 +690,7 @@ task_func_port:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name | wire_name;
task_func_body:
@@ -838,7 +893,7 @@ param_signed:
param_integer:
TOK_INTEGER {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error in param_integer - should not happen?");
astbuf1->children.push_back(new AstNode(AST_RANGE));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true));
@@ -848,7 +903,7 @@ param_integer:
param_real:
TOK_REAL {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real.");
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
} | /* empty */;
@@ -856,7 +911,7 @@ param_range:
range {
if ($1 != NULL) {
if (astbuf1->children.size() != 1)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/real parameters should not have a range.");
astbuf1->children.push_back($1);
}
};
@@ -885,7 +940,7 @@ single_param_decl:
AstNode *node;
if (astbuf1 == nullptr) {
if (!sv_mode)
- frontend_verilog_yyerror("syntax error");
+ frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword");
node = new AstNode(AST_PARAMETER);
node->children.push_back(AstNode::mkconst_int(0, true));
} else {
@@ -921,7 +976,7 @@ wire_decl:
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions.");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
@@ -929,7 +984,7 @@ wire_decl:
}
}
if (astbuf2 && astbuf2->children.size() != 2)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
} wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
@@ -1023,7 +1078,7 @@ wire_name_and_opt_assign:
wire_name:
TOK_ID range_or_multirange {
if (astbuf1 == nullptr)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node.");
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@@ -1031,7 +1086,7 @@ wire_name:
node->children.push_back(astbuf2->clone());
if ($2 != NULL) {
if (node->is_input || node->is_output)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions.");
if (!astbuf2) {
AstNode *rng = new AstNode(AST_RANGE);
rng->children.push_back(AstNode::mkconst_int(0, true));
@@ -1275,11 +1330,51 @@ opt_label:
};
opt_property:
- TOK_PROPERTY | /* empty */;
+ TOK_PROPERTY {
+ $$ = true;
+ } |
+ /* empty */ {
+ $$ = false;
+ };
opt_stmt_label:
TOK_ID ':' | /* empty */;
+modport_stmt:
+ TOK_MODPORT TOK_ID {
+ AstNode *modport = new AstNode(AST_MODPORT);
+ ast_stack.back()->children.push_back(modport);
+ ast_stack.push_back(modport);
+ modport->str = *$2;
+ delete $2;
+ } modport_args_opt {
+ ast_stack.pop_back();
+ log_assert(ast_stack.size() == 2);
+ } ';'
+
+modport_args_opt:
+ '(' ')' | '(' modport_args optional_comma ')';
+
+modport_args:
+ modport_arg | modport_args ',' modport_arg;
+
+modport_arg:
+ modport_type_token modport_member |
+ modport_member
+
+modport_member:
+ TOK_ID {
+ AstNode *modport_member = new AstNode(AST_MODPORTMEMBER);
+ ast_stack.back()->children.push_back(modport_member);
+ modport_member->str = *$1;
+ modport_member->is_input = current_modport_input;
+ modport_member->is_output = current_modport_output;
+ delete $1;
+ }
+
+modport_type_token:
+ TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
+
assert:
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
if (noassert_mode)
@@ -1319,12 +1414,16 @@ assert:
delete $5;
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
} |
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
delete $6;
else
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
+ if (!$3)
+ log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
};
assert_property:
@@ -1398,7 +1497,7 @@ behavioral_stmt:
node->str = *$3;
} behavioral_stmt_list TOK_END opt_label {
if ($3 != NULL && $7 != NULL && *$3 != *$7)
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1);
if ($3 != NULL)
delete $3;
if ($7 != NULL)
@@ -1714,7 +1813,7 @@ basic_expr:
} |
'(' expr ')' TOK_CONSTVAL {
if ($4->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str());
AstNode *bits = $2;
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);
if (val == NULL)
@@ -1724,7 +1823,7 @@ basic_expr:
} |
hierarchical_id TOK_CONSTVAL {
if ($2->substr(0, 1) != "'")
- frontend_verilog_yyerror("Syntax error.");
+ frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str());
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode);