mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Merge pull request #946 from YosysHQ/clifford/specify
Add specify parser
This commit is contained in:
		
						commit
						752553d8e9
					
				
					 19 changed files with 811 additions and 52 deletions
				
			
		
							
								
								
									
										11
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
										
									
									
									
								
							|  | @ -259,11 +259,7 @@ for them: | |||
| 
 | ||||
| - The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types | ||||
| 
 | ||||
| - The ``config`` keyword and library map files | ||||
| 
 | ||||
| - The ``disable``, ``primitive`` and ``specify`` statements | ||||
| 
 | ||||
| - Latched logic (is synthesized as logic with feedback loops) | ||||
| - The ``config`` and ``disable`` keywords and library map files | ||||
| 
 | ||||
| 
 | ||||
| Verilog Attributes and non-standard features | ||||
|  | @ -424,6 +420,11 @@ Verilog Attributes and non-standard features | |||
|   in an unconditional context (only if/case statements on parameters | ||||
|   and constant values). The intended use for this is synthesis-time DRC. | ||||
| 
 | ||||
| - There is limited support for converting specify .. endspecify statements to | ||||
|   special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in | ||||
|   blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this | ||||
|   functionality. (By default specify .. endspecify blocks are ignored.) | ||||
| 
 | ||||
| 
 | ||||
| Non-standard or SystemVerilog features for formal verification | ||||
| ============================================================== | ||||
|  |  | |||
|  | @ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: | |||
| 	} | ||||
| 	f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); | ||||
| 	for (auto &it : cell->parameters) { | ||||
| 		f << stringf("%s  parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str()); | ||||
| 		f << stringf("%s  parameter%s%s %s ", indent.c_str(), | ||||
| 				(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", | ||||
| 				(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", | ||||
| 				it.first.c_str()); | ||||
| 		dump_const(f, it.second); | ||||
| 		f << stringf("\n"); | ||||
| 	} | ||||
|  |  | |||
|  | @ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) | ||||
| void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false) | ||||
| { | ||||
| 	bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0; | ||||
| 	if (width < 0) | ||||
| 		width = data.bits.size() - offset; | ||||
| 	if (width == 0) { | ||||
|  | @ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o | |||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		f << stringf("\""); | ||||
| 		if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) | ||||
| 			f << stringf("\""); | ||||
| 		std::string str = data.decode_string(); | ||||
| 		for (size_t i = 0; i < str.size(); i++) { | ||||
| 			if (str[i] == '\n') | ||||
|  | @ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o | |||
| 			else | ||||
| 				f << str[i]; | ||||
| 		} | ||||
| 		f << stringf("\""); | ||||
| 		if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) | ||||
| 			f << stringf("\""); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -373,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, | |||
| 		else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) | ||||
| 			f << stringf(" 1 "); | ||||
| 		else | ||||
| 			dump_const(f, it->second, -1, 0, false, false, attr2comment); | ||||
| 			dump_const(f, it->second, -1, 0, false, attr2comment); | ||||
| 		f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); | ||||
| 	} | ||||
| } | ||||
|  | @ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) | |||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cell->type.in("$assert", "$assume", "$cover")) | ||||
| 	{ | ||||
| 		f << stringf("%s" "always @* if (", indent.c_str()); | ||||
| 		dump_sigspec(f, cell->getPort("\\EN")); | ||||
| 		f << stringf(") %s(", cell->type.c_str()+1); | ||||
| 		dump_sigspec(f, cell->getPort("\\A")); | ||||
| 		f << stringf(");\n"); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cell->type.in("$specify2", "$specify3")) | ||||
| 	{ | ||||
| 		f << stringf("%s" "specify\n%s  ", indent.c_str(), indent.c_str()); | ||||
| 
 | ||||
| 		SigSpec en = cell->getPort("\\EN"); | ||||
| 		if (en != State::S1) { | ||||
| 			f << stringf("if ("); | ||||
| 			dump_sigspec(f, cell->getPort("\\EN")); | ||||
| 			f << stringf(") "); | ||||
| 		} | ||||
| 
 | ||||
| 		f << "("; | ||||
| 		if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool()) | ||||
| 			f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge "); | ||||
| 
 | ||||
| 		dump_sigspec(f, cell->getPort("\\SRC")); | ||||
| 
 | ||||
| 		f << " "; | ||||
| 		if (cell->getParam("\\SRC_DST_PEN").as_bool()) | ||||
| 			f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-"); | ||||
| 		f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> "); | ||||
| 
 | ||||
| 		if (cell->type == "$specify3") { | ||||
| 			f << "("; | ||||
| 			dump_sigspec(f, cell->getPort("\\DST")); | ||||
| 			f << " "; | ||||
| 			if (cell->getParam("\\DAT_DST_PEN").as_bool()) | ||||
| 				f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-"); | ||||
| 			f << ": "; | ||||
| 			dump_sigspec(f, cell->getPort("\\DAT")); | ||||
| 			f << ")"; | ||||
| 		} else { | ||||
| 			dump_sigspec(f, cell->getPort("\\DST")); | ||||
| 		} | ||||
| 
 | ||||
| 		bool bak_decimal = decimal; | ||||
| 		decimal = 1; | ||||
| 
 | ||||
| 		f << ") = ("; | ||||
| 		dump_const(f, cell->getParam("\\T_RISE_MIN")); | ||||
| 		f << ":"; | ||||
| 		dump_const(f, cell->getParam("\\T_RISE_TYP")); | ||||
| 		f << ":"; | ||||
| 		dump_const(f, cell->getParam("\\T_RISE_MAX")); | ||||
| 		f << ", "; | ||||
| 		dump_const(f, cell->getParam("\\T_FALL_MIN")); | ||||
| 		f << ":"; | ||||
| 		dump_const(f, cell->getParam("\\T_FALL_TYP")); | ||||
| 		f << ":"; | ||||
| 		dump_const(f, cell->getParam("\\T_FALL_MAX")); | ||||
| 		f << ");\n"; | ||||
| 
 | ||||
| 		decimal = bak_decimal; | ||||
| 
 | ||||
| 		f << stringf("%s" "endspecify\n", indent.c_str()); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cell->type == "$specrule") | ||||
| 	{ | ||||
| 		f << stringf("%s" "specify\n%s  ", indent.c_str(), indent.c_str()); | ||||
| 
 | ||||
| 		string spec_type = cell->getParam("\\TYPE").decode_string(); | ||||
| 		f << stringf("%s(", spec_type.c_str()); | ||||
| 
 | ||||
| 		if (cell->getParam("\\SRC_PEN").as_bool()) | ||||
| 			f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge "); | ||||
| 		dump_sigspec(f, cell->getPort("\\SRC")); | ||||
| 
 | ||||
| 		if (cell->getPort("\\SRC_EN") != State::S1) { | ||||
| 			f << " &&& "; | ||||
| 			dump_sigspec(f, cell->getPort("\\SRC_EN")); | ||||
| 		} | ||||
| 
 | ||||
| 		f << ", "; | ||||
| 		if (cell->getParam("\\DST_PEN").as_bool()) | ||||
| 			f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge "); | ||||
| 		dump_sigspec(f, cell->getPort("\\DST")); | ||||
| 
 | ||||
| 		if (cell->getPort("\\DST_EN") != State::S1) { | ||||
| 			f << " &&& "; | ||||
| 			dump_sigspec(f, cell->getPort("\\DST_EN")); | ||||
| 		} | ||||
| 
 | ||||
| 		bool bak_decimal = decimal; | ||||
| 		decimal = 1; | ||||
| 
 | ||||
| 		f << ", "; | ||||
| 		dump_const(f, cell->getParam("\\T_LIMIT")); | ||||
| 
 | ||||
| 		if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") { | ||||
| 			f << ", "; | ||||
| 			dump_const(f, cell->getParam("\\T_LIMIT2")); | ||||
| 		} | ||||
| 
 | ||||
| 		f << ");\n"; | ||||
| 		decimal = bak_decimal; | ||||
| 
 | ||||
| 		f << stringf("%s" "endspecify\n", indent.c_str()); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
 | ||||
| 	// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
 | ||||
| 
 | ||||
|  | @ -1264,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) | |||
| 			if (it != cell->parameters.begin()) | ||||
| 				f << stringf(","); | ||||
| 			f << stringf("\n%s  .%s(", indent.c_str(), id(it->first).c_str()); | ||||
| 			bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; | ||||
| 			dump_const(f, it->second, -1, 0, false, is_signed); | ||||
| 			dump_const(f, it->second); | ||||
| 			f << stringf(")"); | ||||
| 		} | ||||
| 		f << stringf("\n%s" ")", indent.c_str()); | ||||
|  | @ -1312,8 +1426,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) | |||
| 	if (defparam && cell->parameters.size() > 0) { | ||||
| 		for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { | ||||
| 			f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); | ||||
| 			bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; | ||||
| 			dump_const(f, it->second, -1, 0, false, is_signed); | ||||
| 			dump_const(f, it->second); | ||||
| 			f << stringf(";\n"); | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -951,6 +951,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 					continue; | ||||
| 				if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) | ||||
| 					continue; | ||||
| 				if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && | ||||
| 						(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) | ||||
| 					continue; | ||||
| 				blackbox_module = false; | ||||
| 				break; | ||||
| 			} | ||||
|  | @ -1035,6 +1038,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast | |||
| 					child->delete_children(); | ||||
| 					child->children.push_back(AstNode::mkconst_int(0, false, 0)); | ||||
| 					new_children.push_back(child); | ||||
| 				} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && | ||||
| 						(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { | ||||
| 					new_children.push_back(child); | ||||
| 				} else { | ||||
| 					delete child; | ||||
| 				} | ||||
|  |  | |||
|  | @ -1492,10 +1492,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | |||
| 					continue; | ||||
| 				} | ||||
| 				if (child->type == AST_PARASET) { | ||||
| 					int extra_const_flags = 0; | ||||
| 					IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; | ||||
| 					if (child->children[0]->type == AST_REALVALUE) { | ||||
| 						log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", | ||||
| 								log_id(cell), log_id(paraname), child->children[0]->realvalue); | ||||
| 						extra_const_flags = RTLIL::CONST_FLAG_REAL; | ||||
| 						auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); | ||||
| 						strnode->cloneInto(child->children[0]); | ||||
| 						delete strnode; | ||||
|  | @ -1504,6 +1506,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | |||
| 						log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", | ||||
| 								log_id(cell), log_id(paraname)); | ||||
| 					cell->parameters[paraname] = child->children[0]->asParaConst(); | ||||
| 					cell->parameters[paraname].flags |= extra_const_flags; | ||||
| 					continue; | ||||
| 				} | ||||
| 				if (child->type == AST_ARGUMENT) { | ||||
|  | @ -1523,9 +1526,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | |||
| 			} | ||||
| 			for (auto &attr : attributes) { | ||||
| 				if (attr.second->type != AST_CONSTANT) | ||||
| 					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); | ||||
| 					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")) { | ||||
| 				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") { | ||||
| 				int src_width = GetSize(cell->getPort("\\SRC")); | ||||
| 				int dst_width = GetSize(cell->getPort("\\DST")); | ||||
| 				cell->setParam("\\SRC_WIDTH", Const(src_width)); | ||||
| 				cell->setParam("\\DST_WIDTH", Const(dst_width)); | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE | |||
| "attribute"	{ return TOK_ATTRIBUTE; } | ||||
| "parameter"	{ return TOK_PARAMETER; } | ||||
| "signed"	{ return TOK_SIGNED; } | ||||
| "real"		{ return TOK_REAL; } | ||||
| "wire"		{ return TOK_WIRE; } | ||||
| "memory"	{ return TOK_MEMORY; } | ||||
| "width"		{ return TOK_WIDTH; } | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ USING_YOSYS_NAMESPACE | |||
| %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC | ||||
| %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT | ||||
| %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET | ||||
| %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO | ||||
| %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO | ||||
| 
 | ||||
| %type <rsigspec> sigspec_list_reversed | ||||
| %type <sigspec> sigspec sigspec_list | ||||
|  | @ -241,6 +241,12 @@ cell_body: | |||
| 		free($4); | ||||
| 		delete $5; | ||||
| 	} | | ||||
| 	cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { | ||||
| 		current_cell->parameters[$4] = *$5; | ||||
| 		current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; | ||||
| 		free($4); | ||||
| 		delete $5; | ||||
| 	} | | ||||
| 	cell_body TOK_CONNECT TOK_ID sigspec EOL { | ||||
| 		if (current_cell->hasPort($3)) | ||||
| 			rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str()); | ||||
|  |  | |||
|  | @ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend { | |||
| 		log("        delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); | ||||
| 		log("        all modules.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -specify\n"); | ||||
| 		log("        parse and import specify blocks\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -noopt\n"); | ||||
| 		log("        don't perform basic optimizations (such as const folding) in the\n"); | ||||
| 		log("        high-level front-end.\n"); | ||||
|  | @ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend { | |||
| 		bool flag_nooverwrite = false; | ||||
| 		bool flag_overwrite = false; | ||||
| 		bool flag_defer = false; | ||||
| 		bool flag_noblackbox = false; | ||||
| 		bool flag_nowb = false; | ||||
| 		std::map<std::string, std::string> defines_map; | ||||
| 		std::list<std::string> include_dirs; | ||||
| 		std::list<std::string> attributes; | ||||
|  | @ -237,9 +242,8 @@ struct VerilogFrontend : public Frontend { | |||
| 		formal_mode = false; | ||||
| 		norestrict_mode = false; | ||||
| 		assume_asserts_mode = false; | ||||
| 		noblackbox_mode = false; | ||||
| 		lib_mode = false; | ||||
| 		nowb_mode = false; | ||||
| 		specify_mode = false; | ||||
| 		default_nettype_wire = true; | ||||
| 
 | ||||
| 		args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); | ||||
|  | @ -340,7 +344,7 @@ struct VerilogFrontend : public Frontend { | |||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-noblackbox") { | ||||
| 				noblackbox_mode = true; | ||||
| 				flag_noblackbox = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-lib") { | ||||
|  | @ -349,7 +353,11 @@ struct VerilogFrontend : public Frontend { | |||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-nowb") { | ||||
| 				nowb_mode = true; | ||||
| 				flag_nowb = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-specify") { | ||||
| 				specify_mode = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (arg == "-noopt") { | ||||
|  | @ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend { | |||
| 			error_on_dpi_function(current_ast); | ||||
| 
 | ||||
| 		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, | ||||
| 				flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); | ||||
| 				flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); | ||||
| 
 | ||||
| 		if (!flag_nopp) | ||||
| 			delete lexin; | ||||
|  |  | |||
|  | @ -69,14 +69,11 @@ namespace VERILOG_FRONTEND | |||
| 	// running in -assert-assumes mode
 | ||||
| 	extern bool assert_assumes_mode; | ||||
| 
 | ||||
| 	// running in -noblackbox mode
 | ||||
| 	extern bool noblackbox_mode; | ||||
| 
 | ||||
| 	// running in -lib mode
 | ||||
| 	extern bool lib_mode; | ||||
| 
 | ||||
| 	// running in -nowb mode
 | ||||
| 	extern bool nowb_mode; | ||||
| 	// running in -specify mode
 | ||||
| 	extern bool specify_mode; | ||||
| 
 | ||||
| 	// lexer input stream
 | ||||
| 	extern std::istream *lexin; | ||||
|  |  | |||
|  | @ -148,7 +148,7 @@ YOSYS_NAMESPACE_END | |||
| "endfunction"  { return TOK_ENDFUNCTION; } | ||||
| "task"         { return TOK_TASK; } | ||||
| "endtask"      { return TOK_ENDTASK; } | ||||
| "specify"      { return TOK_SPECIFY; } | ||||
| "specify"      { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } | ||||
| "endspecify"   { return TOK_ENDSPECIFY; } | ||||
| "specparam"    { return TOK_SPECPARAM; } | ||||
| "package"      { SV_KEYWORD(TOK_PACKAGE); } | ||||
|  | @ -303,6 +303,12 @@ supply1 { return TOK_SUPPLY1; } | |||
| 	return TOK_ID; | ||||
| } | ||||
| 
 | ||||
| "$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { | ||||
| 	if (!specify_mode) REJECT; | ||||
| 	frontend_verilog_yylval.string = new std::string(yytext); | ||||
| 	return TOK_ID; | ||||
| } | ||||
| 
 | ||||
| "$signed"   { return TOK_TO_SIGNED; } | ||||
| "$unsigned" { return TOK_TO_UNSIGNED; } | ||||
| 
 | ||||
|  | @ -413,6 +419,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { | |||
| "+:" { return TOK_POS_INDEXED; } | ||||
| "-:" { return TOK_NEG_INDEXED; } | ||||
| 
 | ||||
| [-+]?[=*]> { | ||||
| 	if (!specify_mode) REJECT; | ||||
| 	frontend_verilog_yylval.string = new std::string(yytext); | ||||
| 	return TOK_SPECIFY_OPER; | ||||
| } | ||||
| 
 | ||||
| "&&&" { | ||||
| 	if (!specify_mode) REJECT; | ||||
| 	return TOK_SPECIFY_AND; | ||||
| } | ||||
| 
 | ||||
| "/*" { BEGIN(COMMENT); } | ||||
| <COMMENT>.    /* ignore comment body */ | ||||
| <COMMENT>\n   /* ignore comment body */ | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ namespace VERILOG_FRONTEND { | |||
| 	std::vector<char> case_type_stack; | ||||
| 	bool do_not_require_port_stubs; | ||||
| 	bool default_nettype_wire; | ||||
| 	bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; | ||||
| 	bool sv_mode, formal_mode, lib_mode, specify_mode; | ||||
| 	bool noassert_mode, noassume_mode, norestrict_mode; | ||||
| 	bool assume_asserts_mode, assert_assumes_mode; | ||||
| 	bool current_wire_rand, current_wire_const; | ||||
|  | @ -94,6 +94,20 @@ static void free_attr(std::map<std::string, AstNode*> *al) | |||
| 	delete al; | ||||
| } | ||||
| 
 | ||||
| struct specify_target { | ||||
| 	char polarity_op; | ||||
| 	AstNode *dst, *dat; | ||||
| }; | ||||
| 
 | ||||
| struct specify_triple { | ||||
| 	AstNode *t_min, *t_avg, *t_max; | ||||
| }; | ||||
| 
 | ||||
| struct specify_rise_fall { | ||||
| 	specify_triple rise; | ||||
| 	specify_triple fall; | ||||
| }; | ||||
| 
 | ||||
| %} | ||||
| 
 | ||||
| %define api.prefix {frontend_verilog_yy} | ||||
|  | @ -102,10 +116,15 @@ static void free_attr(std::map<std::string, AstNode*> *al) | |||
| 	std::string *string; | ||||
| 	struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; | ||||
| 	std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; | ||||
| 	struct specify_target *specify_target_ptr; | ||||
| 	struct specify_triple *specify_triple_ptr; | ||||
| 	struct specify_rise_fall *specify_rise_fall_ptr; | ||||
| 	bool boolean; | ||||
| 	char ch; | ||||
| } | ||||
| 
 | ||||
| %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL | ||||
| %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE | ||||
| %token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER | ||||
| %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL | ||||
| %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END | ||||
| %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | ||||
|  | @ -116,7 +135,8 @@ static void free_attr(std::map<std::string, AstNode*> *al) | |||
| %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT | ||||
| %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 TOK_ENDSPECIFY TOK_SPECPARAM | ||||
| %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY | ||||
| %token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_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 | ||||
|  | @ -130,6 +150,12 @@ static void free_attr(std::map<std::string, AstNode*> *al) | |||
| %type <boolean> opt_signed opt_property unique_case_attr | ||||
| %type <al> attr case_attr | ||||
| 
 | ||||
| %type <specify_target_ptr> specify_target | ||||
| %type <specify_triple_ptr> specify_triple | ||||
| %type <specify_rise_fall_ptr> specify_rise_fall | ||||
| %type <ast> specify_if specify_condition specify_opt_arg | ||||
| %type <ch> specify_edge | ||||
| 
 | ||||
| // operator precedence from low to high | ||||
| %left OP_LOR | ||||
| %left OP_LAND | ||||
|  | @ -542,7 +568,7 @@ module_body: | |||
| 
 | ||||
| module_body_stmt: | ||||
| 	task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | | ||||
| 	always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; | ||||
| 	always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; | ||||
| 
 | ||||
| checker_decl: | ||||
| 	TOK_CHECKER TOK_ID ';' { | ||||
|  | @ -700,15 +726,254 @@ task_func_body: | |||
| 	task_func_body behavioral_stmt | | ||||
| 	/* empty */; | ||||
| 
 | ||||
| specify_block: | ||||
| 	TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY | | ||||
| 	TOK_SPECIFY TOK_ENDSPECIFY ; | ||||
| /*************************** specify parser ***************************/ | ||||
| 
 | ||||
| specify_item_opt: | ||||
| 	specify_item_opt specify_item | | ||||
| 	specify_item ; | ||||
| specify_block: | ||||
| 	TOK_SPECIFY specify_item_list TOK_ENDSPECIFY; | ||||
| 
 | ||||
| specify_item_list: | ||||
| 	specify_item specify_item_list | | ||||
| 	/* empty */; | ||||
| 
 | ||||
| specify_item: | ||||
| 	specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { | ||||
| 		AstNode *en_expr = $1; | ||||
| 		char specify_edge = $3; | ||||
| 		AstNode *src_expr = $4; | ||||
| 		string *oper = $5; | ||||
| 		specify_target *target = $6; | ||||
| 		specify_rise_fall *timing = $9; | ||||
| 
 | ||||
| 		if (specify_edge != 0 && target->dat == nullptr) | ||||
| 			frontend_verilog_yyerror("Found specify edge but no data spec.\n"); | ||||
| 
 | ||||
| 		AstNode *cell = new AstNode(AST_CELL); | ||||
| 		ast_stack.back()->children.push_back(cell); | ||||
| 		cell->str = stringf("$specify$%d", autoidx++); | ||||
| 		cell->children.push_back(new AstNode(AST_CELLTYPE)); | ||||
| 		cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; | ||||
| 
 | ||||
| 		char oper_polarity = 0; | ||||
| 		char oper_type = oper->at(0); | ||||
| 
 | ||||
| 		if (oper->size() == 3) { | ||||
| 			oper_polarity = oper->at(0); | ||||
| 			oper_type = oper->at(1); | ||||
| 		} | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); | ||||
| 		cell->children.back()->str = "\\FULL"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); | ||||
| 		cell->children.back()->str = "\\SRC_DST_PEN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); | ||||
| 		cell->children.back()->str = "\\SRC_DST_POL"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); | ||||
| 		cell->children.back()->str = "\\T_RISE_MIN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); | ||||
| 		cell->children.back()->str = "\\T_RISE_TYP"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); | ||||
| 		cell->children.back()->str = "\\T_RISE_MAX"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); | ||||
| 		cell->children.back()->str = "\\T_FALL_MIN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); | ||||
| 		cell->children.back()->str = "\\T_FALL_TYP"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); | ||||
| 		cell->children.back()->str = "\\T_FALL_MAX"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); | ||||
| 		cell->children.back()->str = "\\EN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); | ||||
| 		cell->children.back()->str = "\\SRC"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); | ||||
| 		cell->children.back()->str = "\\DST"; | ||||
| 
 | ||||
| 		if (target->dat) | ||||
| 		{ | ||||
| 			cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); | ||||
| 			cell->children.back()->str = "\\EDGE_EN"; | ||||
| 
 | ||||
| 			cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); | ||||
| 			cell->children.back()->str = "\\EDGE_POL"; | ||||
| 
 | ||||
| 			cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); | ||||
| 			cell->children.back()->str = "\\DAT_DST_PEN"; | ||||
| 
 | ||||
| 			cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); | ||||
| 			cell->children.back()->str = "\\DAT_DST_POL"; | ||||
| 
 | ||||
| 			cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); | ||||
| 			cell->children.back()->str = "\\DAT"; | ||||
| 		} | ||||
| 
 | ||||
| 		delete oper; | ||||
| 		delete target; | ||||
| 		delete timing; | ||||
| 	} | | ||||
| 	TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { | ||||
| 		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()); | ||||
| 
 | ||||
| 		AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1); | ||||
| 		AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1); | ||||
| 		AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1); | ||||
| 
 | ||||
| 		AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1); | ||||
| 		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; | ||||
| 
 | ||||
| 		AstNode *cell = new AstNode(AST_CELL); | ||||
| 		ast_stack.back()->children.push_back(cell); | ||||
| 		cell->str = stringf("$specify$%d", autoidx++); | ||||
| 		cell->children.push_back(new AstNode(AST_CELLTYPE)); | ||||
| 		cell->children.back()->str = "$specrule"; | ||||
| 
 | ||||
| 		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, limit2 ? limit2 : AstNode::mkconst_int(0, true))); | ||||
| 		cell->children.back()->str = "\\T_LIMIT2"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, src_pen)); | ||||
| 		cell->children.back()->str = "\\SRC_PEN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, src_pol)); | ||||
| 		cell->children.back()->str = "\\SRC_POL"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, dst_pen)); | ||||
| 		cell->children.back()->str = "\\DST_PEN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_PARASET, dst_pol)); | ||||
| 		cell->children.back()->str = "\\DST_POL"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, src_en)); | ||||
| 		cell->children.back()->str = "\\SRC_EN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); | ||||
| 		cell->children.back()->str = "\\SRC"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en)); | ||||
| 		cell->children.back()->str = "\\DST_EN"; | ||||
| 
 | ||||
| 		cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr)); | ||||
| 		cell->children.back()->str = "\\DST"; | ||||
| 
 | ||||
| 		delete $1; | ||||
| 	}; | ||||
| 
 | ||||
| specify_opt_arg: | ||||
| 	',' expr { | ||||
| 		$$ = $2; | ||||
| 	} | | ||||
| 	/* empty */ { | ||||
| 		$$ = nullptr; | ||||
| 	}; | ||||
| 
 | ||||
| specify_if: | ||||
| 	TOK_IF '(' expr ')' { | ||||
| 		$$ = $3; | ||||
| 	} | | ||||
| 	/* empty */ { | ||||
| 		$$ = nullptr; | ||||
| 	}; | ||||
| 
 | ||||
| specify_condition: | ||||
| 	TOK_SPECIFY_AND expr { | ||||
| 		$$ = $2; | ||||
| 	} | | ||||
| 	/* empty */ { | ||||
| 		$$ = nullptr; | ||||
| 	}; | ||||
| 
 | ||||
| specify_target: | ||||
| 	expr { | ||||
| 		$$ = new specify_target; | ||||
| 		$$->polarity_op = 0; | ||||
| 		$$->dst = $1; | ||||
| 		$$->dat = nullptr; | ||||
| 	} | | ||||
| 	'(' expr ':' expr ')'{ | ||||
| 		$$ = new specify_target; | ||||
| 		$$->polarity_op = 0; | ||||
| 		$$->dst = $2; | ||||
| 		$$->dat = $4; | ||||
| 	} | | ||||
| 	'(' expr TOK_NEG_INDEXED expr ')'{ | ||||
| 		$$ = new specify_target; | ||||
| 		$$->polarity_op = '-'; | ||||
| 		$$->dst = $2; | ||||
| 		$$->dat = $4; | ||||
| 	} | | ||||
| 	'(' expr TOK_POS_INDEXED expr ')'{ | ||||
| 		$$ = new specify_target; | ||||
| 		$$->polarity_op = '+'; | ||||
| 		$$->dst = $2; | ||||
| 		$$->dat = $4; | ||||
| 	}; | ||||
| 
 | ||||
| specify_edge: | ||||
| 	TOK_POSEDGE { $$ = 'p'; } | | ||||
| 	TOK_NEGEDGE { $$ = 'n'; } | | ||||
| 	{ $$ = 0; }; | ||||
| 
 | ||||
| specify_rise_fall: | ||||
| 	specify_triple { | ||||
| 		$$ = new specify_rise_fall; | ||||
| 		$$->rise = *$1; | ||||
| 		$$->fall.t_min = $1->t_min->clone(); | ||||
| 		$$->fall.t_avg = $1->t_avg->clone(); | ||||
| 		$$->fall.t_max = $1->t_max->clone(); | ||||
| 		delete $1; | ||||
| 	} | | ||||
| 	'(' specify_triple ',' specify_triple ')' { | ||||
| 		$$ = new specify_rise_fall; | ||||
| 		$$->rise = *$2; | ||||
| 		$$->fall = *$4; | ||||
| 		delete $2; | ||||
| 		delete $4; | ||||
| 	}; | ||||
| 
 | ||||
| specify_triple: | ||||
| 	expr { | ||||
| 		$$ = new specify_triple; | ||||
| 		$$->t_min = $1; | ||||
| 		$$->t_avg = $1->clone(); | ||||
| 		$$->t_max = $1->clone(); | ||||
| 	} | | ||||
| 	expr ':' expr ':' expr { | ||||
| 		$$ = new specify_triple; | ||||
| 		$$->t_min = $1; | ||||
| 		$$->t_avg = $3; | ||||
| 		$$->t_max = $5; | ||||
| 	}; | ||||
| 
 | ||||
| /******************** ignored specify parser **************************/ | ||||
| 
 | ||||
| ignored_specify_block: | ||||
| 	TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY | | ||||
| 	TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ; | ||||
| 
 | ||||
| ignored_specify_item_opt: | ||||
| 	ignored_specify_item_opt ignored_specify_item | | ||||
| 	ignored_specify_item ; | ||||
| 
 | ||||
| ignored_specify_item: | ||||
| 	specparam_declaration | ||||
| 	// | pulsestyle_declaration | ||||
| 	// | showcancelled_declaration | ||||
|  | @ -724,13 +989,13 @@ specparam_declaration: | |||
| // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 | ||||
| // exxxxtending this for SV specparam would change this anyhow | ||||
| specparam_range: | ||||
| 	'[' constant_expression ':' constant_expression ']' ; | ||||
| 	'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; | ||||
| 
 | ||||
| list_of_specparam_assignments: | ||||
| 	specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; | ||||
| 
 | ||||
| specparam_assignment: | ||||
| 	TOK_ID '=' constant_mintypmax_expression ; | ||||
| 	ignspec_id '=' constant_mintypmax_expression ; | ||||
| 
 | ||||
| /* | ||||
| pulsestyle_declaration : | ||||
|  | @ -805,19 +1070,19 @@ opt_polarity_operator : | |||
| 
 | ||||
| // Good enough for the time being | ||||
| specify_input_terminal_descriptor : | ||||
| 	TOK_ID ; | ||||
| 	ignspec_id ; | ||||
| 
 | ||||
| // Good enough for the time being | ||||
| specify_output_terminal_descriptor : | ||||
| 	TOK_ID ; | ||||
| 	ignspec_id ; | ||||
| 
 | ||||
| system_timing_declaration : | ||||
| 	TOK_ID '(' system_timing_args ')' ';' ; | ||||
| 	ignspec_id '(' system_timing_args ')' ';' ; | ||||
| 
 | ||||
| system_timing_arg : | ||||
| 	TOK_POSEDGE TOK_ID | | ||||
| 	TOK_NEGEDGE TOK_ID | | ||||
| 	expr ; | ||||
| 	TOK_POSEDGE ignspec_id | | ||||
| 	TOK_NEGEDGE ignspec_id | | ||||
| 	ignspec_expr ; | ||||
| 
 | ||||
| system_timing_args : | ||||
| 	system_timing_arg | | ||||
|  | @ -874,19 +1139,27 @@ tzx_path_delay_expression : | |||
| */ | ||||
| 
 | ||||
| path_delay_expression : | ||||
| 	constant_expression; | ||||
| 	ignspec_constant_expression; | ||||
| 
 | ||||
| constant_mintypmax_expression : | ||||
| 	constant_expression | ||||
| 	| constant_expression ':' constant_expression ':' constant_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' | ||||
| // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness | ||||
| constant_expression: | ||||
| 	expr ; | ||||
| ignspec_constant_expression: | ||||
| 	expr { delete $1; }; | ||||
| 
 | ||||
| ignspec_expr: | ||||
| 	expr { delete $1; }; | ||||
| 
 | ||||
| ignspec_id: | ||||
| 	TOK_ID { delete $1; }; | ||||
| 
 | ||||
| /**********************************************************************/ | ||||
| 
 | ||||
| param_signed: | ||||
| 	TOK_SIGNED { | ||||
|  |  | |||
|  | @ -85,6 +85,8 @@ struct CellTypes | |||
| 		setup_internals_eval(); | ||||
| 
 | ||||
| 		IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y"; | ||||
| 		IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT"; | ||||
| 		IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST"; | ||||
| 
 | ||||
| 		setup_type("$tribuf", {A, EN}, {Y}, true); | ||||
| 
 | ||||
|  | @ -99,6 +101,9 @@ struct CellTypes | |||
| 		setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true); | ||||
| 		setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true); | ||||
| 		setup_type("$equiv", {A, B}, {Y}, true); | ||||
| 		setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true); | ||||
| 		setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true); | ||||
| 		setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true); | ||||
| 	} | ||||
| 
 | ||||
| 	void setup_internals_eval() | ||||
|  |  | |||
|  | @ -1194,6 +1194,46 @@ namespace { | |||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			if (cell->type.in("$specify2", "$specify3")) { | ||||
| 				param_bool("\\FULL"); | ||||
| 				param_bool("\\SRC_DST_PEN"); | ||||
| 				param_bool("\\SRC_DST_POL"); | ||||
| 				param("\\T_RISE_MIN"); | ||||
| 				param("\\T_RISE_TYP"); | ||||
| 				param("\\T_RISE_MAX"); | ||||
| 				param("\\T_FALL_MIN"); | ||||
| 				param("\\T_FALL_TYP"); | ||||
| 				param("\\T_FALL_MAX"); | ||||
| 				port("\\EN", 1); | ||||
| 				port("\\SRC", param("\\SRC_WIDTH")); | ||||
| 				port("\\DST", param("\\DST_WIDTH")); | ||||
| 				if (cell->type == "$specify3") { | ||||
| 					param_bool("\\EDGE_EN"); | ||||
| 					param_bool("\\EDGE_POL"); | ||||
| 					param_bool("\\DAT_DST_PEN"); | ||||
| 					param_bool("\\DAT_DST_POL"); | ||||
| 					port("\\DAT", param("\\DST_WIDTH")); | ||||
| 				} | ||||
| 				check_expected(); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			if (cell->type == "$specrule") { | ||||
| 				param("\\TYPE"); | ||||
| 				param_bool("\\SRC_PEN"); | ||||
| 				param_bool("\\SRC_POL"); | ||||
| 				param_bool("\\DST_PEN"); | ||||
| 				param_bool("\\DST_POL"); | ||||
| 				param("\\T_LIMIT"); | ||||
| 				param("\\T_LIMIT2"); | ||||
| 				port("\\SRC_EN", 1); | ||||
| 				port("\\DST_EN", 1); | ||||
| 				port("\\SRC", param("\\SRC_WIDTH")); | ||||
| 				port("\\DST", param("\\DST_WIDTH")); | ||||
| 				check_expected(); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			if (cell->type == "$_BUF_")    { check_gate("AY"); return; } | ||||
| 			if (cell->type == "$_NOT_")    { check_gate("AY"); return; } | ||||
| 			if (cell->type == "$_AND_")    { check_gate("ABY"); return; } | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ namespace RTLIL | |||
| 		CONST_FLAG_NONE   = 0, | ||||
| 		CONST_FLAG_STRING = 1, | ||||
| 		CONST_FLAG_SIGNED = 2,  // only used for parameters
 | ||||
| 		CONST_FLAG_REAL   = 4   // unused -- to be used for parameters
 | ||||
| 		CONST_FLAG_REAL   = 4   // only used for parameters
 | ||||
| 	}; | ||||
| 
 | ||||
| 	struct Const; | ||||
|  |  | |||
|  | @ -465,6 +465,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair} | |||
| {\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. | ||||
| \end{fixme} | ||||
| 
 | ||||
| \begin{fixme} | ||||
| Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells. | ||||
| \end{fixme} | ||||
| 
 | ||||
| \begin{fixme} | ||||
| Add information about {\tt \$slice} and {\tt \$concat} cells. | ||||
| \end{fixme} | ||||
|  |  | |||
|  | @ -64,7 +64,7 @@ struct keep_cache_t | |||
| 
 | ||||
| 	bool query(Cell *cell) | ||||
| 	{ | ||||
| 		if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover")) | ||||
| 		if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule")) | ||||
| 			return true; | ||||
| 
 | ||||
| 		if (cell->has_keep_attr()) | ||||
|  |  | |||
|  | @ -1271,6 +1271,181 @@ endmodule | |||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| module \$specify2 (EN, SRC, DST); | ||||
| 
 | ||||
| parameter FULL = 0; | ||||
| parameter SRC_WIDTH = 1; | ||||
| parameter DST_WIDTH = 1; | ||||
| 
 | ||||
| parameter SRC_DST_PEN = 0; | ||||
| parameter SRC_DST_POL = 0; | ||||
| 
 | ||||
| parameter T_RISE_MIN = 0; | ||||
| parameter T_RISE_TYP = 0; | ||||
| parameter T_RISE_MAX = 0; | ||||
| 
 | ||||
| parameter T_FALL_MIN = 0; | ||||
| parameter T_FALL_TYP = 0; | ||||
| parameter T_FALL_MAX = 0; | ||||
| 
 | ||||
| input EN; | ||||
| input [SRC_WIDTH-1:0] SRC; | ||||
| input [DST_WIDTH-1:0] DST; | ||||
| 
 | ||||
| localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; | ||||
| 
 | ||||
| `ifdef SIMLIB_SPECIFY | ||||
| specify | ||||
| 	if (EN && SD==0 && !FULL) (SRC  => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && SD==0 &&  FULL) (SRC  *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && SD==1 &&  FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && SD==2 &&  FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| endspecify | ||||
| `endif | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| module \$specify3 (EN, SRC, DST, DAT); | ||||
| 
 | ||||
| parameter FULL = 0; | ||||
| parameter SRC_WIDTH = 1; | ||||
| parameter DST_WIDTH = 1; | ||||
| 
 | ||||
| parameter EDGE_EN = 0; | ||||
| parameter EDGE_POL = 0; | ||||
| 
 | ||||
| parameter SRC_DST_PEN = 0; | ||||
| parameter SRC_DST_POL = 0; | ||||
| 
 | ||||
| parameter DAT_DST_PEN = 0; | ||||
| parameter DAT_DST_POL = 0; | ||||
| 
 | ||||
| parameter T_RISE_MIN = 0; | ||||
| parameter T_RISE_TYP = 0; | ||||
| parameter T_RISE_MAX = 0; | ||||
| 
 | ||||
| parameter T_FALL_MIN = 0; | ||||
| parameter T_FALL_TYP = 0; | ||||
| parameter T_FALL_MAX = 0; | ||||
| 
 | ||||
| input EN; | ||||
| input [SRC_WIDTH-1:0] SRC; | ||||
| input [DST_WIDTH-1:0] DST, DAT; | ||||
| 
 | ||||
| localparam ED = EDGE_EN     ? (EDGE_POL    ? 1 : 2) : 0; | ||||
| localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; | ||||
| localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0; | ||||
| 
 | ||||
| `ifdef SIMLIB_SPECIFY | ||||
| specify | ||||
| 	// DD=0 | ||||
| 
 | ||||
| 	if (EN && DD==0 && SD==0 && ED==0 && !FULL) (        SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==0 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==0 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==0 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST  : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	// DD=1 | ||||
| 
 | ||||
| 	if (EN && DD==1 && SD==0 && ED==0 && !FULL) (        SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==1 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==1 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==1 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	// DD=2 | ||||
| 
 | ||||
| 	if (EN && DD==2 && SD==0 && ED==0 && !FULL) (        SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==0 && ED==0 &&  FULL) (        SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==0 && ED==1 &&  FULL) (posedge SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC  => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==0 && ED==2 &&  FULL) (negedge SRC  *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==2 && SD==1 && ED==0 && !FULL) (        SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==1 && ED==0 &&  FULL) (        SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==1 && ED==1 &&  FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==1 && ED==2 &&  FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 
 | ||||
| 	if (EN && DD==2 && SD==2 && ED==0 && !FULL) (        SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==2 && ED==0 &&  FULL) (        SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==2 && ED==1 &&  FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| 	if (EN && DD==2 && SD==2 && ED==2 &&  FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); | ||||
| endspecify | ||||
| `endif | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| module \$specrule (EN_SRC, EN_DST, SRC, DST); | ||||
| 
 | ||||
| parameter TYPE = ""; | ||||
| parameter T_LIMIT = 0; | ||||
| parameter T_LIMIT2 = 0; | ||||
| 
 | ||||
| parameter SRC_WIDTH = 1; | ||||
| parameter DST_WIDTH = 1; | ||||
| 
 | ||||
| parameter SRC_PEN = 0; | ||||
| parameter SRC_POL = 0; | ||||
| 
 | ||||
| parameter DST_PEN = 0; | ||||
| parameter DST_POL = 0; | ||||
| 
 | ||||
| input EN_SRC, EN_DST; | ||||
| input [SRC_WIDTH-1:0] SRC; | ||||
| input [DST_WIDTH-1:0] DST; | ||||
| 
 | ||||
| `ifdef SIMLIB_SPECIFY | ||||
| specify | ||||
| 	// TBD | ||||
| endspecify | ||||
| `endif | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| module \$assert (A, EN); | ||||
| 
 | ||||
| input A, EN; | ||||
|  | @ -1863,4 +2038,5 @@ end | |||
| endmodule | ||||
| 
 | ||||
| `endif | ||||
| 
 | ||||
| // -------------------------------------------------------- | ||||
|  |  | |||
							
								
								
									
										30
									
								
								tests/various/specify.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								tests/various/specify.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| module test ( | ||||
| 	input EN, CLK, | ||||
| 	input [3:0] D, | ||||
| 	output reg [3:0] Q | ||||
| ); | ||||
| 	always @(posedge CLK) | ||||
| 		if (EN) Q <= D; | ||||
| 
 | ||||
| 	specify | ||||
| 		if (EN) (CLK *> (Q : D)) = (1, 2:3:4); | ||||
| 		$setup(D, posedge CLK &&& EN, 5); | ||||
| 		$hold(posedge CLK, D &&& EN, 6); | ||||
| 	endspecify | ||||
| endmodule | ||||
| 
 | ||||
| module test2 ( | ||||
| 	input A, B, | ||||
| 	output Q | ||||
| ); | ||||
| 	xor (Q, A, B); | ||||
| 	specify | ||||
| 		//specparam T_rise = 1; | ||||
| 		//specparam T_fall = 2; | ||||
| 		`define T_rise 1 | ||||
| 		`define T_fall 2 | ||||
| 		(A => Q) = (`T_rise,`T_fall); | ||||
| 		//(B => Q) = (`T_rise+`T_fall)/2.0; | ||||
| 		(B => Q) = 1.5; | ||||
| 	endspecify | ||||
| endmodule | ||||
							
								
								
									
										56
									
								
								tests/various/specify.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								tests/various/specify.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| read_verilog -specify specify.v | ||||
| prep | ||||
| cd test | ||||
| select t:$specify2 -assert-count 0 | ||||
| select t:$specify3 -assert-count 1 | ||||
| select t:$specrule -assert-count 2 | ||||
| cd test2 | ||||
| select t:$specify2 -assert-count 2 | ||||
| select t:$specify3 -assert-count 0 | ||||
| select t:$specrule -assert-count 0 | ||||
| cd | ||||
| write_verilog specify.out | ||||
| design -stash gold | ||||
| 
 | ||||
| read_verilog -specify specify.out | ||||
| prep | ||||
| cd test | ||||
| select t:$specify2 -assert-count 0 | ||||
| select t:$specify3 -assert-count 1 | ||||
| select t:$specrule -assert-count 2 | ||||
| cd test2 | ||||
| select t:$specify2 -assert-count 2 | ||||
| select t:$specify3 -assert-count 0 | ||||
| select t:$specrule -assert-count 0 | ||||
| cd | ||||
| design -stash gate | ||||
| 
 | ||||
| design -copy-from gold -as gold test | ||||
| design -copy-from gate -as gate test | ||||
| rename -hide | ||||
| rename -enumerate -pattern A_% t:$specify3 | ||||
| rename -enumerate -pattern B_% t:$specrule r:TYPE=$setup %i | ||||
| rename -enumerate -pattern C_% t:$specrule r:TYPE=$hold %i | ||||
| select n:A_* -assert-count 2 | ||||
| select n:B_* -assert-count 2 | ||||
| select n:C_* -assert-count 2 | ||||
| equiv_make gold gate equiv | ||||
| hierarchy -top equiv | ||||
| equiv_struct | ||||
| equiv_induct -seq 5 | ||||
| equiv_status -assert | ||||
| design -reset | ||||
| 
 | ||||
| design -copy-from gold -as gold test2 | ||||
| design -copy-from gate -as gate test2 | ||||
| rename -hide | ||||
| rename -enumerate -pattern A_% t:$specify2 r:T_RISE_TYP=1 %i | ||||
| rename -enumerate -pattern B_% t:$specify2 n:A_* %d | ||||
| select n:A_* -assert-count 2 | ||||
| select n:B_* -assert-count 2 | ||||
| equiv_make gold gate equiv | ||||
| hierarchy -top equiv | ||||
| equiv_struct | ||||
| equiv_induct -seq 5 | ||||
| equiv_status -assert | ||||
| design -reset | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue