diff options
| -rw-r--r-- | backends/verilog/verilog_backend.cc | 12 | ||||
| -rw-r--r-- | frontends/ast/genrtlil.cc | 18 | ||||
| -rw-r--r-- | frontends/verilog/verilog_lexer.l | 2 | ||||
| -rw-r--r-- | frontends/verilog/verilog_parser.y | 108 | ||||
| -rw-r--r-- | kernel/rtlil.cc | 8 | ||||
| -rw-r--r-- | passes/opt/opt_clean.cc | 24 | ||||
| -rw-r--r-- | tests/various/specify.v | 29 | ||||
| -rw-r--r-- | tests/various/specify.ys | 21 | 
8 files changed, 170 insertions, 52 deletions
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 682c47a1f..19541f1c4 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1417,11 +1417,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)  		decimal = 1;  		f << ", "; -		dump_const(f, cell->getParam("\\T_LIMIT")); +		dump_const(f, cell->getParam("\\T_LIMIT_MIN")); +		f << ": "; +		dump_const(f, cell->getParam("\\T_LIMIT_TYP")); +		f << ": "; +		dump_const(f, cell->getParam("\\T_LIMIT_MAX"));  		if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {  			f << ", "; -			dump_const(f, cell->getParam("\\T_LIMIT2")); +			dump_const(f, cell->getParam("\\T_LIMIT2_MIN")); +			f << ": "; +			dump_const(f, cell->getParam("\\T_LIMIT2_TYP")); +			f << ": "; +			dump_const(f, cell->getParam("\\T_LIMIT2_MAX"));  		}  		f << ");\n"; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 76705c75f..3fb6b3e5c 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1563,21 +1563,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());  				cell->attributes[attr.first] = attr.second->asAttrConst();  			} -			if (cell->type.in("$specify2", "$specify3")) { +			if (cell->type == "$specify2") {  				int src_width = GetSize(cell->getPort("\\SRC"));  				int dst_width = GetSize(cell->getPort("\\DST"));  				bool full = cell->getParam("\\FULL").as_bool();  				if (!full && src_width != dst_width)  					log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n"); -				if (cell->type == "$specify3") { -					int dat_width = GetSize(cell->getPort("\\DAT")); -					if (dat_width != dst_width) -						log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); -				}  				cell->setParam("\\SRC_WIDTH", Const(src_width));  				cell->setParam("\\DST_WIDTH", Const(dst_width));  			} -			if (cell->type == "$specrule") { +			else if (cell->type ==  "$specify3") { +				int dat_width = GetSize(cell->getPort("\\DAT")); +				int dst_width = GetSize(cell->getPort("\\DST")); +				if (dat_width != dst_width) +					log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); +				int src_width = GetSize(cell->getPort("\\SRC")); +				cell->setParam("\\SRC_WIDTH", Const(src_width)); +				cell->setParam("\\DST_WIDTH", Const(dst_width)); +			} +			else if (cell->type == "$specrule") {  				int src_width = GetSize(cell->getPort("\\SRC"));  				int dst_width = GetSize(cell->getPort("\\DST"));  				cell->setParam("\\SRC_WIDTH", Const(src_width)); diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 9b43c250e..18fa2966b 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -440,7 +440,7 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {  }  "&&&" { -	if (!specify_mode) REJECT; +	if (!specify_mode) return TOK_IGNORED_SPECIFY_AND;  	return TOK_SPECIFY_AND;  } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 9001aa162..bb2a10e9a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -160,7 +160,7 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned =  %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC  %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT  %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY -%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND +%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND  %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 @@ -176,9 +176,9 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned =  %type <al> attr case_attr  %type <specify_target_ptr> specify_target -%type <specify_triple_ptr> specify_triple +%type <specify_triple_ptr> specify_triple specify_opt_triple  %type <specify_rise_fall_ptr> specify_rise_fall -%type <ast> specify_if specify_condition specify_opt_arg +%type <ast> specify_if specify_condition  %type <ch> specify_edge  // operator precedence from low to high @@ -873,7 +873,7 @@ specify_item:  		delete target;  		delete timing;  	} | -	TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { +	TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' {  		if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&  				*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")  			frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); @@ -886,8 +886,8 @@ specify_item:  		AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);  		AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); -		AstNode *limit = $11; -		AstNode *limit2 = $12; +		specify_triple *limit = $11; +		specify_triple *limit2 = $12;  		AstNode *cell = new AstNode(AST_CELL);  		ast_stack.back()->children.push_back(cell); @@ -898,11 +898,23 @@ specify_item:  		cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));  		cell->children.back()->str = "\\TYPE"; -		cell->children.push_back(new AstNode(AST_PARASET, limit)); -		cell->children.back()->str = "\\T_LIMIT"; +		cell->children.push_back(new AstNode(AST_PARASET, limit->t_min)); +		cell->children.back()->str = "\\T_LIMIT_MIN"; -		cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true))); -		cell->children.back()->str = "\\T_LIMIT2"; +		cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg)); +		cell->children.back()->str = "\\T_LIMIT_TYP"; + +		cell->children.push_back(new AstNode(AST_PARASET, limit->t_max)); +		cell->children.back()->str = "\\T_LIMIT_MAX"; + +		cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true))); +		cell->children.back()->str = "\\T_LIMIT2_MIN"; + +		cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true))); +		cell->children.back()->str = "\\T_LIMIT2_TYP"; + +		cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true))); +		cell->children.back()->str = "\\T_LIMIT2_MAX";  		cell->children.push_back(new AstNode(AST_PARASET, src_pen));  		cell->children.back()->str = "\\SRC_PEN"; @@ -931,8 +943,8 @@ specify_item:  		delete $1;  	}; -specify_opt_arg: -	',' expr { +specify_opt_triple: +	',' specify_triple {  		$$ = $2;  	} |  	/* empty */ { @@ -1001,7 +1013,46 @@ specify_rise_fall:  		$$->fall = *$4;  		delete $2;  		delete $4; -	}; +	} | +	'(' specify_triple ',' specify_triple ',' specify_triple ')' { +		$$ = new specify_rise_fall; +		$$->rise = *$2; +		$$->fall = *$4; +		delete $2; +		delete $4; +        delete $6; +        log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); +	} | +	'(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { +		$$ = new specify_rise_fall; +		$$->rise = *$2; +		$$->fall = *$4; +		delete $2; +		delete $4; +        delete $6; +        delete $8; +        delete $10; +        delete $12; +        log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); +	} | +	'(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { +		$$ = new specify_rise_fall; +		$$->rise = *$2; +		$$->fall = *$4; +		delete $2; +		delete $4; +        delete $6; +        delete $8; +        delete $10; +        delete $12; +        delete $14; +        delete $16; +        delete $18; +        delete $20; +        delete $22; +        delete $24; +        log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); +	}  specify_triple:  	expr { @@ -1049,7 +1100,7 @@ list_of_specparam_assignments:  	specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;  specparam_assignment: -	ignspec_id '=' constant_mintypmax_expression ; +	ignspec_id '=' ignspec_expr ;  ignspec_opt_cond:  	TOK_IF '(' ignspec_expr ')' | /* empty */; @@ -1066,13 +1117,15 @@ simple_path_declaration :  	;  path_delay_value : -	'(' path_delay_expression list_of_path_delay_extra_expressions ')' -	|     path_delay_expression -	|     path_delay_expression list_of_path_delay_extra_expressions +	'(' ignspec_expr list_of_path_delay_extra_expressions ')' +	|     ignspec_expr +	|     ignspec_expr list_of_path_delay_extra_expressions  	;  list_of_path_delay_extra_expressions : -	',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions; +	',' ignspec_expr +	| ',' ignspec_expr list_of_path_delay_extra_expressions +	;  specify_edge_identifier :  	TOK_POSEDGE | TOK_NEGEDGE ; @@ -1123,16 +1176,9 @@ system_timing_arg :  system_timing_args :  	system_timing_arg | +	system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg |  	system_timing_args ',' system_timing_arg ; -path_delay_expression : -	ignspec_constant_expression; - -constant_mintypmax_expression : -	ignspec_constant_expression -	| ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression -	; -  // for the time being this is OK, but we may write our own expr here.  // as I'm not sure it is legal to use a full expr here (probably not)  // On the other hand, other rules requiring constant expressions also use 'expr' @@ -1141,10 +1187,16 @@ ignspec_constant_expression:  	expr { delete $1; };  ignspec_expr: -	expr { delete $1; }; +	expr { delete $1; } | +	expr ':' expr ':' expr { +		delete $1; +		delete $3; +		delete $5; +	};  ignspec_id: -	TOK_ID { delete $1; }; +	TOK_ID { delete $1; } +	range_or_multirange { delete $3; };  /**********************************************************************/ diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index f286d139f..5d7e61901 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1258,8 +1258,12 @@ namespace {  				param_bool(ID(SRC_POL));  				param_bool(ID(DST_PEN));  				param_bool(ID(DST_POL)); -				param(ID(T_LIMIT)); -				param(ID(T_LIMIT2)); +				param(ID(T_LIMIT_MIN)); +				param(ID(T_LIMIT_TYP)); +				param(ID(T_LIMIT_MAX)); +				param(ID(T_LIMIT2_MIN)); +				param(ID(T_LIMIT2_TYP)); +				param(ID(T_LIMIT2_MAX));  				port(ID(SRC_EN), 1);  				port(ID(DST_EN), 1);  				port(ID(SRC), param(ID(SRC_WIDTH))); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 2f69b3d4c..f5bb40050 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -51,20 +51,26 @@ struct keep_cache_t  		if (cache.count(module))  			return cache.at(module); -		cache[module] = true; -		if (!module->get_bool_attribute(ID::keep)) { -			bool found_keep = false; +		bool found_keep = false; +		if (module->get_bool_attribute(ID::keep)) +			found_keep = true; +		else  			for (auto cell : module->cells()) -				if (query(cell)) found_keep = true; -			cache[module] = found_keep; -		} +				if (query(cell, true /* ignore_specify */)) { +					found_keep = true; +					break; +				} +		cache[module] = found_keep; -		return cache[module]; +		return found_keep;  	} -	bool query(Cell *cell) +	bool query(Cell *cell, bool ignore_specify = false)  	{ -		if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($specify2), ID($specify3), ID($specrule))) +		if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) +			return true; + +		if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule)))  			return true;  		if (cell->has_keep_attr()) diff --git a/tests/various/specify.v b/tests/various/specify.v index 5d44d78f7..c160d2ec4 100644 --- a/tests/various/specify.v +++ b/tests/various/specify.v @@ -7,11 +7,9 @@ module test (  		if (EN) Q <= D;  	specify -`ifndef SKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS  		if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4);  		$setup(D, posedge CLK &&& EN, 5);  		$hold(posedge CLK, D &&& EN, 6); -`endif  	endspecify  endmodule @@ -37,3 +35,30 @@ specify    (posedge clk *> (q +: d)) = (3,1);  endspecify  endmodule + +module test3(input clk, input [1:0] d, output [1:0] q); +specify +  (posedge clk => (q +: d)) = (3,1); +  (posedge clk *> (q +: d)) = (3,1); +endspecify +endmodule + +module test4(input clk, d, output q); +specify +  $setup(d, posedge clk, 1:2:3); +  $setuphold(d, posedge clk, 1:2:3, 4:5:6); +endspecify +endmodule + +module test5(input clk, d, e, output q); +specify +  $setup(d, posedge clk &&& e, 1:2:3); +endspecify +endmodule + +module test6(input clk, d, e, output q); +specify +  (d[0] *> q[0]) = (3,1); +  (posedge clk[0] => (q[0] +: d[0])) = (3,1); +endspecify +endmodule diff --git a/tests/various/specify.ys b/tests/various/specify.ys index 00597e1e2..9d55b8eb5 100644 --- a/tests/various/specify.ys +++ b/tests/various/specify.ys @@ -55,4 +55,23 @@ equiv_induct -seq 5  equiv_status -assert  design -reset -read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v +read_verilog -specify <<EOT +(* blackbox *) +module test7_sub(input i, output o); +specify +    (i => o) = 1; +endspecify +assign o = ~i; +endmodule + +module test7(input i, output o); +    wire w; +    test7_sub unused(i, w); +    test7_sub used(i, o); +endmodule +EOT +hierarchy +cd test7 +clean +select -assert-count 1 c:used +select -assert-none c:* c:used %d  | 
