mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Fix "verific -extnets" for more complex situations
Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
		
							parent
							
								
									ddc1a4488e
								
							
						
					
					
						commit
						c863796e9f
					
				
					 2 changed files with 93 additions and 15 deletions
				
			
		|  | @ -1619,30 +1619,35 @@ struct VerificExtNets | ||||||
| 	int portname_cnt = 0; | 	int portname_cnt = 0; | ||||||
| 
 | 
 | ||||||
| 	// a map from Net to the same Net one level up in the design hierarchy
 | 	// a map from Net to the same Net one level up in the design hierarchy
 | ||||||
| 	std::map<Net*, Net*> net_level_up; | 	std::map<Net*, Net*> net_level_up_drive_up; | ||||||
|  | 	std::map<Net*, Net*> net_level_up_drive_down; | ||||||
| 
 | 
 | ||||||
| 	Net *get_net_level_up(Net *net) | 	Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr) | ||||||
| 	{ | 	{ | ||||||
|  | 		auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down; | ||||||
|  | 
 | ||||||
| 		if (net_level_up.count(net) == 0) | 		if (net_level_up.count(net) == 0) | ||||||
| 		{ | 		{ | ||||||
| 			Netlist *nl = net->Owner(); | 			Netlist *nl = net->Owner(); | ||||||
| 
 | 
 | ||||||
| 			// Simply return if Netlist is not unique
 | 			// Simply return if Netlist is not unique
 | ||||||
| 			if (nl->NumOfRefs() != 1) | 			log_assert(nl->NumOfRefs() == 1); | ||||||
| 				return net; |  | ||||||
| 
 | 
 | ||||||
| 			Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); | 			Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); | ||||||
| 			Netlist *up_nl = up_inst->Owner(); | 			Netlist *up_nl = up_inst->Owner(); | ||||||
| 
 | 
 | ||||||
| 			// create new Port
 | 			// create new Port
 | ||||||
| 			string name = stringf("___extnets_%d", portname_cnt++); | 			string name = stringf("___extnets_%d", portname_cnt++); | ||||||
| 			Port *new_port = new Port(name.c_str(), DIR_OUT); | 			Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN); | ||||||
| 			nl->Add(new_port); | 			nl->Add(new_port); | ||||||
| 			net->Connect(new_port); | 			net->Connect(new_port); | ||||||
| 
 | 
 | ||||||
| 			// create new Net in up Netlist
 | 			// create new Net in up Netlist
 | ||||||
| 			Net *new_net = new Net(name.c_str()); | 			Net *new_net = final_net; | ||||||
|  | 			if (new_net == nullptr || new_net->Owner() != up_nl) { | ||||||
|  | 				new_net = new Net(name.c_str()); | ||||||
| 				up_nl->Add(new_net); | 				up_nl->Add(new_net); | ||||||
|  | 			} | ||||||
| 			up_inst->Connect(new_port, new_net); | 			up_inst->Connect(new_port, new_net); | ||||||
| 
 | 
 | ||||||
| 			net_level_up[net] = new_net; | 			net_level_up[net] = new_net; | ||||||
|  | @ -1651,6 +1656,39 @@ struct VerificExtNets | ||||||
| 		return net_level_up.at(net); | 		return net_level_up.at(net); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr) | ||||||
|  | 	{ | ||||||
|  | 		while (net->Owner() != dest) | ||||||
|  | 			net = route_up(net, drive_up, final_net); | ||||||
|  | 		if (final_net != nullptr) | ||||||
|  | 			log_assert(net == final_net); | ||||||
|  | 		return net; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	Netlist *find_common_ancestor(Netlist *A, Netlist *B) | ||||||
|  | 	{ | ||||||
|  | 		std::set<Netlist*> ancestors_of_A; | ||||||
|  | 
 | ||||||
|  | 		Netlist *cursor = A; | ||||||
|  | 		while (1) { | ||||||
|  | 			ancestors_of_A.insert(cursor); | ||||||
|  | 			if (cursor->NumOfRefs() != 1) | ||||||
|  | 				break; | ||||||
|  | 			cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		cursor = B; | ||||||
|  | 		while (1) { | ||||||
|  | 			if (ancestors_of_A.count(cursor)) | ||||||
|  | 				return cursor; | ||||||
|  | 			if (cursor->NumOfRefs() != 1) | ||||||
|  | 				break; | ||||||
|  | 			cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void run(Netlist *nl) | 	void run(Netlist *nl) | ||||||
| 	{ | 	{ | ||||||
| 		MapIter mi, mi2; | 		MapIter mi, mi2; | ||||||
|  | @ -1674,19 +1712,37 @@ struct VerificExtNets | ||||||
| 			if (verific_verbose) | 			if (verific_verbose) | ||||||
| 				log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name()); | 				log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name()); | ||||||
| 
 | 
 | ||||||
| 			while (net->IsExternalTo(nl)) | 			Netlist *ext_nl = net->Owner(); | ||||||
| 			{ |  | ||||||
| 				Net *newnet = get_net_level_up(net); |  | ||||||
| 				if (newnet == net) break; |  | ||||||
| 
 | 
 | ||||||
| 			if (verific_verbose) | 			if (verific_verbose) | ||||||
| 					log("  external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name()); | 				log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str()); | ||||||
| 				net = newnet; | 
 | ||||||
|  | 			Netlist *ca_nl = find_common_ancestor(nl, ext_nl); | ||||||
|  | 
 | ||||||
|  | 			if (verific_verbose) | ||||||
|  | 				log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str()); | ||||||
|  | 
 | ||||||
|  | 			Net *ca_net = route_up(net, !port->IsOutput(), ca_nl); | ||||||
|  | 			Net *new_net = ca_net; | ||||||
|  | 
 | ||||||
|  | 			if (ca_nl != nl) | ||||||
|  | 			{ | ||||||
|  | 				if (verific_verbose) | ||||||
|  | 					log(" net in common ancestor: %s\n", ca_net->Name()); | ||||||
|  | 
 | ||||||
|  | 				string name = stringf("___extnets_%d", portname_cnt++); | ||||||
|  | 				new_net = new Net(name.c_str()); | ||||||
|  | 				nl->Add(new_net); | ||||||
|  | 
 | ||||||
|  | 				Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net); | ||||||
|  | 				log_assert(n == ca_net); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (verific_verbose) | 			if (verific_verbose) | ||||||
| 				log("  final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : ""); | 				log(" new local net: %s\n", new_net->Name()); | ||||||
| 			todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net)); | 
 | ||||||
|  | 			log_assert(!new_net->IsExternalTo(nl)); | ||||||
|  | 			todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net)); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto it : todo_connect) { | 		for (auto it : todo_connect) { | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								tests/sva/extnets.sv
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								tests/sva/extnets.sv
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | module top(input i, output o); | ||||||
|  | 	A A(); | ||||||
|  | 	B B(); | ||||||
|  | 	assign A.i = i; | ||||||
|  | 	assign o = B.o; | ||||||
|  | 	always @* assert(o == i); | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module A; | ||||||
|  | 	wire i, y; | ||||||
|  | `ifdef FAIL | ||||||
|  | 	assign B.x = i; | ||||||
|  | `else | ||||||
|  | 	assign B.x = !i; | ||||||
|  | `endif | ||||||
|  | 	assign y = !B.y; | ||||||
|  | endmodule | ||||||
|  | 
 | ||||||
|  | module B; | ||||||
|  | 	wire x, y, o; | ||||||
|  | 	assign y = x, o = A.y; | ||||||
|  | endmodule | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue