mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	verilog: use derived module info to elaborate cell connections
- Attempt to lookup a derived module if it potentially contains a port connection with elaboration ambiguities - Mark the cell if module has not yet been derived - This can be extended to implement automatic hierarchical port connections in a future change
This commit is contained in:
		
							parent
							
								
									bd16d01c0e
								
							
						
					
					
						commit
						e833c6a418
					
				
					 15 changed files with 397 additions and 42 deletions
				
			
		| 
						 | 
				
			
			@ -854,7 +854,7 @@ RTLIL::Const AstNode::bitsAsConst(int width)
 | 
			
		|||
	return bitsAsConst(width, is_signed);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RTLIL::Const AstNode::asAttrConst()
 | 
			
		||||
RTLIL::Const AstNode::asAttrConst() const
 | 
			
		||||
{
 | 
			
		||||
	log_assert(type == AST_CONSTANT);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -869,8 +869,17 @@ RTLIL::Const AstNode::asAttrConst()
 | 
			
		|||
	return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RTLIL::Const AstNode::asParaConst()
 | 
			
		||||
RTLIL::Const AstNode::asParaConst() const
 | 
			
		||||
{
 | 
			
		||||
	if (type == AST_REALVALUE)
 | 
			
		||||
	{
 | 
			
		||||
		AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue));
 | 
			
		||||
		RTLIL::Const val = strnode->asAttrConst();
 | 
			
		||||
		val.flags |= RTLIL::CONST_FLAG_REAL;
 | 
			
		||||
		delete strnode;
 | 
			
		||||
		return val;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	RTLIL::Const val = asAttrConst();
 | 
			
		||||
	if (is_signed)
 | 
			
		||||
		val.flags |= RTLIL::CONST_FLAG_SIGNED;
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,8 +1052,11 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO(zachjs): make design available to simplify() in the future
 | 
			
		||||
		// simplify this module or interface using the current design as context
 | 
			
		||||
		// for lookup up ports and wires within cells
 | 
			
		||||
		set_simplify_design_context(design);
 | 
			
		||||
		while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
 | 
			
		||||
		set_simplify_design_context(nullptr);
 | 
			
		||||
 | 
			
		||||
		if (flag_dump_ast2) {
 | 
			
		||||
			log("Dumping AST after simplification:\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -1171,6 +1183,9 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d
 | 
			
		|||
				continue;
 | 
			
		||||
			module->attributes[attr.first] = attr.second->asAttrConst();
 | 
			
		||||
		}
 | 
			
		||||
		for (const AstNode *node : ast->children)
 | 
			
		||||
			if (node->type == AST_PARAMETER)
 | 
			
		||||
				current_module->avail_parameters(node->str);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (ast->type == AST_INTERFACE)
 | 
			
		||||
| 
						 | 
				
			
			@ -1445,6 +1460,26 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AstModules may contain cells marked with ID::reprocess_after, which indicates
 | 
			
		||||
// that it should be reprocessed once the specified module has been elaborated.
 | 
			
		||||
bool AstModule::reprocess_if_necessary(RTLIL::Design *design)
 | 
			
		||||
{
 | 
			
		||||
	for (const RTLIL::Cell *cell : cells())
 | 
			
		||||
	{
 | 
			
		||||
		std::string modname = cell->get_string_attribute(ID::reprocess_after);
 | 
			
		||||
		if (modname.empty())
 | 
			
		||||
			continue;
 | 
			
		||||
		if (design->module(modname) || design->module("$abstract" + modname)) {
 | 
			
		||||
			log("Reprocessing module %s because instantiated module %s has become available.\n",
 | 
			
		||||
					log_id(name), log_id(modname));
 | 
			
		||||
			loadconfig();
 | 
			
		||||
			process_and_replace_module(design, this, ast, NULL);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again
 | 
			
		||||
// from AST. The interface members are copied into the AST module with the prefix of the interface.
 | 
			
		||||
void AstModule::expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module*> &local_interfaces)
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,6 +1684,17 @@ static std::string serialize_param_value(const RTLIL::Const &val) {
 | 
			
		|||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string AST::derived_module_name(std::string stripped_name, const std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> ¶meters) {
 | 
			
		||||
	std::string para_info;
 | 
			
		||||
	for (const auto &elem : parameters)
 | 
			
		||||
		para_info += stringf("%s=%s", elem.first.c_str(), serialize_param_value(elem.second).c_str());
 | 
			
		||||
 | 
			
		||||
	if (para_info.size() > 60)
 | 
			
		||||
		return "$paramod$" + sha1(para_info) + stripped_name;
 | 
			
		||||
	else
 | 
			
		||||
		return "$paramod" + stripped_name + para_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a new parametric module (when needed) and return the name of the generated module
 | 
			
		||||
std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1657,9 +1703,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
	if (stripped_name.compare(0, 9, "$abstract") == 0)
 | 
			
		||||
		stripped_name = stripped_name.substr(9);
 | 
			
		||||
 | 
			
		||||
	std::string para_info;
 | 
			
		||||
 | 
			
		||||
	int para_counter = 0;
 | 
			
		||||
	std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
 | 
			
		||||
	for (const auto child : ast->children) {
 | 
			
		||||
		if (child->type != AST_PARAMETER)
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -1668,25 +1713,21 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
 | 
			
		|||
		if (it != parameters.end()) {
 | 
			
		||||
			if (!quiet)
 | 
			
		||||
				log("Parameter %s = %s\n", child->str.c_str(), log_signal(it->second));
 | 
			
		||||
			para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str());
 | 
			
		||||
			named_parameters.emplace_back(child->str, it->second);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		it = parameters.find(stringf("$%d", para_counter));
 | 
			
		||||
		if (it != parameters.end()) {
 | 
			
		||||
			if (!quiet)
 | 
			
		||||
				log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(it->second));
 | 
			
		||||
			para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str());
 | 
			
		||||
			named_parameters.emplace_back(child->str, it->second);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	std::string modname;
 | 
			
		||||
	if (parameters.size() == 0)
 | 
			
		||||
		modname = stripped_name;
 | 
			
		||||
	else if (para_info.size() > 60)
 | 
			
		||||
		modname = "$paramod$" + sha1(para_info) + stripped_name;
 | 
			
		||||
	else
 | 
			
		||||
		modname = "$paramod" + stripped_name + para_info;
 | 
			
		||||
	std::string modname = stripped_name;
 | 
			
		||||
	if (parameters.size()) // not named_parameters to cover hierarchical defparams
 | 
			
		||||
		modname = derived_module_name(stripped_name, named_parameters);
 | 
			
		||||
 | 
			
		||||
	if (design->has(modname))
 | 
			
		||||
		return modname;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -262,6 +262,7 @@ namespace AST
 | 
			
		|||
		void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);
 | 
			
		||||
		void meminfo(int &mem_width, int &mem_size, int &addr_bits);
 | 
			
		||||
		bool detect_latch(const std::string &var);
 | 
			
		||||
		const RTLIL::Module* lookup_cell_module();
 | 
			
		||||
 | 
			
		||||
		// additional functionality for evaluating constant functions
 | 
			
		||||
		struct varinfo_t {
 | 
			
		||||
| 
						 | 
				
			
			@ -313,8 +314,8 @@ namespace AST
 | 
			
		|||
		RTLIL::Const bitsAsConst(int width, bool is_signed);
 | 
			
		||||
		RTLIL::Const bitsAsConst(int width = -1);
 | 
			
		||||
		RTLIL::Const bitsAsUnsizedConst(int width);
 | 
			
		||||
		RTLIL::Const asAttrConst();
 | 
			
		||||
		RTLIL::Const asParaConst();
 | 
			
		||||
		RTLIL::Const asAttrConst() const;
 | 
			
		||||
		RTLIL::Const asParaConst() const;
 | 
			
		||||
		uint64_t asInt(bool is_signed);
 | 
			
		||||
		bool bits_only_01() const;
 | 
			
		||||
		bool asBool() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -349,6 +350,7 @@ namespace AST
 | 
			
		|||
		RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail) override;
 | 
			
		||||
		std::string derive_common(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> ¶meters, AstNode **new_ast_out, bool quiet = false);
 | 
			
		||||
		void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces) override;
 | 
			
		||||
		bool reprocess_if_necessary(RTLIL::Design *design) override;
 | 
			
		||||
		RTLIL::Module *clone() const override;
 | 
			
		||||
		void loadconfig() const;
 | 
			
		||||
	};
 | 
			
		||||
| 
						 | 
				
			
			@ -377,6 +379,14 @@ namespace AST
 | 
			
		|||
 | 
			
		||||
	// struct helper exposed from simplify for genrtlil
 | 
			
		||||
	AstNode *make_struct_member_range(AstNode *node, AstNode *member_node);
 | 
			
		||||
 | 
			
		||||
	// generate standard $paramod... derived module name; parameters should be
 | 
			
		||||
	// in the order they are declared in the instantiated module
 | 
			
		||||
	std::string derived_module_name(std::string stripped_name, const std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> ¶meters);
 | 
			
		||||
 | 
			
		||||
	// used to provide simplify() access to the current design for looking up
 | 
			
		||||
	// modules, ports, wires, etc.
 | 
			
		||||
	void set_simplify_design_context(const RTLIL::Design *design);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace AST_INTERNAL
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1917,21 +1917,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (child->type == AST_PARASET) {
 | 
			
		||||
					int extra_const_flags = 0;
 | 
			
		||||
					IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
 | 
			
		||||
					if (child->children[0]->type == AST_REALVALUE) {
 | 
			
		||||
					const AstNode *value = child->children[0];
 | 
			
		||||
					if (value->type == AST_REALVALUE)
 | 
			
		||||
						log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n",
 | 
			
		||||
								log_id(cell), log_id(paraname), child->children[0]->realvalue);
 | 
			
		||||
						extra_const_flags = RTLIL::CONST_FLAG_REAL;
 | 
			
		||||
						auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
 | 
			
		||||
						strnode->cloneInto(child->children[0]);
 | 
			
		||||
						delete strnode;
 | 
			
		||||
					}
 | 
			
		||||
					if (child->children[0]->type != AST_CONSTANT)
 | 
			
		||||
								log_id(cell), log_id(paraname), value->realvalue);
 | 
			
		||||
					else if (value->type != AST_CONSTANT)
 | 
			
		||||
						log_file_error(filename, location.first_line, "Parameter %s.%s with non-constant value!\n",
 | 
			
		||||
								log_id(cell), log_id(paraname));
 | 
			
		||||
					cell->parameters[paraname] = child->children[0]->asParaConst();
 | 
			
		||||
					cell->parameters[paraname].flags |= extra_const_flags;
 | 
			
		||||
					cell->parameters[paraname] = value->asParaConst();
 | 
			
		||||
					continue;
 | 
			
		||||
				}
 | 
			
		||||
				if (child->type == AST_ARGUMENT) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1948,7 +1942,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
 | 
			
		|||
						if (sig.is_wire()) {
 | 
			
		||||
							// if the resulting SigSpec is a wire, its
 | 
			
		||||
							// signedness should match that of the AstNode
 | 
			
		||||
							log_assert(arg->is_signed == sig.as_wire()->is_signed);
 | 
			
		||||
							if (arg->type == AST_IDENTIFIER && arg->id2ast && arg->id2ast->is_signed && !arg->is_signed)
 | 
			
		||||
								// fully-sliced signed wire will be resolved
 | 
			
		||||
								// once the module becomes available
 | 
			
		||||
								log_assert(attributes.count(ID::reprocess_after));
 | 
			
		||||
							else
 | 
			
		||||
								log_assert(arg->is_signed == sig.as_wire()->is_signed);
 | 
			
		||||
						} else if (arg->is_signed) {
 | 
			
		||||
							// non-trivial signed nodes are indirected through
 | 
			
		||||
							// signed wires to enable sign extension
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -564,6 +564,115 @@ static std::string prefix_id(const std::string &prefix, const std::string &str)
 | 
			
		|||
	return prefix + str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// direct access to this global should be limited to the following two functions
 | 
			
		||||
static const RTLIL::Design *simplify_design_context = nullptr;
 | 
			
		||||
 | 
			
		||||
void AST::set_simplify_design_context(const RTLIL::Design *design)
 | 
			
		||||
{
 | 
			
		||||
	log_assert(!simplify_design_context || !design);
 | 
			
		||||
	simplify_design_context = design;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// lookup the module with the given name in the current design context
 | 
			
		||||
static const RTLIL::Module* lookup_module(const std::string &name)
 | 
			
		||||
{
 | 
			
		||||
	return simplify_design_context->module(name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const RTLIL::Module* AstNode::lookup_cell_module()
 | 
			
		||||
{
 | 
			
		||||
	log_assert(type == AST_CELL);
 | 
			
		||||
 | 
			
		||||
	auto reprocess_after = [this] (const std::string &modname) {
 | 
			
		||||
		if (!attributes.count(ID::reprocess_after))
 | 
			
		||||
			attributes[ID::reprocess_after] = AstNode::mkconst_str(modname);
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	const AstNode *celltype = nullptr;
 | 
			
		||||
	for (const AstNode *child : children)
 | 
			
		||||
		if (child->type == AST_CELLTYPE) {
 | 
			
		||||
			celltype = child;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	log_assert(celltype != nullptr);
 | 
			
		||||
 | 
			
		||||
	const RTLIL::Module *module = lookup_module(celltype->str);
 | 
			
		||||
	if (!module)
 | 
			
		||||
		module = lookup_module("$abstract" + celltype->str);
 | 
			
		||||
	if (!module) {
 | 
			
		||||
		if (celltype->str.at(0) != '$')
 | 
			
		||||
			reprocess_after(celltype->str);
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// build a mapping from true param name to param value
 | 
			
		||||
	size_t para_counter = 0;
 | 
			
		||||
	dict<RTLIL::IdString, RTLIL::Const> cell_params_map;
 | 
			
		||||
	for (AstNode *child : children) {
 | 
			
		||||
		if (child->type != AST_PARASET)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (child->str.empty() && para_counter >= module->avail_parameters.size())
 | 
			
		||||
			return nullptr; // let hierarchy handle this error
 | 
			
		||||
		IdString paraname = child->str.empty() ? module->avail_parameters[para_counter++] : child->str;
 | 
			
		||||
 | 
			
		||||
		const AstNode *value = child->children[0];
 | 
			
		||||
		if (value->type != AST_REALVALUE && value->type != AST_CONSTANT)
 | 
			
		||||
			return nullptr; // let genrtlil handle this error
 | 
			
		||||
		cell_params_map[paraname] = value->asParaConst();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// put the parameters in order and generate the derived module name
 | 
			
		||||
	std::vector<std::pair<RTLIL::IdString, RTLIL::Const>> named_parameters;
 | 
			
		||||
	for (RTLIL::IdString param : module->avail_parameters) {
 | 
			
		||||
		auto it = cell_params_map.find(param);
 | 
			
		||||
		if (it != cell_params_map.end())
 | 
			
		||||
			named_parameters.emplace_back(it->first, it->second);
 | 
			
		||||
	}
 | 
			
		||||
	std::string modname = celltype->str;
 | 
			
		||||
	if (cell_params_map.size()) // not named_parameters to cover hierarchical defparams
 | 
			
		||||
		modname = derived_module_name(celltype->str, named_parameters);
 | 
			
		||||
 | 
			
		||||
	// try to find the resolved module
 | 
			
		||||
	module = lookup_module(modname);
 | 
			
		||||
	if (!module) {
 | 
			
		||||
		reprocess_after(modname);
 | 
			
		||||
		return nullptr;
 | 
			
		||||
	}
 | 
			
		||||
	return module;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns whether an expression contains an unbased unsized literal; does not
 | 
			
		||||
// check the literal exists in a self-determined context
 | 
			
		||||
static bool contains_unbased_unsized(const AstNode *node)
 | 
			
		||||
{
 | 
			
		||||
	if (node->type == AST_CONSTANT)
 | 
			
		||||
		return node->is_unsized;
 | 
			
		||||
	for (const AstNode *child : node->children)
 | 
			
		||||
		if (contains_unbased_unsized(child))
 | 
			
		||||
			return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// adds a wire to the current module with the given name that matches the
 | 
			
		||||
// dimensions of the given wire reference
 | 
			
		||||
void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str)
 | 
			
		||||
{
 | 
			
		||||
	AstNode *left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true);
 | 
			
		||||
	AstNode *right = AstNode::mkconst_int(ref->start_offset, true);
 | 
			
		||||
	if (ref->upto)
 | 
			
		||||
		std::swap(left, right);
 | 
			
		||||
	AstNode *range = new AstNode(AST_RANGE, left, right);
 | 
			
		||||
 | 
			
		||||
	AstNode *wire = new AstNode(AST_WIRE, range);
 | 
			
		||||
	wire->is_signed = ref->is_signed;
 | 
			
		||||
	wire->is_logic = true;
 | 
			
		||||
	wire->str = str;
 | 
			
		||||
 | 
			
		||||
	current_ast_mod->children.push_back(wire);
 | 
			
		||||
	current_scope[str] = wire;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// convert the AST into a simpler AST that has all parameters substituted by their
 | 
			
		||||
// values, unrolled for-loops, expanded generate blocks, etc. when this function
 | 
			
		||||
// is done with an AST it can be converted into RTLIL using genRTLIL().
 | 
			
		||||
| 
						 | 
				
			
			@ -920,19 +1029,110 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
 | 
			
		|||
			}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (type == AST_ARGUMENT)
 | 
			
		||||
	{
 | 
			
		||||
		if (children.size() == 1 && children[0]->type == AST_CONSTANT)
 | 
			
		||||
		{
 | 
			
		||||
			// HACK: For port bindings using unbased unsized literals, mark them
 | 
			
		||||
			// signed so they sign-extend. The hierarchy will still incorrectly
 | 
			
		||||
			// generate a warning complaining about resizing the expression.
 | 
			
		||||
			// This also doesn't handle the complex of something like a ternary
 | 
			
		||||
			// expression bound to a port, where the actual size of the port is
 | 
			
		||||
			// needed to resolve the expression correctly.
 | 
			
		||||
			AstNode *arg = children[0];
 | 
			
		||||
			if (arg->is_unsized)
 | 
			
		||||
				arg->is_signed = true;
 | 
			
		||||
	if (type == AST_CELL) {
 | 
			
		||||
		bool lookup_suggested = false;
 | 
			
		||||
 | 
			
		||||
		for (AstNode *child : children) {
 | 
			
		||||
			// simplify any parameters to constants
 | 
			
		||||
			if (child->type == AST_PARASET)
 | 
			
		||||
				while (child->simplify(true, false, false, 1, -1, false, true)) { }
 | 
			
		||||
 | 
			
		||||
			// look for patterns which _may_ indicate ambiguity requiring
 | 
			
		||||
			// resolution of the underlying module
 | 
			
		||||
			if (child->type == AST_ARGUMENT) {
 | 
			
		||||
				if (child->children.size() != 1)
 | 
			
		||||
					continue;
 | 
			
		||||
				const AstNode *value = child->children[0];
 | 
			
		||||
				if (value->type == AST_IDENTIFIER) {
 | 
			
		||||
					const AstNode *elem = value->id2ast;
 | 
			
		||||
					if (elem == nullptr) {
 | 
			
		||||
						if (current_scope.count(value->str))
 | 
			
		||||
							elem = current_scope.at(value->str);
 | 
			
		||||
						else
 | 
			
		||||
							continue;
 | 
			
		||||
					}
 | 
			
		||||
					if (elem->type == AST_MEMORY)
 | 
			
		||||
						// need to determine is the is a read or wire
 | 
			
		||||
						lookup_suggested = true;
 | 
			
		||||
					else if (elem->type == AST_WIRE && elem->is_signed && !value->children.empty())
 | 
			
		||||
						// this may be a fully sliced signed wire which needs
 | 
			
		||||
						// to be indirected to produce an unsigned connection
 | 
			
		||||
						lookup_suggested = true;
 | 
			
		||||
				}
 | 
			
		||||
				else if (contains_unbased_unsized(value))
 | 
			
		||||
					// unbased unsized literals extend to width of the context
 | 
			
		||||
					lookup_suggested = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const RTLIL::Module *module = nullptr;
 | 
			
		||||
		if (lookup_suggested)
 | 
			
		||||
			module = lookup_cell_module();
 | 
			
		||||
		if (module) {
 | 
			
		||||
			size_t port_counter = 0;
 | 
			
		||||
			for (AstNode *child : children) {
 | 
			
		||||
				if (child->type != AST_ARGUMENT)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				// determine the full name of port this argument is connected to
 | 
			
		||||
				RTLIL::IdString port_name;
 | 
			
		||||
				if (child->str.size())
 | 
			
		||||
					port_name = child->str;
 | 
			
		||||
				else {
 | 
			
		||||
					if (port_counter >= module->ports.size())
 | 
			
		||||
						log_file_error(filename, location.first_line,
 | 
			
		||||
								"Cell instance has more ports than the module!\n");
 | 
			
		||||
					port_name = module->ports[port_counter++];
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// find the port's wire in the underlying module
 | 
			
		||||
				const RTLIL::Wire *ref = module->wire(port_name);
 | 
			
		||||
				if (ref == nullptr)
 | 
			
		||||
					log_file_error(filename, location.first_line,
 | 
			
		||||
							"Cell instance refers to port %s which does not exist in module %s!.\n",
 | 
			
		||||
							log_id(port_name), log_id(module->name));
 | 
			
		||||
 | 
			
		||||
				// select the argument, if present
 | 
			
		||||
				log_assert(child->children.size() <= 1);
 | 
			
		||||
				if (child->children.empty())
 | 
			
		||||
					continue;
 | 
			
		||||
				AstNode *arg = child->children[0];
 | 
			
		||||
 | 
			
		||||
				// plain identifiers never need indirection; this also prevents
 | 
			
		||||
				// adding infinite levels of indirection
 | 
			
		||||
				if (arg->type == AST_IDENTIFIER && arg->children.empty())
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				// only add indirection for standard inputs or outputs
 | 
			
		||||
				if (ref->port_input == ref->port_output)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				did_something = true;
 | 
			
		||||
 | 
			
		||||
				// create the indirection wire
 | 
			
		||||
				std::stringstream sstr;
 | 
			
		||||
				sstr << "$indirect$" << ref->name.c_str() << "$" << filename << ":" << location.first_line << "$" << (autoidx++);
 | 
			
		||||
				std::string tmp_str = sstr.str();
 | 
			
		||||
				add_wire_for_ref(ref, tmp_str);
 | 
			
		||||
 | 
			
		||||
				AstNode *asgn = new AstNode(AST_ASSIGN);
 | 
			
		||||
				current_ast_mod->children.push_back(asgn);
 | 
			
		||||
 | 
			
		||||
				AstNode *ident = new AstNode(AST_IDENTIFIER);
 | 
			
		||||
				ident->str = tmp_str;
 | 
			
		||||
				child->children[0] = ident->clone();
 | 
			
		||||
 | 
			
		||||
				if (ref->port_input && !ref->port_output) {
 | 
			
		||||
					asgn->children.push_back(ident);
 | 
			
		||||
					asgn->children.push_back(arg);
 | 
			
		||||
				} else {
 | 
			
		||||
					log_assert(!ref->port_input && ref->port_output);
 | 
			
		||||
					asgn->children.push_back(arg);
 | 
			
		||||
					asgn->children.push_back(ident);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue