Also add support for labels on sva module items, fixes #699

Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
Clifford Wolf 2019-03-08 22:53:58 -08:00
parent 5dfc7becca
commit e7a34d342e
2 changed files with 129 additions and 60 deletions

View File

@ -189,10 +189,57 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
/* parse labels on assert, assume, cover, and restrict right here because it's insanley complex
to do it in the parser (because we force the parser too early to reduce when parsing cells..) */
([a-zA-Z_$][a-zA-Z0-9_$]*[ \t\r\n]*:[ \t\r\n]*)?(assert|assume|cover|restrict)/[^a-zA-Z0-9_$\.] {
frontend_verilog_yylval.string = new std::string(yytext);
auto &str = *frontend_verilog_yylval.string;
std::string keyword;
int cursor = 0;
while (1) {
if (cursor == GetSize(str)) {
keyword = str;
delete frontend_verilog_yylval.string;
frontend_verilog_yylval.string = nullptr;
goto sva_without_label;
}
char c = str[cursor];
if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
cursor++;
continue;
}
keyword = str.substr(cursor);
str = "\\" + str.substr(0, cursor);
break;
}
cursor = 0;
while (1) {
log_assert(cursor < GetSize(keyword));
char c = keyword[cursor];
if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != ':') {
keyword = keyword.substr(cursor);
break;
}
cursor++;
}
if (keyword == "assert") { return TOK_ASSERT; }
else if (keyword == "assume") { return TOK_ASSUME; }
else if (keyword == "cover") { return TOK_COVER; }
else if (keyword == "restrict") { return TOK_RESTRICT; }
else log_abort();
sva_without_label:
if (keyword == "assert") { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
else if (keyword == "assume") { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
else if (keyword == "cover") { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
else if (keyword == "restrict") { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
else log_abort();
}
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
@ -303,7 +350,7 @@ supply1 { return TOK_SUPPLY1; }
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_ID;
return TOK_ID;
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {

View File

@ -106,6 +106,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
}
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token <string> TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
%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
@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%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 opt_stmt_label tok_prim_wrapper hierarchical_id
%type <string> opt_label tok_prim_wrapper hierarchical_id
%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
@ -1337,14 +1337,6 @@ opt_property:
$$ = false;
};
opt_stmt_label:
TOK_ID ':' {
$$ = $1;
} |
/* empty */ {
$$ = NULL;
};
modport_stmt:
TOK_MODPORT TOK_ID {
AstNode *modport = new AstNode(AST_MODPORT);
@ -1381,11 +1373,35 @@ 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 ')' ';' {
TOK_ASSERT opt_property '(' expr ')' ';' {
if (noassert_mode) {
delete $4;
} else {
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
TOK_ASSUME opt_property '(' expr ')' ';' {
if (noassume_mode) {
delete $4;
} else {
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $4);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassert_mode) {
delete $5;
} else {
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
@ -1393,11 +1409,11 @@ assert:
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassume_mode) {
delete $5;
} else {
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
@ -1405,39 +1421,15 @@ assert:
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassert_mode) {
delete $6;
} else {
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassume_mode) {
delete $6;
} else {
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
AstNode *node = new AstNode(AST_COVER, $5);
TOK_COVER opt_property '(' expr ')' ';' {
AstNode *node = new AstNode(AST_COVER, $4);
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
TOK_COVER opt_property '(' ')' ';' {
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
@ -1445,7 +1437,7 @@ assert:
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_COVER ';' {
TOK_COVER ';' {
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
@ -1453,30 +1445,30 @@ assert:
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode) {
delete $5;
delete $4;
} else {
AstNode *node = new AstNode(AST_ASSUME, $5);
AstNode *node = new AstNode(AST_ASSUME, $4);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3)
if (!$2)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode) {
delete $6;
delete $5;
} else {
AstNode *node = new AstNode(AST_FAIR, $6);
AstNode *node = new AstNode(AST_FAIR, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3)
if (!$2)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
@ -1485,30 +1477,60 @@ assert:
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
if (norestrict_mode)
if (norestrict_mode) {
delete $4;
else
} else {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
} |
TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
if (norestrict_mode) {
delete $5;
else
} else {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
};
simple_behavioral_stmt: