diff options
Diffstat (limited to 'frontends/verilog')
| -rw-r--r-- | frontends/verilog/verilog_lexer.l | 59 | ||||
| -rw-r--r-- | frontends/verilog/verilog_parser.y | 99 | 
2 files changed, 66 insertions, 92 deletions
| diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e51a12f76..6ef38252a 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -189,57 +189,18 @@ YOSYS_NAMESPACE_END  "always_ff"    { SV_KEYWORD(TOK_ALWAYS); }  "always_latch" { SV_KEYWORD(TOK_ALWAYS); } - /* 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(); + /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex +    to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some +    global state.. its a mess) */ +[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(std::string("\\") + yytext); +	return TOK_SVA_LABEL;  } +"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); }  "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); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 649dd384f..52685f637 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -105,8 +105,8 @@ static void free_attr(std::map<std::string, AstNode*> *al)  	bool boolean;  } -%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE -%token <string> TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER +%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL +%token 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 @@ -126,7 +126,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 <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id  %type <boolean> opt_signed opt_property unique_case_attr  %type <al> attr case_attr @@ -1329,6 +1329,14 @@ opt_label:  		$$ = NULL;  	}; +opt_sva_label: +	TOK_SVA_LABEL ':' { +		$$ = $1; +	} | +	/* empty */ { +		$$ = NULL; +	}; +  opt_property:  	TOK_PROPERTY {  		$$ = true; @@ -1373,11 +1381,11 @@ modport_type_token:      TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}  assert: -	TOK_ASSERT opt_property '(' expr ')' ';' { +	opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {  		if (noassert_mode) { -			delete $4; +			delete $5;  		} else { -			AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4); +			AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);  			if ($1 != nullptr)  				node->str = *$1;  			ast_stack.back()->children.push_back(node); @@ -1385,11 +1393,11 @@ assert:  		if ($1 != nullptr)  			delete $1;  	} | -	TOK_ASSUME opt_property '(' expr ')' ';' { +	opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {  		if (noassume_mode) { -			delete $4; +			delete $5;  		} else { -			AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $4); +			AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);  			if ($1 != nullptr)  				node->str = *$1;  			ast_stack.back()->children.push_back(node); @@ -1397,11 +1405,11 @@ assert:  		if ($1 != nullptr)  			delete $1;  	} | -	TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { +	opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {  		if (noassert_mode) { -			delete $5; +			delete $6;  		} else { -			AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5); +			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); @@ -1409,11 +1417,11 @@ assert:  		if ($1 != nullptr)  			delete $1;  	} | -	TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { +	opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {  		if (noassume_mode) { -			delete $5; +			delete $6;  		} else { -			AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $5); +			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); @@ -1421,15 +1429,15 @@ assert:  		if ($1 != nullptr)  			delete $1;  	} | -	TOK_COVER opt_property '(' expr ')' ';' { -		AstNode *node = new AstNode(AST_COVER, $4); +	opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { +		AstNode *node = new AstNode(AST_COVER, $5);  		if ($1 != nullptr) {  			node->str = *$1;  			delete $1;  		}  		ast_stack.back()->children.push_back(node);  	} | -	TOK_COVER opt_property '(' ')' ';' { +	opt_sva_label TOK_COVER opt_property '(' ')' ';' {  		AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));  		if ($1 != nullptr) {  			node->str = *$1; @@ -1437,7 +1445,7 @@ assert:  		}  		ast_stack.back()->children.push_back(node);  	} | -	TOK_COVER ';' { +	opt_sva_label TOK_COVER ';' {  		AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));  		if ($1 != nullptr) {  			node->str = *$1; @@ -1445,87 +1453,87 @@ assert:  		}  		ast_stack.back()->children.push_back(node);  	} | -	TOK_RESTRICT opt_property '(' expr ')' ';' { +	opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {  		if (norestrict_mode) { -			delete $4; +			delete $5;  		} else { -			AstNode *node = new AstNode(AST_ASSUME, $4); +			AstNode *node = new AstNode(AST_ASSUME, $5);  			if ($1 != nullptr)  				node->str = *$1;  			ast_stack.back()->children.push_back(node);  		} -		if (!$2) +		if (!$3)  			log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");  		if ($1 != nullptr)  			delete $1;  	} | -	TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { +	opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {  		if (norestrict_mode) { -			delete $5; +			delete $6;  		} else { -			AstNode *node = new AstNode(AST_FAIR, $5); +			AstNode *node = new AstNode(AST_FAIR, $6);  			if ($1 != nullptr)  				node->str = *$1;  			ast_stack.back()->children.push_back(node);  		} -		if (!$2) +		if (!$3)  			log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");  		if ($1 != nullptr)  			delete $1;  	};  assert_property: -	TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { -		ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); +	opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));  		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)); +	opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));  		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)); +	opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));  		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)); +	opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));  		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)); +	opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));  		if ($1 != nullptr) {  			ast_stack.back()->children.back()->str = *$1;  			delete $1;  		}  	} | -	TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { +	opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {  		if (norestrict_mode) { -			delete $4; +			delete $5;  		} else { -			ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); +			ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));  			if ($1 != nullptr) {  				ast_stack.back()->children.back()->str = *$1;  				delete $1;  			}  		}  	} | -	TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { +	opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {  		if (norestrict_mode) { -			delete $5; +			delete $6;  		} else { -			ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); +			ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));  			if ($1 != nullptr) {  				ast_stack.back()->children.back()->str = *$1;  				delete $1; @@ -1748,6 +1756,11 @@ case_expr_list:  	TOK_DEFAULT {  		ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));  	} | +	TOK_SVA_LABEL { +		ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); +		ast_stack.back()->children.back()->str = *$1; +		delete $1; +	} |  	expr {  		ast_stack.back()->children.push_back($1);  	} | | 
