mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-03 21:09:12 +00:00 
			
		
		
		
	Merge pull request #864 from YosysHQ/svalabelfix
Fix handling of cases that look like sva labels, fixes #862
This commit is contained in:
		
						commit
						ef48b62cb1
					
				
					 2 changed files with 82 additions and 108 deletions
				
			
		| 
						 | 
				
			
			@ -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); }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,35 +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 ')' ';' {
 | 
			
		||||
		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 ')' ';' {
 | 
			
		||||
	opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
 | 
			
		||||
		if (noassert_mode) {
 | 
			
		||||
			delete $5;
 | 
			
		||||
		} else {
 | 
			
		||||
			AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5);
 | 
			
		||||
			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);
 | 
			
		||||
| 
						 | 
				
			
			@ -1409,11 +1393,11 @@ assert:
 | 
			
		|||
		if ($1 != nullptr)
 | 
			
		||||
			delete $1;
 | 
			
		||||
	} |
 | 
			
		||||
	TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
 | 
			
		||||
	opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
 | 
			
		||||
		if (noassume_mode) {
 | 
			
		||||
			delete $5;
 | 
			
		||||
		} else {
 | 
			
		||||
			AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $5);
 | 
			
		||||
			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);
 | 
			
		||||
| 
						 | 
				
			
			@ -1421,15 +1405,39 @@ assert:
 | 
			
		|||
		if ($1 != nullptr)
 | 
			
		||||
			delete $1;
 | 
			
		||||
	} |
 | 
			
		||||
	TOK_COVER opt_property '(' expr ')' ';' {
 | 
			
		||||
		AstNode *node = new AstNode(AST_COVER, $4);
 | 
			
		||||
	opt_sva_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_sva_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_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);
 | 
			
		||||
	} |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue