mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Added nosync attribute and some async reset related fixes
This commit is contained in:
		
							parent
							
								
									3737964809
								
							
						
					
					
						commit
						227520f94d
					
				
					 5 changed files with 27 additions and 34 deletions
				
			
		
							
								
								
									
										6
									
								
								README
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								README
									
										
									
									
									
								
							| 
						 | 
					@ -199,6 +199,12 @@ Verilog Attributes and non-standard features
 | 
				
			||||||
  prohibits the generation of logic-loops for latches. Instead
 | 
					  prohibits the generation of logic-loops for latches. Instead
 | 
				
			||||||
  all not explicitly assigned values default to x-bits.
 | 
					  all not explicitly assigned values default to x-bits.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The "nosync" attribute on registers prohibits the generation of a
 | 
				
			||||||
 | 
					  storage element. The register itself will always have all bits set
 | 
				
			||||||
 | 
					  to 'x' (undefined). The variable may only be used as blocking assigned
 | 
				
			||||||
 | 
					  temporary variable within an always block. This is mostly used internally
 | 
				
			||||||
 | 
					  by yosys to synthesize verilog functions and access arrays.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- In addition to the (* ... *) attribute syntax, yosys supports
 | 
					- In addition to the (* ... *) attribute syntax, yosys supports
 | 
				
			||||||
  the non-standard {* ... *} attribute syntax to set default attributes
 | 
					  the non-standard {* ... *} attribute syntax to set default attributes
 | 
				
			||||||
  for everything that comes after the {* ... *} statement. (Reset
 | 
					  for everything that comes after the {* ... *} statement. (Reset
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,7 +165,7 @@ namespace AST
 | 
				
			||||||
		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);
 | 
				
			||||||
		void replace_ids(std::map<std::string, std::string> &rules);
 | 
							void replace_ids(std::map<std::string, std::string> &rules);
 | 
				
			||||||
		void mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc, bool force_mem2reg);
 | 
							void mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<AstNode*> &mem2reg_candidates, bool sync_proc, bool async_proc, bool force_mem2reg);
 | 
				
			||||||
		void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block);
 | 
							void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
 | 
				
			||||||
		void meminfo(int &mem_width, int &mem_size, int &addr_bits);
 | 
							void meminfo(int &mem_width, int &mem_size, int &addr_bits);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// create a human-readable text representation of the AST (for debugging)
 | 
							// create a human-readable text representation of the AST (for debugging)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,14 +245,14 @@ struct AST_INTERNAL::ProcessGenerator
 | 
				
			||||||
				RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
 | 
									RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
 | 
				
			||||||
				syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
 | 
									syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
 | 
				
			||||||
				syncrule->signal = child->children[0]->genRTLIL();
 | 
									syncrule->signal = child->children[0]->genRTLIL();
 | 
				
			||||||
				addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
 | 
									addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
 | 
				
			||||||
				proc->syncs.push_back(syncrule);
 | 
									proc->syncs.push_back(syncrule);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		if (proc->syncs.empty()) {
 | 
							if (proc->syncs.empty()) {
 | 
				
			||||||
			RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
 | 
								RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
 | 
				
			||||||
			syncrule->type = RTLIL::STa;
 | 
								syncrule->type = RTLIL::STa;
 | 
				
			||||||
			syncrule->signal = RTLIL::SigSpec();
 | 
								syncrule->signal = RTLIL::SigSpec();
 | 
				
			||||||
			addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to);
 | 
								addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
 | 
				
			||||||
			proc->syncs.push_back(syncrule);
 | 
								proc->syncs.push_back(syncrule);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -350,7 +350,7 @@ struct AST_INTERNAL::ProcessGenerator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// add an assignment (aka "action") but split it up in chunks. this way huge assignments
 | 
						// add an assignment (aka "action") but split it up in chunks. this way huge assignments
 | 
				
			||||||
	// are avoided and the generated $mux cells have a more "natural" size.
 | 
						// are avoided and the generated $mux cells have a more "natural" size.
 | 
				
			||||||
	void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue)
 | 
						void addChunkActions(std::vector<RTLIL::SigSig> &actions, RTLIL::SigSpec lvalue, RTLIL::SigSpec rvalue, bool noSyncToUndef = false)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		assert(lvalue.width == rvalue.width);
 | 
							assert(lvalue.width == rvalue.width);
 | 
				
			||||||
		lvalue.optimize();
 | 
							lvalue.optimize();
 | 
				
			||||||
| 
						 | 
					@ -360,6 +360,8 @@ struct AST_INTERNAL::ProcessGenerator
 | 
				
			||||||
		for (size_t i = 0; i < lvalue.chunks.size(); i++) {
 | 
							for (size_t i = 0; i < lvalue.chunks.size(); i++) {
 | 
				
			||||||
			RTLIL::SigSpec lhs = lvalue.chunks[i];
 | 
								RTLIL::SigSpec lhs = lvalue.chunks[i];
 | 
				
			||||||
			RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue.chunks[i].width);
 | 
								RTLIL::SigSpec rhs = rvalue.extract(offset, lvalue.chunks[i].width);
 | 
				
			||||||
 | 
								if (noSyncToUndef && lvalue.chunks[i].wire && lvalue.chunks[i].wire->attributes.count("\\nosync"))
 | 
				
			||||||
 | 
									rhs = RTLIL::SigSpec(RTLIL::State::Sx, rhs.width);
 | 
				
			||||||
			actions.push_back(RTLIL::SigSig(lhs, rhs));
 | 
								actions.push_back(RTLIL::SigSig(lhs, rhs));
 | 
				
			||||||
			offset += lhs.width;
 | 
								offset += lhs.width;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mem2reg_as_needed_pass2(mem2reg_set, this, NULL, NULL);
 | 
								mem2reg_as_needed_pass2(mem2reg_set, this, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			for (size_t i = 0; i < children.size(); i++) {
 | 
								for (size_t i = 0; i < children.size(); i++) {
 | 
				
			||||||
				if (mem2reg_set.count(children[i]) > 0) {
 | 
									if (mem2reg_set.count(children[i]) > 0) {
 | 
				
			||||||
| 
						 | 
					@ -685,6 +685,8 @@ skip_dynamic_range_lvalue_expansion:;
 | 
				
			||||||
				wire->port_id = 0;
 | 
									wire->port_id = 0;
 | 
				
			||||||
				wire->is_input = false;
 | 
									wire->is_input = false;
 | 
				
			||||||
				wire->is_output = false;
 | 
									wire->is_output = false;
 | 
				
			||||||
 | 
									if (type == AST_FCALL)
 | 
				
			||||||
 | 
										wire->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
 | 
				
			||||||
				current_ast_mod->children.push_back(wire);
 | 
									current_ast_mod->children.push_back(wire);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				replace_rules[child->str] = wire->str;
 | 
									replace_rules[child->str] = wire->str;
 | 
				
			||||||
| 
						 | 
					@ -957,7 +959,7 @@ void AstNode::mem2reg_as_needed_pass1(std::set<AstNode*> &mem2reg_set, std::set<
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// actually replace memories with registers
 | 
					// actually replace memories with registers
 | 
				
			||||||
void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *top_block)
 | 
					void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (type == AST_BLOCK)
 | 
						if (type == AST_BLOCK)
 | 
				
			||||||
		block = this;
 | 
							block = this;
 | 
				
			||||||
| 
						 | 
					@ -975,25 +977,15 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
 | 
				
			||||||
		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
 | 
							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->str = id_addr;
 | 
				
			||||||
		wire_addr->is_reg = true;
 | 
							wire_addr->is_reg = true;
 | 
				
			||||||
 | 
							wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
 | 
				
			||||||
		mod->children.push_back(wire_addr);
 | 
							mod->children.push_back(wire_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
 | 
							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->str = id_data;
 | 
				
			||||||
		wire_data->is_reg = true;
 | 
							wire_data->is_reg = true;
 | 
				
			||||||
 | 
							wire_data->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
 | 
				
			||||||
		mod->children.push_back(wire_data);
 | 
							mod->children.push_back(wire_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assert(top_block != NULL);
 | 
					 | 
				
			||||||
		std::vector<RTLIL::State> x_bits;
 | 
					 | 
				
			||||||
		x_bits.push_back(RTLIL::State::Sx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		AstNode *assign_addr_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
 | 
					 | 
				
			||||||
		assign_addr_x->children[0]->str = id_addr;
 | 
					 | 
				
			||||||
		top_block->children.insert(top_block->children.begin(), assign_addr_x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		AstNode *assign_data_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
 | 
					 | 
				
			||||||
		assign_data_x->children[0]->str = id_data;
 | 
					 | 
				
			||||||
		top_block->children.insert(top_block->children.begin(), assign_data_x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		assert(block != NULL);
 | 
							assert(block != NULL);
 | 
				
			||||||
		size_t assign_idx = 0;
 | 
							size_t assign_idx = 0;
 | 
				
			||||||
		while (assign_idx < block->children.size() && block->children[assign_idx] != this)
 | 
							while (assign_idx < block->children.size() && block->children[assign_idx] != this)
 | 
				
			||||||
| 
						 | 
					@ -1036,10 +1028,12 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
 | 
							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->str = id_addr;
 | 
				
			||||||
 | 
							wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
 | 
				
			||||||
		mod->children.push_back(wire_addr);
 | 
							mod->children.push_back(wire_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
 | 
							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->str = id_data;
 | 
				
			||||||
 | 
							wire_data->attributes["\\nosync"] = AstNode::mkconst_int(0, false, 0);
 | 
				
			||||||
		mod->children.push_back(wire_data);
 | 
							mod->children.push_back(wire_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
 | 
							AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
 | 
				
			||||||
| 
						 | 
					@ -1068,17 +1062,6 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
 | 
				
			||||||
		cond_node->children[1]->children.push_back(assign_reg);
 | 
							cond_node->children[1]->children.push_back(assign_reg);
 | 
				
			||||||
		case_node->children.push_back(cond_node);
 | 
							case_node->children.push_back(cond_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (top_block)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			AstNode *assign_addr_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
 | 
					 | 
				
			||||||
			assign_addr_x->children[0]->str = id_addr;
 | 
					 | 
				
			||||||
			top_block->children.insert(top_block->children.begin(), assign_addr_x);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			AstNode *assign_data_x = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false));
 | 
					 | 
				
			||||||
			assign_data_x->children[0]->str = id_data;
 | 
					 | 
				
			||||||
			top_block->children.insert(top_block->children.begin(), assign_data_x);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (block)
 | 
							if (block)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			size_t assign_idx = 0;
 | 
								size_t assign_idx = 0;
 | 
				
			||||||
| 
						 | 
					@ -1107,11 +1090,8 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
 | 
				
			||||||
	assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
 | 
						assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto children_list = children;
 | 
						auto children_list = children;
 | 
				
			||||||
	for (size_t i = 0; i < children_list.size(); i++) {
 | 
						for (size_t i = 0; i < children_list.size(); i++)
 | 
				
			||||||
		if (type == AST_ALWAYS && children_list[i]->type == AST_BLOCK)
 | 
							children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block);
 | 
				
			||||||
			top_block = children_list[i];
 | 
					 | 
				
			||||||
		children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, top_block);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// calulate memory dimensions
 | 
					// calulate memory dimensions
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,11 @@ static void proc_arst(RTLIL::Module *mod, RTLIL::Process *proc, SigMap &assign_m
 | 
				
			||||||
				for (auto &action : sync->actions) {
 | 
									for (auto &action : sync->actions) {
 | 
				
			||||||
					RTLIL::SigSpec rspec = action.second;
 | 
										RTLIL::SigSpec rspec = action.second;
 | 
				
			||||||
					RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
 | 
										RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.width);
 | 
				
			||||||
 | 
										rspec.expand(), rval.expand();
 | 
				
			||||||
 | 
										for (int i = 0; i < int(rspec.chunks.size()); i++)
 | 
				
			||||||
 | 
											if (rspec.chunks[i].wire == NULL)
 | 
				
			||||||
 | 
												rval.chunks[i] = rspec.chunks[i];
 | 
				
			||||||
 | 
										rspec.optimize(), rval.optimize();
 | 
				
			||||||
					RTLIL::SigSpec last_rval;
 | 
										RTLIL::SigSpec last_rval;
 | 
				
			||||||
					for (int count = 0; rval != last_rval; count++) {
 | 
										for (int count = 0; rval != last_rval; count++) {
 | 
				
			||||||
						last_rval = rval;
 | 
											last_rval = rval;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue