mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Merge pull request #513 from udif/pr_reg_wire_error
Add error checking for reg/wire/logic misuse - PR now passes 'make test' (plus a new test)
This commit is contained in:
		
						commit
						3d27c1cc80
					
				
					 7 changed files with 132 additions and 4 deletions
				
			
		|  | @ -191,8 +191,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch | |||
| 	is_input = false; | ||||
| 	is_output = false; | ||||
| 	is_reg = false; | ||||
| 	is_logic = false; | ||||
| 	is_signed = false; | ||||
| 	is_string = false; | ||||
| 	was_checked = false; | ||||
| 	range_valid = false; | ||||
| 	range_swapped = false; | ||||
| 	port_id = 0; | ||||
|  | @ -285,7 +287,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const | |||
| 		fprintf(f, " input"); | ||||
| 	if (is_output) | ||||
| 		fprintf(f, " output"); | ||||
| 	if (is_reg) | ||||
| 	if (is_logic) | ||||
| 		fprintf(f, " logic"); | ||||
| 	if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine.
 | ||||
| 		fprintf(f, " reg"); | ||||
| 	if (is_signed) | ||||
| 		fprintf(f, " signed"); | ||||
|  | @ -652,6 +656,8 @@ bool AstNode::operator==(const AstNode &other) const | |||
| 		return false; | ||||
| 	if (is_output != other.is_output) | ||||
| 		return false; | ||||
| 	if (is_logic != other.is_logic) | ||||
| 		return false; | ||||
| 	if (is_reg != other.is_reg) | ||||
| 		return false; | ||||
| 	if (is_signed != other.is_signed) | ||||
|  |  | |||
|  | @ -168,7 +168,7 @@ namespace AST | |||
| 		// node content - most of it is unused in most node types
 | ||||
| 		std::string str; | ||||
| 		std::vector<RTLIL::State> bits; | ||||
| 		bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped; | ||||
| 		bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked; | ||||
| 		int port_id, range_left, range_right; | ||||
| 		uint32_t integer; | ||||
| 		double realvalue; | ||||
|  |  | |||
|  | @ -327,6 +327,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 			if (node->type == AST_WIRE) { | ||||
| 				if (this_wire_scope.count(node->str) > 0) { | ||||
| 					AstNode *first_node = this_wire_scope[node->str]; | ||||
| 					if (first_node->is_input && node->is_reg) | ||||
| 						goto wires_are_incompatible; | ||||
| 					if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) | ||||
| 						goto wires_are_compatible; | ||||
| 					if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { | ||||
|  | @ -361,6 +363,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 						first_node->is_output = true; | ||||
| 					if (node->is_reg) | ||||
| 						first_node->is_reg = true; | ||||
| 					if (node->is_logic) | ||||
| 						first_node->is_logic = true; | ||||
| 					if (node->is_signed) | ||||
| 						first_node->is_signed = true; | ||||
| 					for (auto &it : node->attributes) { | ||||
|  | @ -440,6 +444,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 		children[1]->detectSignWidth(width_hint, sign_hint); | ||||
| 		width_hint = max(width_hint, backup_width_hint); | ||||
| 		child_0_is_self_determined = true; | ||||
| 		// test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier
 | ||||
| 		if (children[0]->id2ast && !children[0]->was_checked) { | ||||
| 			if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) | ||||
| 				children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment
 | ||||
| 			if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) | ||||
| 				log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); | ||||
| 			if (type == AST_ASSIGN && children[0]->id2ast->is_reg) | ||||
| 				log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); | ||||
| 			children[0]->was_checked = true; | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
| 	case AST_PARAMETER: | ||||
|  | @ -949,6 +963,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, | |||
| 
 | ||||
| 		AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); | ||||
| 		assign->children[0]->str = wire_id; | ||||
| 		assign->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		if (current_block) | ||||
| 		{ | ||||
|  | @ -1414,16 +1429,19 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		AstNode *wire_check = new AstNode(AST_WIRE); | ||||
| 		wire_check->str = id_check; | ||||
| 		wire_check->was_checked = true; | ||||
| 		current_ast_mod->children.push_back(wire_check); | ||||
| 		current_scope[wire_check->str] = wire_check; | ||||
| 		while (wire_check->simplify(true, false, false, 1, -1, false, false)) { } | ||||
| 
 | ||||
| 		AstNode *wire_en = new AstNode(AST_WIRE); | ||||
| 		wire_en->str = id_en; | ||||
| 		wire_en->was_checked = true; | ||||
| 		current_ast_mod->children.push_back(wire_en); | ||||
| 		if (current_always_clocked) { | ||||
| 			current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); | ||||
| 			current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; | ||||
| 			current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; | ||||
| 		} | ||||
| 		current_scope[wire_en->str] = wire_en; | ||||
| 		while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } | ||||
|  | @ -1433,9 +1451,11 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); | ||||
| 		assign_check->children[0]->str = id_check; | ||||
| 		assign_check->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); | ||||
| 		assign_en->children[0]->str = id_en; | ||||
| 		assign_en->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		AstNode *default_signals = new AstNode(AST_BLOCK); | ||||
| 		default_signals->children.push_back(assign_check); | ||||
|  | @ -1444,6 +1464,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); | ||||
| 		assign_check->children[0]->str = id_check; | ||||
| 		assign_check->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		if (current_always == nullptr || current_always->type != AST_INITIAL) { | ||||
| 			assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); | ||||
|  | @ -1452,6 +1473,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 			assign_en->children[1]->str = "\\$initstate"; | ||||
| 		} | ||||
| 		assign_en->children[0]->str = id_en; | ||||
| 		assign_en->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		newNode = new AstNode(AST_BLOCK); | ||||
| 		newNode->children.push_back(assign_check); | ||||
|  | @ -1560,12 +1582,14 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); | ||||
| 		wire_addr->str = id_addr; | ||||
| 		wire_addr->was_checked = true; | ||||
| 		current_ast_mod->children.push_back(wire_addr); | ||||
| 		current_scope[wire_addr->str] = wire_addr; | ||||
| 		while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } | ||||
| 
 | ||||
| 		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||
| 		wire_data->str = id_data; | ||||
| 		wire_data->was_checked = true; | ||||
| 		wire_data->is_signed = mem_signed; | ||||
| 		current_ast_mod->children.push_back(wire_data); | ||||
| 		current_scope[wire_data->str] = wire_data; | ||||
|  | @ -1575,6 +1599,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 		if (current_always->type != AST_INITIAL) { | ||||
| 			wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||
| 			wire_en->str = id_en; | ||||
| 			wire_en->was_checked = true; | ||||
| 			current_ast_mod->children.push_back(wire_en); | ||||
| 			current_scope[wire_en->str] = wire_en; | ||||
| 			while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } | ||||
|  | @ -1590,14 +1615,17 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); | ||||
| 		assign_addr->children[0]->str = id_addr; | ||||
| 		assign_addr->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); | ||||
| 		assign_data->children[0]->str = id_data; | ||||
| 		assign_data->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		AstNode *assign_en = nullptr; | ||||
| 		if (current_always->type != AST_INITIAL) { | ||||
| 			assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); | ||||
| 			assign_en->children[0]->str = id_en; | ||||
| 			assign_en->children[0]->was_checked = true; | ||||
| 		} | ||||
| 
 | ||||
| 		AstNode *default_signals = new AstNode(AST_BLOCK); | ||||
|  | @ -1609,6 +1637,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 
 | ||||
| 		assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); | ||||
| 		assign_addr->children[0]->str = id_addr; | ||||
| 		assign_addr->children[0]->was_checked = true; | ||||
| 
 | ||||
| 		if (children[0]->children.size() == 2) | ||||
| 		{ | ||||
|  | @ -1623,12 +1652,14 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), | ||||
| 						new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); | ||||
| 				assign_data->children[0]->str = id_data; | ||||
| 				assign_data->children[0]->was_checked = true; | ||||
| 
 | ||||
| 				if (current_always->type != AST_INITIAL) { | ||||
| 					for (int i = 0; i < mem_width; i++) | ||||
| 						set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; | ||||
| 					assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); | ||||
| 					assign_en->children[0]->str = id_en; | ||||
| 					assign_en->children[0]->was_checked = true; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
|  | @ -1650,6 +1681,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), | ||||
| 						new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); | ||||
| 				assign_data->children[0]->str = id_data; | ||||
| 				assign_data->children[0]->was_checked = true; | ||||
| 
 | ||||
| 				if (current_always->type != AST_INITIAL) { | ||||
| 					for (int i = 0; i < mem_width; i++) | ||||
|  | @ -1657,6 +1689,7 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 					assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), | ||||
| 							new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); | ||||
| 					assign_en->children[0]->str = id_en; | ||||
| 					assign_en->children[0]->was_checked = true; | ||||
| 				} | ||||
| 
 | ||||
| 				delete left_at_zero_ast; | ||||
|  | @ -1668,10 +1701,12 @@ skip_dynamic_range_lvalue_expansion:; | |||
| 		{ | ||||
| 			assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); | ||||
| 			assign_data->children[0]->str = id_data; | ||||
| 			assign_data->children[0]->was_checked = true; | ||||
| 
 | ||||
| 			if (current_always->type != AST_INITIAL) { | ||||
| 				assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); | ||||
| 				assign_en->children[0]->str = id_en; | ||||
| 				assign_en->children[0]->was_checked = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -3007,6 +3042,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); | ||||
| 		wire_addr->str = id_addr; | ||||
| 		wire_addr->is_reg = true; | ||||
| 		wire_addr->was_checked = true; | ||||
| 		wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
| 		mod->children.push_back(wire_addr); | ||||
| 		while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } | ||||
|  | @ -3014,6 +3050,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||
| 		wire_data->str = id_data; | ||||
| 		wire_data->is_reg = true; | ||||
| 		wire_data->was_checked = true; | ||||
| 		wire_data->is_signed = mem_signed; | ||||
| 		wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
| 		mod->children.push_back(wire_data); | ||||
|  | @ -3082,6 +3119,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 			AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); | ||||
| 			wire_addr->str = id_addr; | ||||
| 			wire_addr->is_reg = true; | ||||
| 			wire_addr->was_checked = true; | ||||
| 			if (block) | ||||
| 				wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
| 			mod->children.push_back(wire_addr); | ||||
|  | @ -3090,6 +3128,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 			AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); | ||||
| 			wire_data->str = id_data; | ||||
| 			wire_data->is_reg = true; | ||||
| 			wire_data->was_checked = true; | ||||
| 			wire_data->is_signed = mem_signed; | ||||
| 			if (block) | ||||
| 				wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); | ||||
|  | @ -3098,6 +3137,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 
 | ||||
| 			AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); | ||||
| 			assign_addr->children[0]->str = id_addr; | ||||
| 			assign_addr->children[0]->was_checked = true; | ||||
| 
 | ||||
| 			AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); | ||||
| 			case_node->children[0]->str = id_addr; | ||||
|  | @ -3108,6 +3148,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 				AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); | ||||
| 				AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); | ||||
| 				assign_reg->children[0]->str = id_data; | ||||
| 				assign_reg->children[0]->was_checked = true; | ||||
| 				assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); | ||||
| 				cond_node->children[1]->children.push_back(assign_reg); | ||||
| 				case_node->children.push_back(cond_node); | ||||
|  | @ -3120,6 +3161,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, | |||
| 			AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); | ||||
| 			AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); | ||||
| 			assign_reg->children[0]->str = id_data; | ||||
| 			assign_reg->children[0]->was_checked = true; | ||||
| 			cond_node->children[1]->children.push_back(assign_reg); | ||||
| 			case_node->children.push_back(cond_node); | ||||
| 
 | ||||
|  |  | |||
|  | @ -192,7 +192,7 @@ YOSYS_NAMESPACE_END | |||
| "const"      { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } | ||||
| "checker"    { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } | ||||
| "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } | ||||
| "logic"      { SV_KEYWORD(TOK_REG); } | ||||
| "logic"      { SV_KEYWORD(TOK_LOGIC); } | ||||
| "bit"        { SV_KEYWORD(TOK_REG); } | ||||
| 
 | ||||
| "eventually"   { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } | ||||
|  |  | |||
|  | @ -105,7 +105,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) | |||
| %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END | ||||
| %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM | ||||
| %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP | ||||
| %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG | ||||
| %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC | ||||
| %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL | ||||
| %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 | ||||
|  | @ -397,6 +397,9 @@ wire_type_token: | |||
| 	TOK_REG { | ||||
| 		astbuf3->is_reg = true; | ||||
| 	} | | ||||
| 	TOK_LOGIC { | ||||
| 		astbuf3->is_logic = true; | ||||
| 	} | | ||||
| 	TOK_INTEGER { | ||||
| 		astbuf3->is_reg = true; | ||||
| 		astbuf3->range_left = 31; | ||||
|  | @ -548,6 +551,7 @@ task_func_decl: | |||
| 		AstNode *outreg = new AstNode(AST_WIRE); | ||||
| 		outreg->str = *$6; | ||||
| 		outreg->is_signed = $4; | ||||
| 		outreg->is_reg = true; | ||||
| 		if ($5 != NULL) { | ||||
| 			outreg->children.push_back($5); | ||||
| 			outreg->is_signed = $4 || $5->is_signed; | ||||
|  | @ -1027,6 +1031,7 @@ wire_name: | |||
| 				node->port_id = current_function_or_task_port_id++; | ||||
| 		} | ||||
| 		ast_stack.back()->children.push_back(node); | ||||
| 
 | ||||
| 		delete $1; | ||||
| 	}; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										74
									
								
								tests/various/reg_wire_error.sv
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								tests/various/reg_wire_error.sv
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| module sub_mod(input i_in, output o_out); | ||||
| assign o_out = i_in; | ||||
| endmodule | ||||
| 
 | ||||
| module test(i_clk, i, i_reg, o_reg, o_wire, o_mr, o_mw, o_ml); | ||||
| input i_clk; | ||||
| input i; | ||||
| input i_reg; | ||||
| output o_reg; | ||||
| output o_wire; | ||||
| output o_mr, o_mw, o_ml; | ||||
| 
 | ||||
| // Enable this to see how it doesn't fail on yosys although it should
 | ||||
| //reg o_wire;
 | ||||
| // Enable this instead of the above to see how logic can be mapped to a wire
 | ||||
| logic o_wire; | ||||
| // Enable this to see how it doesn't fail on yosys although it should
 | ||||
| //reg i_reg;
 | ||||
| // Disable this to see how it doesn't fail on yosys although it should
 | ||||
| //reg o_reg;
 | ||||
| 
 | ||||
| logic l_reg; | ||||
| 
 | ||||
| // Enable this to tst if logic-turne-reg will catch assignments even if done before it turned into a reg
 | ||||
| assign l_reg = !o_reg; | ||||
| initial o_reg = 1'b0; | ||||
| always @(posedge i_clk) | ||||
| begin | ||||
|   o_reg <= !o_reg; | ||||
|   l_reg <= !o_reg; | ||||
| end | ||||
| 
 | ||||
| assign o_wire = !o_reg; | ||||
| // Uncomment this to see how a logic already turned intoa reg can be freely assigned on yosys
 | ||||
| assign l_reg = !o_reg; | ||||
| 
 | ||||
| sub_mod sm_inst ( | ||||
|   .i_in(1'b1), | ||||
|   .o_out(o_reg) | ||||
| ); | ||||
| 
 | ||||
| wire   mw1[0:1]; | ||||
| wire   mw2[0:1]; | ||||
| wire   mw3[0:1]; | ||||
| reg    mr1[0:1]; | ||||
| reg    mr2[0:1]; | ||||
| reg    mr3[0:1]; | ||||
| logic  ml1[0:1]; | ||||
| logic  ml2[0:1]; | ||||
| logic  ml3[0:1]; | ||||
| 
 | ||||
| assign o_mw = mw1[i]; | ||||
| assign o_mr = mr1[i]; | ||||
| assign o_ml = ml1[i]; | ||||
| 
 | ||||
| assign mw1[1] = 1'b1; | ||||
| //assign mr1[1] = 1'b1;
 | ||||
| assign ml1[1] = 1'b1; | ||||
| always @(posedge i_clk) | ||||
| begin | ||||
|   mr2[0] = 1'b0; | ||||
|   mw2[0] = 1'b0; | ||||
|   ml2[0] = 1'b0; | ||||
| end | ||||
| 
 | ||||
| always @(posedge i_clk) | ||||
| begin | ||||
|   mr3[0] <= 1'b0; | ||||
|   mw3[0] <= 1'b0; | ||||
|   ml3[0] <= 1'b0; | ||||
| end | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
							
								
								
									
										1
									
								
								tests/various/reg_wire_error.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/various/reg_wire_error.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| read_verilog -sv reg_wire_error.sv | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue