diff options
Diffstat (limited to 'frontends')
| -rw-r--r-- | frontends/ast/ast.h | 2 | ||||
| -rw-r--r-- | frontends/ast/simplify.cc | 311 | ||||
| -rw-r--r-- | frontends/ilang/.gitignore | 4 | ||||
| -rw-r--r-- | frontends/ilang/Makefile.inc | 19 | ||||
| -rw-r--r-- | frontends/rpc/rpc_frontend.cc | 2 | ||||
| -rw-r--r-- | frontends/rtlil/.gitignore | 4 | ||||
| -rw-r--r-- | frontends/rtlil/Makefile.inc | 19 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_frontend.cc (renamed from frontends/ilang/ilang_frontend.cc) | 61 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_frontend.h (renamed from frontends/ilang/ilang_frontend.h) | 22 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_lexer.l (renamed from frontends/ilang/ilang_lexer.l) | 24 | ||||
| -rw-r--r-- | frontends/rtlil/rtlil_parser.y (renamed from frontends/ilang/ilang_parser.y) | 42 | ||||
| -rw-r--r-- | frontends/verific/verific.cc | 255 | 
12 files changed, 564 insertions, 201 deletions
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 9a5aa15f9..203b50021 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -250,7 +250,7 @@ namespace AST  		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()  		bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);  		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); -		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map); +		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map, bool original_scope = true);  		void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);  		void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,  				dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 66f22e113..153a42e19 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -89,7 +89,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  				case 'S':  				case 'd':  				case 'D': -					if (got_len) +					if (got_len && len_value != 0)  						goto unsupported_format;  					YS_FALLTHROUGH  				case 'x': @@ -110,6 +110,12 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  						goto unsupported_format;  					break; +				case 'l': +				case 'L': +					if (got_len) +						goto unsupported_format; +					break; +  				default:  				unsupported_format:  					log_file_error(filename, location.first_line, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); @@ -155,6 +161,11 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  					sout += log_id(current_module->name);  					break; +				case 'l': +				case 'L': +					sout += log_id(current_module->name); +					break; +  				default:  					log_abort();  			} @@ -380,31 +391,66 @@ static int size_packed_struct(AstNode *snode, int base_offset)  static AstNode *node_int(int ival)  { -	// maybe mkconst_int should have default values for the common integer case -	return AstNode::mkconst_int(ival, true, 32); +	return AstNode::mkconst_int(ival, true); +} + +static AstNode *multiply_by_const(AstNode *expr_node, int stride) +{ +	return new AstNode(AST_MUL, expr_node, node_int(stride));  } -static AstNode *offset_indexed_range(int offset_right, int stride, AstNode *left_expr, AstNode *right_expr) +static AstNode *offset_indexed_range(int offset, int stride, AstNode *left_expr, AstNode *right_expr)  {  	// adjust the range expressions to add an offset into the struct  	// and maybe index using an array stride  	auto left  = left_expr->clone();  	auto right = right_expr->clone(); -	if (stride == 1) { -		// just add the offset -		left  = new AstNode(AST_ADD, node_int(offset_right), left); -		right = new AstNode(AST_ADD, node_int(offset_right), right); +	if (stride > 1) { +		// newleft = (left + 1) * stride - 1 +		left  = new AstNode(AST_SUB, multiply_by_const(new AstNode(AST_ADD, left, node_int(1)), stride), node_int(1)); +		// newright = right * stride +		right = multiply_by_const(right, stride); +	} +	// add the offset +	if (offset) { +		left  = new AstNode(AST_ADD, node_int(offset), left); +		right = new AstNode(AST_ADD, node_int(offset), right); +	} +	return new AstNode(AST_RANGE, left, right); +} + +static AstNode *make_struct_index_range(AstNode *node, AstNode *rnode, int stride, int offset) +{ +	// generate a range node to perform either bit or array indexing +	if (rnode->children.size() == 1) { +		// index e.g. s.a[i] +		return offset_indexed_range(offset, stride, rnode->children[0], rnode->children[0]); +	} +	else if (rnode->children.size() == 2) { +		// slice e.g. s.a[i:j] +		return offset_indexed_range(offset, stride, rnode->children[0], rnode->children[1]);  	}  	else { -		// newleft = offset_right - 1 + (left + 1) * stride -		left  = new AstNode(AST_ADD, new AstNode(AST_SUB, node_int(offset_right), node_int(1)), -				new AstNode(AST_MUL, node_int(stride), new AstNode(AST_ADD, left, node_int(1)))); -		// newright = offset_right + right * stride -		right = new AstNode(AST_ADD, node_int(offset_right), new AstNode(AST_MUL, right, node_int(stride))); +		struct_op_error(node);  	} +} + +static AstNode *slice_range(AstNode *rnode, AstNode *snode) +{ +	// apply the bit slice indicated by snode to the range rnode +	log_assert(rnode->type==AST_RANGE); +	auto left  = rnode->children[0]; +	auto right = rnode->children[1]; +	log_assert(snode->type==AST_RANGE); +	auto slice_left  = snode->children[0]; +	auto slice_right = snode->children[1]; +	auto width = new AstNode(AST_SUB, slice_left->clone(), slice_right->clone()); +	right = new AstNode(AST_ADD, right->clone(), slice_right->clone()); +	left  = new AstNode(AST_ADD, right->clone(), width);  	return new AstNode(AST_RANGE, left, right);  } +  static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node)  {  	// Work out the range in the packed array that corresponds to a struct member @@ -414,27 +460,26 @@ static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node)  	int range_right = member_node->range_right;  	if (node->children.empty()) {  		// no range operations apply, return the whole width +		return make_range(range_left, range_right);  	} -	else if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { -		auto rnode = node->children[0]; -		int stride = get_struct_array_width(member_node); -		if (rnode->children.size() == 1) { -			// index e.g. s.a[i] -			return offset_indexed_range(range_right, stride, rnode->children[0], rnode->children[0]); -		} -		else if (rnode->children.size() == 2) { -			// slice e.g. s.a[i:j] -			return offset_indexed_range(range_right, stride, rnode->children[0], rnode->children[1]); -		} -		else { -			struct_op_error(node); -		} +	int stride = get_struct_array_width(member_node); +	if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { +		// bit or array indexing e.g. s.a[2] or s.a[1:0] +		return make_struct_index_range(node, node->children[0], stride, range_right); +	} +	else if (node->children.size() == 1 && node->children[0]->type == AST_MULTIRANGE) { +		// multirange, i.e. bit slice after array index, e.g. s.a[i][p:q] +		log_assert(stride > 1); +		auto mrnode = node->children[0]; +		auto element_range = make_struct_index_range(node, mrnode->children[0], stride, range_right); +		// then apply bit slice range +		auto range = slice_range(element_range, mrnode->children[1]); +		delete element_range; +		return range;  	}  	else { -		// TODO multirange, i.e. bit slice after array index s.a[i][p:q]  		struct_op_error(node);  	} -	return make_range(range_left, range_right);  }  static void add_members_to_scope(AstNode *snode, std::string name) @@ -1478,7 +1523,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)  		{ -			if (GetSize(children[0]->children) < i) +			if (GetSize(children[0]->children) <= i)  				log_file_error(filename, location.first_line, "Insufficient number of array indices for %s.\n", log_id(str));  			AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); @@ -1563,6 +1608,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_IDENTIFIER) {  		if (current_scope.count(str) == 0) {  			AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; +			const std::string& mod_scope = current_scope_ast->str; +			if (str[0] == '\\' && str.substr(0, mod_scope.size()) == mod_scope) { +				std::string new_str = "\\" + str.substr(mod_scope.size() + 1); +				if (current_scope.count(new_str)) { +					str = new_str; +				} +			}  			for (auto node : current_scope_ast->children) {  				//log("looking at mod scope child %s\n", type2str(node->type).c_str());  				switch (node->type) { @@ -1807,7 +1859,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			if (type == AST_GENFOR) {  				for (size_t i = 0; i < buf->children.size(); i++) { -					buf->children[i]->simplify(false, false, false, stage, -1, false, false); +					buf->children[i]->simplify(const_fold, false, false, stage, -1, false, false);  					current_ast_mod->children.push_back(buf->children[i]);  				}  			} else { @@ -1883,7 +1935,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		}  		for (size_t i = 0; i < children.size(); i++) { -			children[i]->simplify(false, false, false, stage, -1, false, false); +			children[i]->simplify(const_fold, false, false, stage, -1, false, false);  			current_ast_mod->children.push_back(children[i]);  		} @@ -1920,7 +1972,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			}  			for (size_t i = 0; i < buf->children.size(); i++) { -				buf->children[i]->simplify(false, false, false, stage, -1, false, false); +				buf->children[i]->simplify(const_fold, false, false, stage, -1, false, false);  				current_ast_mod->children.push_back(buf->children[i]);  			} @@ -1999,7 +2051,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			}  			for (size_t i = 0; i < buf->children.size(); i++) { -				buf->children[i]->simplify(false, false, false, stage, -1, false, false); +				buf->children[i]->simplify(const_fold, false, false, stage, -1, false, false);  				current_ast_mod->children.push_back(buf->children[i]);  			} @@ -3052,7 +3104,7 @@ skip_dynamic_range_lvalue_expansion:;  			bool all_args_const = true;  			for (auto child : children) {  				while (child->simplify(true, false, false, 1, -1, false, true)) { } -				if (child->type != AST_CONSTANT) +				if (child->type != AST_CONSTANT && child->type != AST_REALVALUE)  					all_args_const = false;  			} @@ -3177,14 +3229,15 @@ skip_dynamic_range_lvalue_expansion:;  				if (wire_cache.count(child->str))  				{  					wire = wire_cache.at(child->str); -					if (wire->children.empty()) { +					bool contains_value = wire->type == AST_LOCALPARAM; +					if (wire->children.size() == contains_value) {  						for (auto c : child->children)  							wire->children.push_back(c->clone());  					} else if (!child->children.empty()) {  						while (child->simplify(true, false, false, stage, -1, false, false)) { } -						if (GetSize(child->children) == GetSize(wire->children)) { +						if (GetSize(child->children) == GetSize(wire->children) - contains_value) {  							for (int i = 0; i < GetSize(child->children); i++) -								if (*child->children.at(i) != *wire->children.at(i)) +								if (*child->children.at(i) != *wire->children.at(i + contains_value))  									goto tcall_incompatible_wires;  						} else {  					tcall_incompatible_wires: @@ -3711,8 +3764,11 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  }  // annotate the names of all wires and other named objects in a generate block -void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) +void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map, bool original_scope)  { +	// `original_scope` defaults to false, and is used to prevent the premature +	// prefixing of items in named sub-blocks +  	if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) {  		if (children.empty()) {  			current_scope[index_var]->children[0]->cloneInto(this); @@ -3725,53 +3781,85 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma  		}  	} -	if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) && name_map.count(str) > 0) -		str = name_map[str]; +	if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) { +		if (name_map.count(str) > 0) { +			str = name_map[str]; +		} else { +			// remap the prefix of this ident if it is a local generate scope +			size_t pos = str.rfind('.'); +			if (pos != std::string::npos) { +				std::string existing_prefix = str.substr(0, pos); +				if (name_map.count(existing_prefix) > 0) { +					str = name_map[existing_prefix] + str.substr(pos); +				} +			} +		} +	}  	std::map<std::string, std::string> backup_name_map; +	auto prefix_node = [&](AstNode* child) { +		if (backup_name_map.size() == 0) +			backup_name_map = name_map; + +		// if within a nested scope +		if (!original_scope) { +			// this declaration shadows anything in the parent scope(s) +			name_map[child->str] = child->str; +			return; +		} + +		std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; +		size_t pos = child->str.rfind('.'); +		if (pos == std::string::npos) +			pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0; +		else +			pos = pos + 1; +		new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos); +		if (new_name[0] != '$' && new_name[0] != '\\') +			new_name = prefix[0] + new_name; + +		name_map[child->str] = new_name; +		if (child->type == AST_FUNCTION) +			replace_result_wire_name_in_function(child, child->str, new_name); +		else +			child->str = new_name; +		current_scope[new_name] = child; +	}; +  	for (size_t i = 0; i < children.size(); i++) {  		AstNode *child = children[i]; -		if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || -				child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF || child->type == AST_ENUM_ITEM) { -			if (backup_name_map.size() == 0) -				backup_name_map = name_map; -			std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; -			size_t pos = child->str.rfind('.'); -			if (pos == std::string::npos) -				pos = child->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0; -			else -				pos = pos + 1; -			new_name = child->str.substr(0, pos) + new_name + child->str.substr(pos); -			if (new_name[0] != '$' && new_name[0] != '\\') -				new_name = prefix[0] + new_name; -			name_map[child->str] = new_name; -			if (child->type == AST_FUNCTION) -				replace_result_wire_name_in_function(child, child->str, new_name); -			else -				child->str = new_name; -			current_scope[new_name] = child; -		} -		if (child->type == AST_ENUM){ + +		switch (child->type) { +		case AST_WIRE: +		case AST_MEMORY: +		case AST_PARAMETER: +		case AST_LOCALPARAM: +		case AST_FUNCTION: +		case AST_TASK: +		case AST_CELL: +		case AST_TYPEDEF: +		case AST_ENUM_ITEM: +		case AST_GENVAR: +			prefix_node(child); +			break; + +		case AST_BLOCK: +		case AST_GENBLOCK: +			if (!child->str.empty()) +				prefix_node(child); +			break; + +		case AST_ENUM:  			current_scope[child->str] = child;  			for (auto enode : child->children){  				log_assert(enode->type == AST_ENUM_ITEM); -				if (backup_name_map.size() == 0) -					backup_name_map = name_map; -				std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix; -				size_t pos = enode->str.rfind('.'); -				if (pos == std::string::npos) -					pos = enode->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0; -				else -					pos = pos + 1; -				new_name = enode->str.substr(0, pos) + new_name + enode->str.substr(pos); -				if (new_name[0] != '$' && new_name[0] != '\\') -					new_name = prefix[0] + new_name; -				name_map[enode->str] = new_name; - -				enode->str = new_name; -				current_scope[new_name] = enode; +				prefix_node(enode);  			} +			break; + +		default: +			break;  		}  	} @@ -3781,8 +3869,14 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma  		// still needs to recursed-into  		if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)  			continue; -		if (child->type != AST_FUNCTION && child->type != AST_TASK) -			child->expand_genblock(index_var, prefix, name_map); +		// functions/tasks may reference wires, constants, etc. in this scope +		if (child->type == AST_FUNCTION || child->type == AST_TASK) +			child->expand_genblock(index_var, prefix, name_map, false); +		// continue prefixing if this child block is anonymous +		else if (child->type == AST_GENBLOCK || child->type == AST_BLOCK) +			child->expand_genblock(index_var, prefix, name_map, original_scope && child->str.empty()); +		else +			child->expand_genblock(index_var, prefix, name_map, original_scope);  	} @@ -4370,27 +4464,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  	size_t argidx = 0;  	for (auto child : children)  	{ -		if (child->type == AST_WIRE) -		{ -			while (child->simplify(true, false, false, 1, -1, false, true)) { } -			if (!child->range_valid) -				log_file_error(child->filename, child->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n", -						child->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column); -			variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); -			variables[child->str].offset = min(child->range_left, child->range_right); -			variables[child->str].is_signed = child->is_signed; -			if (child->is_input && argidx < fcall->children.size()) -				variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size()); -			backup_scope[child->str] = current_scope[child->str]; -			current_scope[child->str] = child; -			continue; -		} -  		block->children.push_back(child->clone());  	} -	log_assert(variables.count(str) != 0); -  	while (!block->children.empty())  	{  		AstNode *stmt = block->children.front(); @@ -4402,6 +4478,47 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  		stmt->dumpAst(NULL, "stmt> ");  #endif +		if (stmt->type == AST_WIRE) +		{ +			while (stmt->simplify(true, false, false, 1, -1, false, true)) { } +			if (!stmt->range_valid) +				log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n", +						stmt->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column); +			variables[stmt->str].val = RTLIL::Const(RTLIL::State::Sx, abs(stmt->range_left - stmt->range_right)+1); +			variables[stmt->str].offset = min(stmt->range_left, stmt->range_right); +			variables[stmt->str].is_signed = stmt->is_signed; +			if (stmt->is_input && argidx < fcall->children.size()) { +				int width = variables[stmt->str].val.bits.size(); +				auto* arg_node = fcall->children.at(argidx++); +				if (arg_node->type == AST_CONSTANT) { +					variables[stmt->str].val = arg_node->bitsAsConst(width); +				} else { +					log_assert(arg_node->type == AST_REALVALUE); +					variables[stmt->str].val = arg_node->realAsConst(width); +				} +			} +			if (!backup_scope.count(stmt->str)) +				backup_scope[stmt->str] = current_scope[stmt->str]; +			current_scope[stmt->str] = stmt; + +			block->children.erase(block->children.begin()); +			continue; +		} + +		log_assert(variables.count(str) != 0); + +		if (stmt->type == AST_LOCALPARAM) +		{ +			while (stmt->simplify(true, false, false, 1, -1, false, true)) { } + +			if (!backup_scope.count(stmt->str)) +				backup_scope[stmt->str] = current_scope[stmt->str]; +			current_scope[stmt->str] = stmt; + +			block->children.erase(block->children.begin()); +			continue; +		} +  		if (stmt->type == AST_ASSIGN_EQ)  		{  			if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 && diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore deleted file mode 100644 index f586b33c7..000000000 --- a/frontends/ilang/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -ilang_lexer.cc -ilang_parser.output -ilang_parser.tab.cc -ilang_parser.tab.hh diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc deleted file mode 100644 index 6f1f0e8fc..000000000 --- a/frontends/ilang/Makefile.inc +++ /dev/null @@ -1,19 +0,0 @@ - -GENFILES += frontends/ilang/ilang_parser.tab.cc -GENFILES += frontends/ilang/ilang_parser.tab.hh -GENFILES += frontends/ilang/ilang_parser.output -GENFILES += frontends/ilang/ilang_lexer.cc - -frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y -	$(Q) mkdir -p $(dir $@) -	$(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $< - -frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc - -frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l -	$(Q) mkdir -p $(dir $@) -	$(P) flex -o frontends/ilang/ilang_lexer.cc $< - -OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o -OBJS += frontends/ilang/ilang_frontend.o - diff --git a/frontends/rpc/rpc_frontend.cc b/frontends/rpc/rpc_frontend.cc index 6d72cbff5..5a40001cb 100644 --- a/frontends/rpc/rpc_frontend.cc +++ b/frontends/rpc/rpc_frontend.cc @@ -378,7 +378,7 @@ struct RpcFrontend : public Pass {  		log("    -> {\"method\": \"derive\", \"module\": \"<module-name\">, \"parameters\": {\n");  		log("        \"<param-name>\": {\"type\": \"[unsigned|signed|string|real]\",\n");  		log("                           \"value\": \"<param-value>\"}, ...}}\n"); -		log("    <- {\"frontend\": \"[ilang|verilog|...]\",\"source\": \"<source>\"}}\n"); +		log("    <- {\"frontend\": \"[rtlil|verilog|...]\",\"source\": \"<source>\"}}\n");  		log("    <- {\"error\": \"<error-message>\"}\n");  		log("        request for the module <module-name> to be derived for a specific set of\n");  		log("        parameters. <param-name> starts with \\ for named parameters, and with $\n"); diff --git a/frontends/rtlil/.gitignore b/frontends/rtlil/.gitignore new file mode 100644 index 000000000..d4a322756 --- /dev/null +++ b/frontends/rtlil/.gitignore @@ -0,0 +1,4 @@ +rtlil_lexer.cc +rtlil_parser.output +rtlil_parser.tab.cc +rtlil_parser.tab.hh diff --git a/frontends/rtlil/Makefile.inc b/frontends/rtlil/Makefile.inc new file mode 100644 index 000000000..d0c0cfcf8 --- /dev/null +++ b/frontends/rtlil/Makefile.inc @@ -0,0 +1,19 @@ + +GENFILES += frontends/rtlil/rtlil_parser.tab.cc +GENFILES += frontends/rtlil/rtlil_parser.tab.hh +GENFILES += frontends/rtlil/rtlil_parser.output +GENFILES += frontends/rtlil/rtlil_lexer.cc + +frontends/rtlil/rtlil_parser.tab.cc: frontends/rtlil/rtlil_parser.y +	$(Q) mkdir -p $(dir $@) +	$(P) $(BISON) -o $@ -d -r all -b frontends/rtlil/rtlil_parser $< + +frontends/rtlil/rtlil_parser.tab.hh: frontends/rtlil/rtlil_parser.tab.cc + +frontends/rtlil/rtlil_lexer.cc: frontends/rtlil/rtlil_lexer.l +	$(Q) mkdir -p $(dir $@) +	$(P) flex -o frontends/rtlil/rtlil_lexer.cc $< + +OBJS += frontends/rtlil/rtlil_parser.tab.o frontends/rtlil/rtlil_lexer.o +OBJS += frontends/rtlil/rtlil_frontend.o + diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 973e62f2c..00c34175e 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -18,30 +18,30 @@   *  ---   *   *  A very simple and straightforward frontend for the RTLIL text - *  representation (as generated by the 'ilang' backend). + *  representation.   *   */ -#include "ilang_frontend.h" +#include "rtlil_frontend.h"  #include "kernel/register.h"  #include "kernel/log.h" -void rtlil_frontend_ilang_yyerror(char const *s) +void rtlil_frontend_yyerror(char const *s)  { -	YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s); +	YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s);  }  YOSYS_NAMESPACE_BEGIN -struct IlangFrontend : public Frontend { -	IlangFrontend() : Frontend("ilang", "read modules from ilang file") { } +struct RTLILFrontend : public Frontend { +	RTLILFrontend() : Frontend("rtlil", "read modules from RTLIL file") { }  	void help() override  	{  		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|  		log("\n"); -		log("    read_ilang [filename]\n"); +		log("    read_rtlil [filename]\n");  		log("\n"); -		log("Load modules from an ilang file to the current design. (ilang is a text\n"); +		log("Load modules from an RTLIL file to the current design. (RTLIL is a text\n");  		log("representation of a design in yosys's internal format.)\n");  		log("\n");  		log("    -nooverwrite\n"); @@ -58,27 +58,27 @@ struct IlangFrontend : public Frontend {  	}  	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override  	{ -		ILANG_FRONTEND::flag_nooverwrite = false; -		ILANG_FRONTEND::flag_overwrite = false; -		ILANG_FRONTEND::flag_lib = false; +		RTLIL_FRONTEND::flag_nooverwrite = false; +		RTLIL_FRONTEND::flag_overwrite = false; +		RTLIL_FRONTEND::flag_lib = false; -		log_header(design, "Executing ILANG frontend.\n"); +		log_header(design, "Executing RTLIL frontend.\n");  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) {  			std::string arg = args[argidx];  			if (arg == "-nooverwrite") { -				ILANG_FRONTEND::flag_nooverwrite = true; -				ILANG_FRONTEND::flag_overwrite = false; +				RTLIL_FRONTEND::flag_nooverwrite = true; +				RTLIL_FRONTEND::flag_overwrite = false;  				continue;  			}  			if (arg == "-overwrite") { -				ILANG_FRONTEND::flag_nooverwrite = false; -				ILANG_FRONTEND::flag_overwrite = true; +				RTLIL_FRONTEND::flag_nooverwrite = false; +				RTLIL_FRONTEND::flag_overwrite = true;  				continue;  			}  			if (arg == "-lib") { -				ILANG_FRONTEND::flag_lib = true; +				RTLIL_FRONTEND::flag_lib = true;  				continue;  			}  			break; @@ -87,12 +87,27 @@ struct IlangFrontend : public Frontend {  		log("Input filename: %s\n", filename.c_str()); -		ILANG_FRONTEND::lexin = f; -		ILANG_FRONTEND::current_design = design; -		rtlil_frontend_ilang_yydebug = false; -		rtlil_frontend_ilang_yyrestart(NULL); -		rtlil_frontend_ilang_yyparse(); -		rtlil_frontend_ilang_yylex_destroy(); +		RTLIL_FRONTEND::lexin = f; +		RTLIL_FRONTEND::current_design = design; +		rtlil_frontend_yydebug = false; +		rtlil_frontend_yyrestart(NULL); +		rtlil_frontend_yyparse(); +		rtlil_frontend_yylex_destroy(); +	} +} RTLILFrontend; + +struct IlangFrontend : public Frontend { +	IlangFrontend() : Frontend("ilang", "(deprecated) alias of read_rtlil") { } +	void help() override +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("See `help read_rtlil`.\n"); +		log("\n"); +	} +	void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override +	{ +		RTLILFrontend.execute(f, filename, args, design);  	}  } IlangFrontend; diff --git a/frontends/ilang/ilang_frontend.h b/frontends/rtlil/rtlil_frontend.h index f8a152841..a420778b0 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/rtlil/rtlil_frontend.h @@ -18,18 +18,18 @@   *  ---   *   *  A very simple and straightforward frontend for the RTLIL text - *  representation (as generated by the 'ilang' backend). + *  representation.   *   */ -#ifndef ILANG_FRONTEND_H -#define ILANG_FRONTEND_H +#ifndef RTLIL_FRONTEND_H +#define RTLIL_FRONTEND_H  #include "kernel/yosys.h"  YOSYS_NAMESPACE_BEGIN -namespace ILANG_FRONTEND { +namespace RTLIL_FRONTEND {  	extern std::istream *lexin;  	extern RTLIL::Design *current_design;  	extern bool flag_nooverwrite; @@ -39,13 +39,13 @@ namespace ILANG_FRONTEND {  YOSYS_NAMESPACE_END -extern int rtlil_frontend_ilang_yydebug; -int rtlil_frontend_ilang_yylex(void); -void rtlil_frontend_ilang_yyerror(char const *s); -void rtlil_frontend_ilang_yyrestart(FILE *f); -int rtlil_frontend_ilang_yyparse(void); -int rtlil_frontend_ilang_yylex_destroy(void); -int rtlil_frontend_ilang_yyget_lineno(void); +extern int rtlil_frontend_yydebug; +int rtlil_frontend_yylex(void); +void rtlil_frontend_yyerror(char const *s); +void rtlil_frontend_yyrestart(FILE *f); +int rtlil_frontend_yyparse(void); +int rtlil_frontend_yylex_destroy(void); +int rtlil_frontend_yyget_lineno(void);  #endif diff --git a/frontends/ilang/ilang_lexer.l b/frontends/rtlil/rtlil_lexer.l index 3362ed641..295455f53 100644 --- a/frontends/ilang/ilang_lexer.l +++ b/frontends/rtlil/rtlil_lexer.l @@ -18,7 +18,7 @@   *  ---   *   *  A very simple and straightforward frontend for the RTLIL text - *  representation (as generated by the 'ilang' backend). + *  representation.   *   */ @@ -30,20 +30,20 @@  #endif  #include <cstdlib> -#include "frontends/ilang/ilang_frontend.h" -#include "ilang_parser.tab.hh" +#include "frontends/rtlil/rtlil_frontend.h" +#include "rtlil_parser.tab.hh"  USING_YOSYS_NAMESPACE  #define YY_INPUT(buf,result,max_size) \ -	result = readsome(*ILANG_FRONTEND::lexin, buf, max_size) +	result = readsome(*RTLIL_FRONTEND::lexin, buf, max_size)  %}  %option yylineno  %option noyywrap  %option nounput -%option prefix="rtlil_frontend_ilang_yy" +%option prefix="rtlil_frontend_yy"  %x STRING @@ -84,11 +84,11 @@ USING_YOSYS_NAMESPACE  [a-z]+		{ return TOK_INVALID; } -"\\"[^ \t\r\n]+		{ rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } -"$"[^ \t\r\n]+		{ rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } -"."[0-9]+		{ rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; } +"\\"[^ \t\r\n]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } +"$"[^ \t\r\n]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } +"."[0-9]+		{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_ID; } -[0-9]+'[01xzm-]*	{ rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; } +[0-9]+'[01xzm-]*	{ rtlil_frontend_yylval.string = strdup(yytext); return TOK_VALUE; }  -?[0-9]+		{  	char *end = nullptr;  	errno = 0; @@ -98,7 +98,7 @@ USING_YOSYS_NAMESPACE  		return TOK_INVALID; // literal out of range of long  	if (value < INT_MIN || value > INT_MAX)  		return TOK_INVALID; // literal out of range of int (relevant mostly for LP64 platforms) -	rtlil_frontend_ilang_yylval.integer = value; +	rtlil_frontend_yylval.integer = value;  	return TOK_INT;  } @@ -131,7 +131,7 @@ USING_YOSYS_NAMESPACE  		yystr[j++] = yystr[i++];  	}  	yystr[j] = 0; -	rtlil_frontend_ilang_yylval.string = yystr; +	rtlil_frontend_yylval.string = yystr;  	return TOK_STRING;  }  <STRING>.	{ yymore(); } @@ -145,6 +145,6 @@ USING_YOSYS_NAMESPACE  %%  // this is a hack to avoid the 'yyinput defined but not used' error msgs -void *rtlil_frontend_ilang_avoid_input_warnings() { +void *rtlil_frontend_avoid_input_warnings() {  	return (void*)&yyinput;  } diff --git a/frontends/ilang/ilang_parser.y b/frontends/rtlil/rtlil_parser.y index 879ef4af9..646489196 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/rtlil/rtlil_parser.y @@ -18,15 +18,15 @@   *  ---   *   *  A very simple and straightforward frontend for the RTLIL text - *  representation (as generated by the 'ilang' backend). + *  representation.   *   */  %{  #include <list> -#include "frontends/ilang/ilang_frontend.h" +#include "frontends/rtlil/rtlil_frontend.h"  YOSYS_NAMESPACE_BEGIN -namespace ILANG_FRONTEND { +namespace RTLIL_FRONTEND {  	std::istream *lexin;  	RTLIL::Design *current_design;  	RTLIL::Module *current_module; @@ -40,12 +40,12 @@ namespace ILANG_FRONTEND {  	bool flag_nooverwrite, flag_overwrite, flag_lib;  	bool delete_current_module;  } -using namespace ILANG_FRONTEND; +using namespace RTLIL_FRONTEND;  YOSYS_NAMESPACE_END  USING_YOSYS_NAMESPACE  %} -%define api.prefix {rtlil_frontend_ilang_yy} +%define api.prefix {rtlil_frontend_yy}  /* The union is defined in the header, so we need to provide all the   * includes it requires @@ -53,7 +53,7 @@ USING_YOSYS_NAMESPACE  %code requires {  #include <string>  #include <vector> -#include "frontends/ilang/ilang_frontend.h" +#include "frontends/rtlil/rtlil_frontend.h"  }  %union { @@ -87,7 +87,7 @@ input:  		attrbuf.clear();  	} design {  		if (attrbuf.size() != 0) -			rtlil_frontend_ilang_yyerror("dangling attribute"); +			rtlil_frontend_yyerror("dangling attribute");  	};  EOL: @@ -111,7 +111,7 @@ module:  				log("Ignoring blackbox re-definition of module %s.\n", $2);  				delete_current_module = true;  			} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { -				rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); +				rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str());  			} else if (flag_nooverwrite) {  				log("Ignoring re-definition of module %s.\n", $2);  				delete_current_module = true; @@ -129,7 +129,7 @@ module:  		free($2);  	} module_body TOK_END {  		if (attrbuf.size() != 0) -			rtlil_frontend_ilang_yyerror("dangling attribute"); +			rtlil_frontend_yyerror("dangling attribute");  		current_module->fixup_ports();  		if (delete_current_module)  			delete current_module; @@ -172,12 +172,12 @@ autoidx_stmt:  wire_stmt:  	TOK_WIRE { -		current_wire = current_module->addWire("$__ilang_frontend_tmp__"); +		current_wire = current_module->addWire("$__rtlil_frontend_tmp__");  		current_wire->attributes = attrbuf;  		attrbuf.clear();  	} wire_options TOK_ID EOL {  		if (current_module->wire($4) != nullptr) -			rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str()); +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str());  		current_module->rename(current_wire, $4);  		free($4);  	}; @@ -187,7 +187,7 @@ wire_options:  		current_wire->width = $3;  	} |  	wire_options TOK_WIDTH TOK_INVALID { -		rtlil_frontend_ilang_yyerror("ilang error: invalid wire width"); +		rtlil_frontend_yyerror("RTLIL error: invalid wire width");  	} |  	wire_options TOK_UPTO {  		current_wire->upto = true; @@ -222,7 +222,7 @@ memory_stmt:  		attrbuf.clear();  	} memory_options TOK_ID EOL {  		if (current_module->memories.count($4) != 0) -			rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str()); +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str());  		current_memory->name = $4;  		current_module->memories[$4] = current_memory;  		free($4); @@ -243,7 +243,7 @@ memory_options:  cell_stmt:  	TOK_CELL TOK_ID TOK_ID EOL {  		if (current_module->cell($3) != nullptr) -			rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str()); +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str());  		current_cell = current_module->addCell($3, $2);  		current_cell->attributes = attrbuf;  		attrbuf.clear(); @@ -271,7 +271,7 @@ cell_body:  	} |  	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()); +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str());  		current_cell->setPort($3, *$4);  		delete $4;  		free($3); @@ -281,7 +281,7 @@ cell_body:  proc_stmt:  	TOK_PROCESS TOK_ID EOL {  		if (current_module->processes.count($2) != 0) -			rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str()); +			rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str());  		current_process = new RTLIL::Process;  		current_process->name = $2;  		current_process->attributes = attrbuf; @@ -342,7 +342,7 @@ case_body:  assign_stmt:  	TOK_ASSIGN sigspec sigspec EOL {  		if (attrbuf.size() != 0) -			rtlil_frontend_ilang_yyerror("dangling attribute"); +			rtlil_frontend_yyerror("dangling attribute");  		case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));  		delete $2;  		delete $3; @@ -438,19 +438,19 @@ sigspec:  	} |  	TOK_ID {  		if (current_module->wire($1) == nullptr) -			rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str()); +			rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str());  		$$ = new RTLIL::SigSpec(current_module->wire($1));  		free($1);  	} |  	sigspec '[' TOK_INT ']' {  		if ($3 >= $1->size() || $3 < 0) -			rtlil_frontend_ilang_yyerror("bit index out of range"); +			rtlil_frontend_yyerror("bit index out of range");  		$$ = new RTLIL::SigSpec($1->extract($3));  		delete $1;  	} |  	sigspec '[' TOK_INT ':' TOK_INT ']' {  		if ($3 >= $1->size() || $3 < 0 || $3 < $5) -			rtlil_frontend_ilang_yyerror("invalid slice"); +			rtlil_frontend_yyerror("invalid slice");  		$$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));  		delete $1;  	} | @@ -477,7 +477,7 @@ sigspec_list: sigspec_list_reversed {  conn_stmt:  	TOK_CONNECT sigspec sigspec EOL {  		if (attrbuf.size() != 0) -			rtlil_frontend_ilang_yyerror("dangling attribute"); +			rtlil_frontend_yyerror("dangling attribute");  		current_module->connect(*$2, *$3);  		delete $2;  		delete $3; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 632dc51fd..7bbda9d49 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -54,7 +54,7 @@ USING_YOSYS_NAMESPACE  #  error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific."  #endif -#if SYMBIOTIC_VERIFIC_API_VERSION < 202006 +#if SYMBIOTIC_VERIFIC_API_VERSION < 20200801  #  error "Please update your version of Symbiotic EDA flavored Verific."  #endif @@ -199,12 +199,17 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att  				attributes.emplace(stringf("\\enum_value_%s", p+2), RTLIL::escape_id(k));  			}  			else if (nl->IsFromVhdl()) { -				// Expect "<binary>" +				// Expect "<binary>" or plain <binary>  				auto p = v;  				if (p) { -					if (*p != '"') -						p = nullptr; -					else { +					if (*p != '"') { +						auto l = strlen(p); +						auto q = (char*)malloc(l+1); +						strncpy(q, p, l); +						q[l] = '\0'; +						for(char *ptr = q; *ptr; ++ptr )*ptr = tolower(*ptr); +						attributes.emplace(stringf("\\enum_value_%s", q), RTLIL::escape_id(k)); +					} else {  						auto *q = p+1;  						for (; *q != '"'; q++)  							if (*q != '0' && *q != '1') { @@ -213,16 +218,20 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att  							}  						if (p && *(q+1) != '\0')  							p = nullptr; + +						if (p != nullptr) +						{ +							auto l = strlen(p); +							auto q = (char*)malloc(l+1-2); +							strncpy(q, p+1, l-2); +							q[l-2] = '\0'; +							attributes.emplace(stringf("\\enum_value_%s", q), RTLIL::escape_id(k)); +							free(q); +						}  					}  				}  				if (p == nullptr) -					log_error("Expected TypeRange value '%s' to be of form \"<binary>\".\n", v); -				auto l = strlen(p); -				auto q = (char*)malloc(l+1-2); -				strncpy(q, p+1, l-2); -				q[l-2] = '\0'; -				attributes.emplace(stringf("\\enum_value_%s", q), RTLIL::escape_id(k)); -				free(q); +					log_error("Expected TypeRange value '%s' to be of form \"<binary>\" or <binary>.\n", v);  			}  		}  	} @@ -2158,6 +2167,70 @@ struct VerificPass : public Pass {  		log("    Dump the Verific netlist as a verilog file.\n");  		log("\n");  		log("\n"); +		log("    verific [-work <libname>] -pp [options] <filename> [<module>]..\n"); +		log("\n"); +		log("Pretty print design (or just module) to the specified file from the\n"); +		log("specified library. (default library when -work is not present: \"work\")\n"); +		log("\n"); +		log("Pretty print options:\n"); +		log("\n"); +		log("  -verilog\n"); +		log("    Save output for Verilog/SystemVerilog design modules (default).\n"); +		log("\n"); +		log("  -vhdl\n"); +		log("    Save output for VHDL design units.\n"); +		log("\n"); +		log("\n"); +		log("    verific -app <application>..\n"); +		log("\n"); +		log("Execute SEDA formal application on loaded Verilog files.\n"); +		log("\n"); +		log("Application options:\n"); +		log("\n"); +		log("    -blacklist <filename[:lineno]>\n"); +		log("        Do not run application on modules from files that match the filename\n"); +		log("        or filename and line number if provided in such format.\n"); +		log("        Parameter can also contain comma separated list of file locations.\n"); +		log("\n"); +		log("    -blfile <file>\n"); +		log("        Do not run application on locations specified in file, they can represent filename\n"); +		log("        or filename and location in file.\n"); +		log("\n"); +		log("Applications:\n"); +		log("\n"); +#ifdef YOSYS_ENABLE_VERIFIC +		VerificFormalApplications vfa; +		log("%s\n",vfa.GetHelp().c_str()); +#else +		log("  WARNING: Applications only available in commercial build.\n"); + +#endif +		log("\n"); +		log("\n"); +		log("    verific -template <name> <top_module>..\n"); +		log("\n"); +		log("Generate template for specified top module of loaded design.\n"); +		log("\n"); +		log("Template options:\n"); +		log("\n"); +		log("  -out\n"); +		log("    Specifies output file for generated template, by default output is stdout\n"); +		log("\n"); +		log("  -chparam name value \n"); +		log("    Generate template using this parameter value. Otherwise default parameter\n"); +		log("    values will be used for templat generate functionality. This option\n"); +		log("    can be specified multiple times to override multiple parameters.\n"); +		log("    String values must be passed in double quotes (\").\n"); +		log("\n"); +		log("Templates:\n"); +		log("\n"); +#ifdef YOSYS_ENABLE_VERIFIC +		VerificTemplateGenerator vfg; +		log("%s\n",vfg.GetHelp().c_str()); +#else +		log("  WARNING: Templates only available in commercial build.\n"); +		log("\n"); +#endif  		log("Use Symbiotic EDA Suite if you need Yosys+Verifc.\n");  		log("https://www.symbioticeda.com/seda-suite\n");  		log("\n"); @@ -2202,6 +2275,9 @@ struct VerificPass : public Pass {  			RuntimeFlags::SetVar("veri_preserve_assignments", 1);  			RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); +			RuntimeFlags::SetVar("veri_preserve_comments",1); +			//RuntimeFlags::SetVar("vhdl_preserve_comments",1); +  			// Workaround for VIPER #13851  			RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); @@ -2399,6 +2475,161 @@ struct VerificPass : public Pass {  			goto check_error;  		} +		if (argidx+1 < GetSize(args) && args[argidx] == "-app") +		{ +			VerificFormalApplications vfa; +			auto apps = vfa.GetApps(); +			std::string app = args[++argidx]; +			std::vector<std::string> blacklists; +			if (apps.find(app) == apps.end()) +				log_cmd_error("Application '%s' does not exist.\n", app.c_str()); + +			for (argidx++; argidx < GetSize(args); argidx++) { +				if (args[argidx] == "-blacklist" && argidx+1 < GetSize(args)) { +					std::string line = args[++argidx]; +					std::string p; +					while (!(p = next_token(line, ",\t\r\n ")).empty()) +						blacklists.push_back(p); +					continue; +				} +				if (args[argidx] == "-blfile" && argidx+1 < GetSize(args)) { +					std::string fn = args[++argidx]; +					std::ifstream f(fn); +					if (f.fail()) +						log_cmd_error("Can't open blacklist file '%s'!\n", fn.c_str()); + +					std::string line,p; +					while (std::getline(f, line)) { +						while (!(p = next_token(line, ",\t\r\n ")).empty()) +							blacklists.push_back(p); +					} +					continue; +				} +				break; +			} +			if (argidx < GetSize(args)) +				cmd_error(args, argidx, "unknown option/parameter"); +			MapIter mi; +			VeriModule *module ; +			VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); +			log("Running formal application '%s'.\n", app.c_str()); +			FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, module) { +				vfa.Run(module,apps[app],blacklists); +			} +			goto check_error; +		} + +		if (argidx < GetSize(args) && args[argidx] == "-pp") +		{ +			const char* filename = nullptr; +			const char* module = nullptr; +			bool mode_vhdl = false; +			for (argidx++; argidx < GetSize(args); argidx++) { +				if (args[argidx] == "-vhdl") { +					mode_vhdl = true; +					continue; +				} +				if (args[argidx] == "-verilog") { +					mode_vhdl = false; +					continue; +				} + +				if (args[argidx].compare(0, 1, "-") == 0) { +					cmd_error(args, argidx, "unknown option"); +					goto check_error; +				} + +				if (!filename) { +					filename = args[argidx].c_str(); +					continue; +				} +				if (module) +					log_cmd_error("Only one module can be specified.\n"); +				module = args[argidx].c_str(); +			} + +			if (argidx < GetSize(args)) +				cmd_error(args, argidx, "unknown option/parameter"); + +			if (!filename) +				log_cmd_error("Filname must be specified.\n"); + +			if (mode_vhdl) +				vhdl_file::PrettyPrint(filename, module, work.c_str()); +			else +				veri_file::PrettyPrint(filename, module, work.c_str()); +			goto check_error; +		} + +		if (argidx < GetSize(args) && args[argidx] == "-template") +		{ +			if (!(argidx < GetSize(args))) +				cmd_error(args, argidx, "No template type specified.\n"); + +			VerificTemplateGenerator vfg; +			auto gens = vfg.GetGenerators(); +			std::string app = args[++argidx]; +			if (gens.find(app) == gens.end()) +				log_cmd_error("Template generator '%s' does not exist.\n", app.c_str()); +			TemplateGenerator *generator = gens[app]; +			if (!(argidx < GetSize(args))) +				cmd_error(args, argidx, "No top module specified.\n"); +			 +			std::string module = args[++argidx]; +			VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); +			VeriModule *veri_module = veri_lib ? veri_lib->GetModule(module.c_str(), 1) : nullptr; +			if (!veri_module) { +				log_error("Can't find module/unit '%s'.\n", module.c_str()); +			} + +			log("Template '%s' is running for module '%s'.\n", app.c_str(),module.c_str()); + +			Map parameters(STRING_HASH); +			const char *out_filename = nullptr; + +			for (argidx++; argidx < GetSize(args); argidx++) { +				if (generator->checkParams(args, argidx)) +					continue; +				if (args[argidx] == "-chparam"  && argidx+2 < GetSize(args)) { +					const std::string &key = args[++argidx]; +					const std::string &value = args[++argidx]; +					unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(), +									           1 /* force_overwrite */); +					if (!new_insertion) +						log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str()); +					continue; +				} + +				if (args[argidx] == "-out" && argidx+1 < GetSize(args)) { +					out_filename = args[++argidx].c_str(); +					continue; +				} + +				break; +			} +			if (argidx < GetSize(args)) +				cmd_error(args, argidx, "unknown option/parameter"); + +			const char *err = generator->validate(); +			if (err) +				cmd_error(args, argidx, err); + +			std::string val = generator->generate(veri_module, ¶meters); + +			FILE *of = stdout; +			if (out_filename) { +				of = fopen(out_filename, "w"); +				if (of == nullptr) +					log_error("Can't open '%s' for writing: %s\n", out_filename, strerror(errno)); +				log("Writing output to '%s'\n",out_filename); +			} +			fprintf(of, "%s\n",val.c_str()); +			fflush(of); +			if (of!=stdout) +				fclose(of); +			goto check_error; +		} +  		if (GetSize(args) > argidx && args[argidx] == "-import")  		{  			std::set<Netlist*> nl_todo, nl_done;  | 
