diff options
Diffstat (limited to 'frontends/ast')
| -rw-r--r-- | frontends/ast/ast.cc | 292 | ||||
| -rw-r--r-- | frontends/ast/ast.h | 13 | ||||
| -rw-r--r-- | frontends/ast/genrtlil.cc | 158 | ||||
| -rw-r--r-- | frontends/ast/simplify.cc | 109 | 
4 files changed, 453 insertions, 119 deletions
| diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index e79be953a..2c1561552 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -2,6 +2,7 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + *  Copyright (C) 2018  Ruben Undheim <ruben.undheim@gmail.com>   *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above @@ -171,8 +172,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)  	AstNode *attr = attributes.at(id);  	if (attr->type != AST_CONSTANT) -		log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", -			       id.c_str()); +		log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str());  	return attr->integer != 0;  } @@ -903,9 +903,9 @@ RTLIL::Const AstNode::realAsConst(int width)  }  // create a new AstModule from an AST_MODULE AST node -static AstModule* process_module(AstNode *ast, bool defer) +static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL)  { -	log_assert(ast->type == AST_MODULE); +	log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);  	if (defer)  		log("Storing AST representation for module `%s'.\n", ast->str.c_str()); @@ -916,9 +916,14 @@ static AstModule* process_module(AstNode *ast, bool defer)  	current_module->ast = NULL;  	current_module->name = ast->str;  	current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); +	current_module->set_bool_attribute("\\cells_not_processed");  	current_ast_mod = ast; -	AstNode *ast_before_simplify = ast->clone(); +	AstNode *ast_before_simplify; +	if (original_ast != NULL) +		ast_before_simplify = original_ast; +	else +		ast_before_simplify = ast->clone();  	if (flag_dump_ast1) {  		log("Dumping Verilog AST before simplification:\n"); @@ -963,8 +968,7 @@ static AstModule* process_module(AstNode *ast, bool defer)  		for (auto &attr : ast->attributes) {  			if (attr.second->type != AST_CONSTANT) -				log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", -					       attr.first.c_str()); +				log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  			current_module->attributes[attr.first] = attr.second->asAttrConst();  		}  		for (size_t i = 0; i < ast->children.size(); i++) { @@ -989,6 +993,8 @@ static AstModule* process_module(AstNode *ast, bool defer)  		ignoreThisSignalsInInitial = RTLIL::SigSpec();  	} +	if (ast->type == AST_INTERFACE) +		current_module->set_bool_attribute("\\is_interface");  	current_module->ast = ast_before_simplify;  	current_module->nolatches = flag_nolatches;  	current_module->nomeminit = flag_nomeminit; @@ -1031,7 +1037,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump  	log_assert(current_ast->type == AST_DESIGN);  	for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++)  	{ -		if ((*it)->type == AST_MODULE) +		if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE)  		{  			for (auto n : design->verilog_globals)  				(*it)->children.push_back(n->clone()); @@ -1053,8 +1059,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump  			if (design->has((*it)->str)) {  				RTLIL::Module *existing_mod = design->module((*it)->str);  				if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { -					log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", -						       (*it)->str.c_str()); +					log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str());  				} else if (nooverwrite) {  					log("Ignoring re-definition of module `%s' at %s:%d.\n",  							(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); @@ -1083,8 +1088,264 @@ AstModule::~AstModule()  		delete ast;  } + +// An interface port with modport is specified like this: +//    <interface_name>.<modport_name> +// This function splits the interface_name from the modport_name, and fails if it is not a valid combination +std::pair<std::string,std::string> AST::split_modport_from_type(std::string name_type) +{ +	std::string interface_type = ""; +	std::string interface_modport = ""; +	size_t ndots = std::count(name_type.begin(), name_type.end(), '.'); +	// Separate the interface instance name from any modports: +	if (ndots == 0) { // Does not have modport +		interface_type = name_type; +	} +	else { +		std::stringstream name_type_stream(name_type); +		std::string segment; +		std::vector<std::string> seglist; +		while(std::getline(name_type_stream, segment, '.')) { +			seglist.push_back(segment); +		} +		if (ndots == 1) { // Has modport +			interface_type = seglist[0]; +			interface_modport = seglist[1]; +		} +		else { // Erroneous port type +			log_error("More than two '.' in signal port type (%s)\n", name_type.c_str()); +		} +	} +	return std::pair<std::string,std::string>(interface_type, interface_modport); + +} + +AstNode * AST::find_modport(AstNode *intf, std::string name) +{ +	for (auto &ch : intf->children) +		if (ch->type == AST_MODPORT) +			if (ch->str == name) // Modport found +				return ch; +	return NULL; +} + +// Iterate over all wires in an interface and add them as wires in the AST module: +void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) +{ +	for (auto &wire_it : intfmodule->wires_){ +		AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); +		std::string origname = log_id(wire_it.first); +		std::string newname = intfname + "." + origname; +		wire->str = newname; +		if (modport != NULL) { +			bool found_in_modport = false; +			// Search for the current wire in the wire list for the current modport +			for (auto &ch : modport->children) { +				if (ch->type == AST_MODPORTMEMBER) { +					std::string compare_name = "\\" + origname; +					if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output +						found_in_modport = true; +						wire->is_input = ch->is_input; +						wire->is_output = ch->is_output; +						break; +					} +				} +			} +			if (found_in_modport) { +				module_ast->children.push_back(wire); +			} +			else { // If not found in modport, do not create port +				delete wire; +			} +		} +		else { // If no modport, set inout +			wire->is_input = true; +			wire->is_output = true; +			module_ast->children.push_back(wire); +		} +	} +} + +// 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::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces) +{ +	bool is_top = false; +	AstNode *new_ast = ast->clone(); +	for (auto &intf : local_interfaces) { +		std::string intfname = intf.first.str(); +		RTLIL::Module *intfmodule = intf.second; +		for (auto &wire_it : intfmodule->wires_){ +			AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); +			std::string newname = log_id(wire_it.first); +			newname = intfname + "." + newname; +			wire->str = newname; +			new_ast->children.push_back(wire); +		} +	} + +	AstNode *ast_before_replacing_interface_ports = new_ast->clone(); + +	// Explode all interface ports. Note this will only have an effect on 'top +	// level' modules. Other sub-modules will have their interface ports +	// exploded via the derive(..) function +	for (size_t i =0; i<new_ast->children.size(); i++) +	{ +		AstNode *ch2 = new_ast->children[i]; +		if (ch2->type == AST_INTERFACEPORT) { // Is an interface port +			std::string name_port = ch2->str; // Name of the interface port +			if (ch2->children.size() > 0) { +				for(size_t j=0; j<ch2->children.size();j++) { +					AstNode *ch = ch2->children[j]; +					if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface +						std::pair<std::string,std::string> res = split_modport_from_type(ch->str); +						std::string interface_type = res.first; +						std::string interface_modport = res.second; // Is "", if no modport +						if (design->modules_.count(interface_type) > 0) { +							// Add a cell to the module corresponding to the interface port such that +							// it can further propagated down if needed: +							AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); +							celltype_for_intf->str = interface_type; +							AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); +							cell_for_intf->str = name_port + "_inst_from_top_dummy"; +							new_ast->children.push_back(cell_for_intf); + +							// Get all members of this non-overridden dummy interface instance: +							RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming +							                                                              // reprocess_module is called from the hierarchy pass) be +							                                                              // present in design->modules_ +							AstModule *ast_module_of_interface = (AstModule*)intfmodule; +							std::string interface_modport_compare_str = "\\" + interface_modport; +							AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport +							// Iterate over all wires in the interface and add them to the module: +							explode_interface_port(new_ast, intfmodule, name_port, modport); +						} +						break; +					} +				} +			} +		} +	} + +	// The old module will be deleted. Rename and mark for deletion: +	std::string original_name = this->name.str(); +	std::string changed_name = original_name + "_before_replacing_local_interfaces"; +	design->rename(this, changed_name); +	this->set_bool_attribute("\\to_delete"); + +	// Check if the module was the top module. If it was, we need to remove the top attribute and put it on the +	// new module. +	if (this->get_bool_attribute("\\initial_top")) { +		this->attributes.erase("\\initial_top"); +		is_top = true; +	} + +	// Generate RTLIL from AST for the new module and add to the design: +	AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports); +	delete(new_ast); +	design->add(newmod); +	RTLIL::Module* mod = design->module(original_name); +	if (is_top) +		mod->set_bool_attribute("\\top"); + +	// Set the attribute "interfaces_replaced_in_module" so that it does not happen again. +	mod->set_bool_attribute("\\interfaces_replaced_in_module"); +} + +// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces +// This method is used to explode the interface when the interface is a port of the module (not instantiated inside) +RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) +{ +	AstNode *new_ast = NULL; +	std::string modname = derive_common(design, parameters, &new_ast, mayfail); + +	// Since interfaces themselves may be instantiated with different parameters, +	// "modname" must also take those into account, so that unique modules +	// are derived for any variant of interface connections: +	std::string interf_info = ""; + +	bool has_interfaces = false; +	for(auto &intf : interfaces) { +		interf_info += log_id(intf.second->name); +		has_interfaces = true; +	} + +	if (has_interfaces) +		modname += "$interfaces$" + interf_info; + + +	if (!design->has(modname)) { +		new_ast->str = modname; + +		// Iterate over all interfaces which are ports in this module: +		for(auto &intf : interfaces) { +			RTLIL::Module * intfmodule = intf.second; +			std::string intfname = intf.first.str(); +			// Check if a modport applies for the interface port: +			AstNode *modport = NULL; +			if (modports.count(intfname) > 0) { +				std::string interface_modport = modports.at(intfname).str(); +				AstModule *ast_module_of_interface = (AstModule*)intfmodule; +				AstNode *ast_node_of_interface = ast_module_of_interface->ast; +				modport = find_modport(ast_node_of_interface, interface_modport); +			} +			// Iterate over all wires in the interface and add them to the module: +			explode_interface_port(new_ast, intfmodule, intfname, modport); +		} + +		design->add(process_module(new_ast, false)); +		design->module(modname)->check(); + +		RTLIL::Module* mod = design->module(modname); + +		// Now that the interfaces have been exploded, we can delete the dummy port related to every interface. +		for(auto &intf : interfaces) { +			if(mod->wires_.count(intf.first)) { +				mod->wires_.erase(intf.first); +				mod->fixup_ports(); +				// We copy the cell of the interface to the sub-module such that it can further be found if it is propagated +				// down to sub-sub-modules etc. +				RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name); +				new_subcell->set_bool_attribute("\\is_interface"); +			} +			else { +				log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str()); +			} +		} + +		// If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module': +		if (interfaces.size() > 0) { +			mod->set_bool_attribute("\\interfaces_replaced_in_module"); +		} + +	} else { +		log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); +	} + +	delete new_ast; +	return modname; +} + +// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces +RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) +{ +	AstNode *new_ast = NULL; +	std::string modname = derive_common(design, parameters, &new_ast, mayfail); + +	if (!design->has(modname)) { +		new_ast->str = modname; +		design->add(process_module(new_ast, false)); +		design->module(modname)->check(); +	} else { +		log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); +	} + +	delete new_ast; +	return modname; +} +  // create a new parametric module (when needed) and return the name of the generated module -RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool) +std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool)  {  	std::string stripped_name = name.str(); @@ -1156,15 +1417,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R  	else  		modname = "$paramod" + stripped_name + para_info; -	if (!design->has(modname)) { -		new_ast->str = modname; -		design->add(process_module(new_ast, false)); -		design->module(modname)->check(); -	} else { -		log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); -	} -	delete new_ast; +	(*new_ast_out) = new_ast;  	return modname;  } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 7e97bdb3b..08f91c9c3 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -142,6 +142,11 @@ namespace AST  		AST_NEGEDGE,  		AST_EDGE, +		AST_INTERFACE, +		AST_INTERFACEPORT, +		AST_INTERFACEPORTTYPE, +		AST_MODPORT, +		AST_MODPORTMEMBER,  		AST_PACKAGE  	}; @@ -284,6 +289,9 @@ namespace AST  		bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;  		~AstModule() YS_OVERRIDE;  		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; +		RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE; +		std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail); +		void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE;  		RTLIL::Module *clone() const YS_OVERRIDE;  	}; @@ -300,6 +308,11 @@ namespace AST  	// call a DPI function  	AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args); + +	// Helper functions related to handling SystemVerilog interfaces +	std::pair<std::string,std::string> split_modport_from_type(std::string name_type); +	AstNode * find_modport(AstNode *intf, std::string name); +	void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport);  }  namespace AST_INTERNAL diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index c9345ff08..9531dd356 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -55,8 +55,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi  	if (gen_attributes)  		for (auto &attr : that->attributes) {  			if (attr.second->type != AST_CONSTANT) -				log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", -					       attr.first.c_str()); +				log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  			cell->attributes[attr.first] = attr.second->asAttrConst();  		} @@ -89,8 +88,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s  	if (that != NULL)  		for (auto &attr : that->attributes) {  			if (attr.second->type != AST_CONSTANT) -				log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", -					       attr.first.c_str()); +				log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  			cell->attributes[attr.first] = attr.second->asAttrConst();  		} @@ -117,8 +115,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi  	for (auto &attr : that->attributes) {  		if (attr.second->type != AST_CONSTANT) -			log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", -				       attr.first.c_str()); +			log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  		cell->attributes[attr.first] = attr.second->asAttrConst();  	} @@ -152,8 +149,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const  	for (auto &attr : that->attributes) {  		if (attr.second->type != AST_CONSTANT) -			log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", -				       attr.first.c_str()); +			log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  		cell->attributes[attr.first] = attr.second->asAttrConst();  	} @@ -480,8 +476,7 @@ struct AST_INTERNAL::ProcessGenerator  				for (auto &attr : ast->attributes) {  					if (attr.second->type != AST_CONSTANT) -						log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", -							       attr.first.c_str()); +						log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  					sw->attributes[attr.first] = attr.second->asAttrConst();  				} @@ -648,8 +643,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  				while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }  				while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }  				if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", -						       str.c_str()); +					log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  				this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;  				delete left_at_zero_ast;  				delete right_at_zero_ast; @@ -778,7 +772,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  				while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }  				if (children[0]->type != AST_CONSTANT)  					log_file_error(filename, linenum, "System function %s called with non-const argument!\n", -						       RTLIL::unescape_id(str).c_str()); +							RTLIL::unescape_id(str).c_str());  				width_hint = max(width_hint, int(children[0]->asInt(true)));  			}  			break; @@ -799,8 +793,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	default:  		for (auto f : log_files)  			current_ast->dumpAst(f, "verilog-ast> "); -		log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", -			       type2str(type).c_str()); +		log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());  	}  	if (*found_real) @@ -853,6 +846,35 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	case AST_GENIF:  	case AST_GENCASE:  	case AST_PACKAGE: +	case AST_MODPORT: +	case AST_MODPORTMEMBER: +		break; +	case AST_INTERFACEPORT: { +		// If a port in a module with unknown type is found, mark it with the attribute 'is_interface' +		// This is used by the hierarchy pass to know when it can replace interface connection with the individual +		// signals. +		RTLIL::Wire *wire = current_module->addWire(str, 1); +		wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +		wire->start_offset = 0; +		wire->port_id = port_id; +		wire->port_input = true; +		wire->port_output = true; +		wire->set_bool_attribute("\\is_interface"); +		if (children.size() > 0) { +			for(size_t i=0; i<children.size();i++) { +				if(children[i]->type == AST_INTERFACEPORTTYPE) { +					std::pair<std::string,std::string> res = AST::split_modport_from_type(children[i]->str); +					wire->attributes["\\interface_type"] = res.first; +					if (res.second != "") +						wire->attributes["\\interface_modport"] = res.second; +					break; +				} +			} +		} +		wire->upto = 0; +		} +		break; +	case AST_INTERFACEPORTTYPE:  		break;  	// remember the parameter, needed for example in techmap @@ -863,11 +885,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	// create an RTLIL::Wire for an AST_WIRE node  	case AST_WIRE: {  			if (current_module->wires_.count(str) != 0) -				log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str());  			if (!range_valid) -				log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", str.c_str());  			log_assert(range_left >= range_right || (range_left == -1 && range_right == 0)); @@ -881,8 +901,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			for (auto &attr : attributes) {  				if (attr.second->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", -						       attr.first.c_str()); +					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				wire->attributes[attr.first] = attr.second->asAttrConst();  			}  		} @@ -891,16 +910,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	// create an RTLIL::Memory for an AST_MEMORY node  	case AST_MEMORY: {  			if (current_module->memories.count(str) != 0) -				log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str());  			log_assert(children.size() >= 2);  			log_assert(children[0]->type == AST_RANGE);  			log_assert(children[1]->type == AST_RANGE);  			if (!children[0]->range_valid || !children[1]->range_valid) -				log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str());  			RTLIL::Memory *memory = new RTLIL::Memory;  			memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -917,8 +934,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			for (auto &attr : attributes) {  				if (attr.second->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", -						       attr.first.c_str()); +					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				memory->attributes[attr.first] = attr.second->asAttrConst();  			}  		} @@ -937,8 +953,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	case AST_REALVALUE:  		{  			RTLIL::SigSpec sig = realAsConst(width_hint); -			log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", -					 realvalue, log_signal(sig)); +			log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));  			return sig;  		} @@ -949,6 +964,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		{  			RTLIL::Wire *wire = NULL;  			RTLIL::SigChunk chunk; +			bool is_interface = false;  			int add_undef_bits_msb = 0;  			int add_undef_bits_lsb = 0; @@ -964,19 +980,42 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			}  			else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {  				if (id2ast->children[0]->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", -						       str.c_str()); +					log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str());  				chunk = RTLIL::Const(id2ast->children[0]->bits);  				goto use_const_chunk;  			} -			else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE && -					id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0) -				log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", -						str.c_str()); +			else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { +				RTLIL::Wire *current_wire = current_module->wire(str); +				if (current_wire->get_bool_attribute("\\is_interface")) +					is_interface = true; +				// Ignore +			} +			// If an identifier is found that is not already known, assume that it is an interface: +			else if (1) { // FIXME: Check if sv_mode first? +				is_interface = true; +			} +			else { +				log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str()); +			}  			if (id2ast->type == AST_MEMORY) -				log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str()); + +			// If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface' +			// This makes it possible for the hierarchy pass to see what are interface connections and then replace them +			// with the individual signals: +			if (is_interface) { +				RTLIL::Wire *dummy_wire; +				std::string dummy_wire_name = "$dummywireforinterface" + str; +				if (current_module->wires_.count(dummy_wire_name)) +					dummy_wire = current_module->wires_[dummy_wire_name]; +				else { +					dummy_wire = current_module->addWire(dummy_wire_name); +					dummy_wire->set_bool_attribute("\\is_interface"); +				} +				RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire); +				return tmp; +			}  			wire = current_module->wires_[str];  			chunk.wire = wire; @@ -995,8 +1034,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }  					while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }  					if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", -							       str.c_str()); +						log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  					int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;  					AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?  							children[0]->children[1]->clone() : children[0]->children[0]->clone()); @@ -1025,10 +1063,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {  						if (chunk.width == 1)  							log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", -									 str.c_str()); +									str.c_str());  						else -							log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n", -									str.c_str(), chunk.width); +							log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", +									children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width);  						chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);  					} else {  						if (chunk.width + chunk.offset > source_width) { @@ -1041,11 +1079,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  							chunk.offset += add_undef_bits_lsb;  						}  						if (add_undef_bits_lsb) -							log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", -									 str.c_str(), add_undef_bits_lsb); +							log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", +									children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb);  						if (add_undef_bits_msb) -							log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", -									 str.c_str(), add_undef_bits_msb); +							log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", +									children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb);  					}  				}  			} @@ -1380,8 +1418,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			for (auto &attr : attributes) {  				if (attr.second->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", -						       attr.first.c_str()); +					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				cell->attributes[attr.first] = attr.second->asAttrConst();  			} @@ -1403,9 +1440,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  						new_right.append(right[i]);  					}  				log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n" -						 "    old assignment: %s = %s\n    new assignment: %s = %s.\n", -						 log_signal(left), log_signal(right), -						 log_signal(new_left), log_signal(new_right)); +						"    old assignment: %s = %s\n    new assignment: %s = %s.\n", +						log_signal(left), log_signal(right), +						log_signal(new_left), log_signal(new_right));  				left = new_left;  				right = new_right;  			} @@ -1423,6 +1460,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			RTLIL::Cell *cell = current_module->addCell(str, "");  			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass +			cell->set_bool_attribute("\\module_not_derived");  			for (auto it = children.begin(); it != children.end(); it++) {  				AstNode *child = *it; @@ -1436,14 +1475,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;  					if (child->children[0]->type == AST_REALVALUE) {  						log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", -								 log_id(cell), log_id(paraname), child->children[0]->realvalue); +								log_id(cell), log_id(paraname), child->children[0]->realvalue);  						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_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", -							       log_id(cell), log_id(paraname)); +								log_id(cell), log_id(paraname));  					cell->parameters[paraname] = child->children[0]->asParaConst();  					continue;  				} @@ -1464,8 +1503,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			}  			for (auto &attr : attributes) {  				if (attr.second->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", -						       attr.first.c_str()); +					log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				cell->attributes[attr.first] = attr.second->asAttrConst();  			}  		} @@ -1493,18 +1531,17 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				if (GetSize(children) > 1)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n", -						       RTLIL::unescape_id(str).c_str(), GetSize(children)); +							RTLIL::unescape_id(str).c_str(), GetSize(children));  				if (GetSize(children) == 1) {  					if (children[0]->type != AST_CONSTANT)  						log_file_error(filename, linenum, "System function %s called with non-const argument!\n", -							       RTLIL::unescape_id(str).c_str()); +								RTLIL::unescape_id(str).c_str());  					width = children[0]->asInt(true);  				}  				if (width <= 0) -					log_file_error(filename, linenum, "Failed to detect width of %s!\n", -						       RTLIL::unescape_id(str).c_str()); +					log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str());  				Cell *cell = current_module->addCell(myid, str.substr(1));  				cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -1531,8 +1568,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		for (auto f : log_files)  			current_ast->dumpAst(f, "verilog-ast> ");  		type_name = type2str(type); -		log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", -			       type_name.c_str()); +		log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());  	}  	return RTLIL::SigSpec(); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 71eba547c..83714f897 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -71,7 +71,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (stage == 0)  	{ -		log_assert(type == AST_MODULE); +		log_assert(type == AST_MODULE || type == AST_INTERFACE);  		last_blocking_assignment_warn = pair<string, int>();  		deep_recursion_warning = true; @@ -196,7 +196,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		int nargs = GetSize(children);  		if (nargs < 1)  			log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n", -				       str.c_str(), int(children.size())); +					str.c_str(), int(children.size()));  		// First argument is the format string  		AstNode *node_string = children[0]; @@ -240,7 +240,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  					case 'X':  						if (next_arg >= GetSize(children))  							log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", -								       cformat, str.c_str()); +									cformat, str.c_str());  						node_arg = children[next_arg++];  						while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } @@ -450,8 +450,21 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				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); +			if (type == AST_ASSIGN && children[0]->id2ast->is_reg) { +				bool is_rand_reg = false; +				if (children[1]->type == AST_FCALL) { +					if (children[1]->str == "\\$anyconst") +						is_rand_reg = true; +					if (children[1]->str == "\\$anyseq") +						is_rand_reg = true; +					if (children[1]->str == "\\$allconst") +						is_rand_reg = true; +					if (children[1]->str == "\\$allseq") +						is_rand_reg = true; +				} +				if (!is_rand_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; @@ -732,7 +745,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		if (current_scope.at(modname)->type != AST_CELL)  			log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n", -				       RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); +					RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());  		AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);  		paraset->str = paramname; @@ -880,7 +893,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			if (children[0]->type == AST_REALVALUE) {  				RTLIL::Const constvalue = children[0]->realAsConst(width);  				log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", -						 children[0]->realvalue, log_signal(constvalue)); +						children[0]->realvalue, log_signal(constvalue));  				delete children[0];  				children[0] = mkconst_bits(constvalue.bits, sign_hint);  				did_something = true; @@ -1299,8 +1312,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_PRIMITIVE)  	{  		if (children.size() < 2) -			log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", -				       str.c_str()); +			log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", str.c_str());  		std::vector<AstNode*> children_list;  		for (auto child : children) { @@ -1315,8 +1327,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1")  		{  			if (children_list.size() != 3) -				log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", str.c_str());  			std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz); @@ -1336,6 +1347,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			str.clear();  			type = AST_ASSIGN;  			children.push_back(children_list.at(0)); +			children.back()->was_checked = true;  			children.push_back(node);  			did_something = true;  		} @@ -1372,6 +1384,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			str.clear();  			type = AST_ASSIGN;  			children.push_back(children_list[0]); +			children.back()->was_checked = true;  			children.push_back(node);  			did_something = true;  		} @@ -1401,8 +1414,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }  			while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }  			if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) -				log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", -					       str.c_str()); +				log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  			result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;  		}  		did_something = true; @@ -1530,6 +1542,7 @@ skip_dynamic_range_lvalue_expansion:;  			wire_tmp_id->str = wire_tmp->str;  			newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); +			newNode->children.back()->was_checked = true;  			int cursor = 0;  			for (auto child : children[0]->children) @@ -1772,11 +1785,11 @@ skip_dynamic_range_lvalue_expansion:;  				if (GetSize(children) != 1 && GetSize(children) != 2)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				if (!current_always_clocked)  					log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", -						       RTLIL::unescape_id(str).c_str()); +							RTLIL::unescape_id(str).c_str());  				if (GetSize(children) == 2)  				{ @@ -1797,6 +1810,11 @@ skip_dynamic_range_lvalue_expansion:;  				log_assert(block != nullptr); +				if (num_steps == 0) { +					newNode = children[0]->clone(); +					goto apply_newNode; +				} +  				int myidx = autoidx++;  				AstNode *outreg = nullptr; @@ -1815,6 +1833,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *regid = new AstNode(AST_IDENTIFIER);  					regid->str = reg->str;  					regid->id2ast = reg; +					regid->was_checked = true;  					AstNode *rhs = nullptr; @@ -1840,11 +1859,11 @@ skip_dynamic_range_lvalue_expansion:;  			{  				if (GetSize(children) != 1)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				if (!current_always_clocked)  					log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", -						       RTLIL::unescape_id(str).c_str()); +							RTLIL::unescape_id(str).c_str());  				AstNode *present = children.at(0)->clone();  				AstNode *past = clone(); @@ -1857,10 +1876,14 @@ skip_dynamic_range_lvalue_expansion:;  					newNode = new AstNode(AST_NE, past, present);  				else if (str == "\\$rose") -					newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present); +					newNode = new AstNode(AST_LOGIC_AND, +							new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))), +							new AstNode(AST_BIT_AND, present, mkconst_int(1,false)));  				else if (str == "\\$fell") -					newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present)); +					newNode = new AstNode(AST_LOGIC_AND, +							new AstNode(AST_BIT_AND, past, mkconst_int(1,false)), +							new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false))));  				else  					log_abort(); @@ -1878,7 +1901,7 @@ skip_dynamic_range_lvalue_expansion:;  			{  				if (children.size() != 1)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				AstNode *buf = children[0]->clone();  				while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } @@ -1895,7 +1918,7 @@ skip_dynamic_range_lvalue_expansion:;  					if (arg_value.bits.at(i) == RTLIL::State::S1)  						result = i + 1; -				newNode = mkconst_int(result, false); +				newNode = mkconst_int(result, true);  				goto apply_newNode;  			} @@ -1903,11 +1926,11 @@ skip_dynamic_range_lvalue_expansion:;  			{  				if (str == "\\$bits" && children.size() != 1)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				if (str == "\\$size" && children.size() != 1 && children.size() != 2)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				int dim = 1;  				if (str == "\\$size" && children.size() == 2) { @@ -1981,18 +2004,18 @@ skip_dynamic_range_lvalue_expansion:;  				if (func_with_two_arguments) {  					if (children.size() != 2)  						log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n", -							       RTLIL::unescape_id(str).c_str(), int(children.size())); +								RTLIL::unescape_id(str).c_str(), int(children.size()));  				} else {  					if (children.size() != 1)  						log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", -							       RTLIL::unescape_id(str).c_str(), int(children.size())); +								RTLIL::unescape_id(str).c_str(), int(children.size()));  				}  				if (children.size() >= 1) {  					while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (!children[0]->isConst())  						log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", -							       RTLIL::unescape_id(str).c_str()); +								RTLIL::unescape_id(str).c_str());  					int child_width_hint = width_hint;  					bool child_sign_hint = sign_hint;  					children[0]->detectSignWidth(child_width_hint, child_sign_hint); @@ -2003,7 +2026,7 @@ skip_dynamic_range_lvalue_expansion:;  					while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (!children[1]->isConst())  						log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", -							       RTLIL::unescape_id(str).c_str()); +								RTLIL::unescape_id(str).c_str());  					int child_width_hint = width_hint;  					bool child_sign_hint = sign_hint;  					children[1]->detectSignWidth(child_width_hint, child_sign_hint); @@ -2091,7 +2114,7 @@ skip_dynamic_range_lvalue_expansion:;  			{  				if (GetSize(children) < 2 || GetSize(children) > 4)  					log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n", -						       RTLIL::unescape_id(str).c_str(), int(children.size())); +							RTLIL::unescape_id(str).c_str(), int(children.size()));  				AstNode *node_filename = children[0]->clone();  				while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } @@ -2204,6 +2227,8 @@ skip_dynamic_range_lvalue_expansion:;  			AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK,  					new AstNode(AST_ASSIGN_EQ, lvalue, clone()))); +			always->children[0]->children[0]->was_checked = true; +  			current_ast_mod->children.push_back(always);  			goto replace_fcall_with_id; @@ -2253,6 +2278,7 @@ skip_dynamic_range_lvalue_expansion:;  						AstNode *assign = child->is_input ?  								new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) :  								new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); +						assign->children[0]->was_checked = true;  						for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {  							if (*it != current_block_child) @@ -2323,6 +2349,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *assign = child->is_input ?  							new AstNode(AST_ASSIGN_EQ, wire_id, arg) :  							new AstNode(AST_ASSIGN_EQ, arg, wire_id); +					assign->children[0]->was_checked = true;  					for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {  						if (*it != current_block_child) @@ -2762,6 +2789,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  				block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));  				block->children.back()->children[0]->str = memory->str;  				block->children.back()->children[0]->id2ast = memory; +				block->children.back()->children[0]->was_checked = true;  			}  			cursor += increment; @@ -3022,6 +3050,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  		AstNode *newNode = clone();  		newNode->type = AST_ASSIGN_EQ; +		newNode->children[0]->was_checked = true;  		async_block->children[0]->children.push_back(newNode);  		newNode = new AstNode(AST_NONE); @@ -3067,6 +3096,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  		AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, 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;  		block->children.insert(block->children.begin()+assign_idx+1, assign_addr);  		AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); @@ -3090,6 +3120,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  		children[0]->id2ast = NULL;  		children[0]->str = id_data;  		type = AST_ASSIGN_EQ; +		children[0]->was_checked = true;  		did_something = true;  	} @@ -3247,12 +3278,12 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia  		if (!children.empty()) {  			if (children.size() != 1 || children.at(0)->type != AST_RANGE)  				log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			children.at(0)->replace_variables(variables, fcall);  			while (simplify(true, false, false, 1, -1, false, true)) { }  			if (!children.at(0)->range_valid)  				log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			offset = min(children.at(0)->range_left, children.at(0)->range_right);  			width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);  		} @@ -3292,7 +3323,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			while (child->simplify(true, false, false, 1, -1, false, true)) { }  			if (!child->range_valid)  				log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n", -					       child->str.c_str(), fcall->filename.c_str(), fcall->linenum); +						child->str.c_str(), fcall->filename.c_str(), fcall->linenum);  			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; @@ -3336,15 +3367,15 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			if (stmt->children.at(1)->type != AST_CONSTANT)  				log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			if (stmt->children.at(0)->type != AST_IDENTIFIER)  				log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			if (!variables.count(stmt->children.at(0)->str))  				log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			if (stmt->children.at(0)->children.empty()) {  				variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size()); @@ -3352,7 +3383,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  				AstNode *range = stmt->children.at(0)->children.at(0);  				if (!range->range_valid)  					log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n", -						       fcall->filename.c_str(), fcall->linenum); +							fcall->filename.c_str(), fcall->linenum);  				int offset = min(range->range_left, range->range_right);  				int width = std::abs(range->range_left - range->range_right) + 1;  				varinfo_t &v = variables[stmt->children.at(0)->str]; @@ -3384,7 +3415,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			if (cond->type != AST_CONSTANT)  				log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			if (cond->asBool()) {  				block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); @@ -3405,7 +3436,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			if (num->type != AST_CONSTANT)  				log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", -					       fcall->filename.c_str(), fcall->linenum); +						fcall->filename.c_str(), fcall->linenum);  			block->children.erase(block->children.begin());  			for (int i = 0; i < num->bitsAsConst().as_int(); i++) @@ -3443,7 +3474,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  					if (cond->type != AST_CONSTANT)  						log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", -							       fcall->filename.c_str(), fcall->linenum); +								fcall->filename.c_str(), fcall->linenum);  					found_match = cond->asBool();  					delete cond; @@ -3473,7 +3504,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  		}  		log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n", -			       fcall->filename.c_str(), fcall->linenum); +				fcall->filename.c_str(), fcall->linenum);  		log_abort();  	} | 
