diff options
Diffstat (limited to 'frontends/ast')
| -rw-r--r-- | frontends/ast/ast.cc | 46 | ||||
| -rw-r--r-- | frontends/ast/ast.h | 9 | ||||
| -rw-r--r-- | frontends/ast/genrtlil.cc | 203 | ||||
| -rw-r--r-- | frontends/ast/simplify.cc | 262 | 
4 files changed, 253 insertions, 267 deletions
| diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 239813810..ec1cac779 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -182,7 +182,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->location.first_line, "Attribute `%s' with non-constant value!\n", id.c_str());  	return attr->integer != 0;  } @@ -197,7 +197,6 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch  	this->type = type;  	filename = current_filename; -	linenum = get_line_num();  	is_input = false;  	is_output = false;  	is_reg = false; @@ -280,7 +279,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const  	}  	std::string type_name = type2str(type); -	fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum); +	fprintf(f, "%s%s <%s:%d.%d-%d.%d>", indent.c_str(), type_name.c_str(), filename.c_str(), location.first_line, +		location.first_column, location.last_line, location.last_column);  	if (!flag_no_dump_ptr) {  		if (id2ast) @@ -951,7 +951,8 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast  	current_module = new AstModule;  	current_module->ast = NULL;  	current_module->name = ast->str; -	current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); +	current_module->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, +		ast->location.first_column, ast->location.last_line, ast->location.last_column);  	current_module->set_bool_attribute("\\cells_not_processed");  	current_ast_mod = ast; @@ -1028,14 +1029,14 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast  		if (!blackbox_module && ast->attributes.count("\\blackbox")) {  			AstNode *n = ast->attributes.at("\\blackbox");  			if (n->type != AST_CONSTANT) -				log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n"); +				log_file_error(ast->filename, ast->location.first_line, "Got blackbox attribute with non-constant value!\n");  			blackbox_module = n->asBool();  		}  		if (blackbox_module && ast->attributes.count("\\whitebox")) {  			AstNode *n = ast->attributes.at("\\whitebox");  			if (n->type != AST_CONSTANT) -				log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n"); +				log_file_error(ast->filename, ast->location.first_line, "Got whitebox attribute with non-constant value!\n");  			blackbox_module = !n->asBool();  		} @@ -1043,7 +1044,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast  			if (blackbox_module) {  				AstNode *n = ast->attributes.at("\\noblackbox");  				if (n->type != AST_CONSTANT) -					log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n"); +					log_file_error(ast->filename, ast->location.first_line, "Got noblackbox attribute with non-constant value!\n");  				blackbox_module = !n->asBool();  			}  			delete ast->attributes.at("\\noblackbox"); @@ -1089,7 +1090,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast  		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->location.first_line, "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++) { @@ -1202,15 +1203,15 @@ 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_blackbox_attribute()) { -					log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str()); +					log_file_error((*it)->filename, (*it)->location.first_line, "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); +					log("Ignoring re-definition of module `%s' at %s:%d.%d-%d.%d.\n", +							(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->location.first_line, (*it)->location.first_column, (*it)->location.last_line, (*it)->location.last_column);  					continue;  				} else { -					log("Replacing existing%s module `%s' at %s:%d.\n", +					log("Replacing existing%s module `%s' at %s:%d.%d-%d.%d.\n",  							existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", -							(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); +							(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->location.first_line, (*it)->location.first_column, (*it)->location.last_line, (*it)->location.last_column);  					design->remove(existing_mod);  				}  			} @@ -1625,25 +1626,6 @@ void AstModule::loadconfig() const  	flag_icells = icells;  	flag_pwires = pwires;  	flag_autowire = autowire; -	use_internal_line_num(); -} - -// internal dummy line number callbacks -namespace { -	int internal_line_num; -	void internal_set_line_num(int n) { -		internal_line_num = n; -	} -	int internal_get_line_num() { -		return internal_line_num; -	} -} - -// use internal dummy line number callbacks -void AST::use_internal_line_num() -{ -	set_line_num = &internal_set_line_num; -	get_line_num = &internal_get_line_num;  }  YOSYS_NAMESPACE_END diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index a50ae306d..816de005c 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -156,6 +156,13 @@ namespace AST  		AST_TYPEDEF  	}; +	struct AstSrcLocType { +		unsigned int first_line, last_line; +		unsigned int first_column, last_column; +		AstSrcLocType() : first_line(0), last_line(0), first_column(0), last_column(0) {} +		AstSrcLocType(int _first_line, int _first_column, int _last_line, int _last_column) : first_line(_first_line), last_line(_last_line), first_column(_first_column), last_column(_last_column) {} +	}; +  	// convert an node type to a string (e.g. for debug output)  	std::string type2str(AstNodeType type); @@ -199,7 +206,7 @@ namespace AST  		// it is automatically set by the constructor using AST::current_filename and  		// the AST::get_line_num() callback function.  		std::string filename; -		int linenum; +		AstSrcLocType location;  		// creating and deleting nodes  		AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 3fb6b3e5c..6e4e837b5 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -44,18 +44,18 @@ using namespace AST_INTERNAL;  static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true)  {  	std::stringstream sstr; -	sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); +	sstr << type << "$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++);  	RTLIL::Cell *cell = current_module->addCell(sstr.str(), type); -	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); -	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  			cell->attributes[attr.first] = attr.second->asAttrConst();  		} @@ -77,18 +77,18 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s  	}  	std::stringstream sstr; -	sstr << "$extend" << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); +	sstr << "$extend" << "$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++);  	RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$pos"); -	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", width); -	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  			cell->attributes[attr.first] = attr.second->asAttrConst();  		} @@ -105,17 +105,17 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s  static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)  {  	std::stringstream sstr; -	sstr << type << "$" << that->filename << ":" << that->linenum << "$" << (autoidx++); +	sstr << type << "$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++);  	RTLIL::Cell *cell = current_module->addCell(sstr.str(), type); -	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); -	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  		cell->attributes[attr.first] = attr.second->asAttrConst();  	} @@ -139,17 +139,17 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const  	log_assert(cond.size() == 1);  	std::stringstream sstr; -	sstr << "$ternary$" << that->filename << ":" << that->linenum << "$" << (autoidx++); +	sstr << "$ternary$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++);  	RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$mux"); -	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	cell->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", left.size()); -	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->linenum); +	wire->attributes["\\src"] = stringf("%s:%d", that->filename.c_str(), that->location.first_line);  	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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  		cell->attributes[attr.first] = attr.second->asAttrConst();  	} @@ -199,11 +199,11 @@ struct AST_INTERNAL::ProcessGenerator  	{  		// generate process and simple root case  		proc = new RTLIL::Process; -		proc->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum); -		proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++); +		proc->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", always->filename.c_str(), always->location.first_line, always->location.first_column, always->location.last_line, always->location.last_column); +		proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->location.first_line, autoidx++);  		for (auto &attr : always->attributes) {  			if (attr.second->type != AST_CONSTANT) -				log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n", +				log_file_error(always->filename, always->location.first_line, "Attribute `%s' with non-constant value!\n",  						attr.first.c_str());  			proc->attributes[attr.first] = attr.second->asAttrConst();  		} @@ -234,8 +234,8 @@ struct AST_INTERNAL::ProcessGenerator  		if (found_anyedge_syncs) {  			if (found_global_syncs) -				log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); -			log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum); +				log_file_error(always->filename, always->location.first_line, "Found non-synthesizable event list!\n"); +			log("Note: Assuming pure combinatorial block at %s:%d.%d-%d.%d in\n", always->filename.c_str(), always->location.first_line, always->location.first_column, always->location.last_line, always->location.last_column);  			log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");  			log("use of @* instead of @(...) for better match of synthesis and simulation.\n");  		} @@ -249,12 +249,12 @@ struct AST_INTERNAL::ProcessGenerator  					continue;  				found_clocked_sync = true;  				if (found_global_syncs || found_anyedge_syncs) -					log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); +					log_file_error(always->filename, always->location.first_line, "Found non-synthesizable event list!\n");  				RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;  				syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;  				syncrule->signal = child->children[0]->genRTLIL();  				if (GetSize(syncrule->signal) != 1) -					log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n"); +					log_file_error(always->filename, always->location.first_line, "Found posedge/negedge event on a signal that is not 1 bit wide!\n");  				addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);  				proc->syncs.push_back(syncrule);  			} @@ -335,7 +335,7 @@ struct AST_INTERNAL::ProcessGenerator  			} while (current_module->wires_.count(wire_name) > 0);  			RTLIL::Wire *wire = current_module->addWire(wire_name, chunk.width); -			wire->attributes["\\src"] = stringf("%s:%d", always->filename.c_str(), always->linenum); +			wire->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", always->filename.c_str(), always->location.first_line, always->location.first_column, always->location.last_line, always->location.last_column);  			chunk.wire = wire;  			chunk.offset = 0; @@ -470,13 +470,13 @@ struct AST_INTERNAL::ProcessGenerator  		case AST_CASE:  			{  				RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; -				sw->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); +				sw->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", ast->filename.c_str(), ast->location.first_line, ast->location.first_column, ast->location.last_line, ast->location.last_column);  				sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap());  				current_case->switches.push_back(sw);  				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->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  					sw->attributes[attr.first] = attr.second->asAttrConst();  				} @@ -504,7 +504,7 @@ struct AST_INTERNAL::ProcessGenerator  					RTLIL::CaseRule *backup_case = current_case;  					current_case = new RTLIL::CaseRule; -					current_case->attributes["\\src"] = stringf("%s:%d", child->filename.c_str(), child->linenum); +					current_case->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", child->filename.c_str(), child->location.first_line, child->location.first_column, child->location.last_line, child->location.last_column);  					last_generated_case = current_case;  					addChunkActions(current_case->actions, this_case_eq_ltemp, this_case_eq_rvalue);  					for (auto node : child->children) { @@ -554,16 +554,16 @@ struct AST_INTERNAL::ProcessGenerator  			break;  		case AST_WIRE: -			log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n"); +			log_file_error(ast->filename, ast->location.first_line, "Found reg declaration in block without label!\n");  			break;  		case AST_ASSIGN: -			log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n"); +			log_file_error(ast->filename, ast->location.first_line, "Found continous assignment in always/initial block!\n");  			break;  		case AST_PARAMETER:  		case AST_LOCALPARAM: -			log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n"); +			log_file_error(ast->filename, ast->location.first_line, "Found parameter declaration in block without label!\n");  			break;  		case AST_NONE: @@ -614,7 +614,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  		if (id_ast == NULL && current_scope.count(str))  			id_ast = current_scope.at(str);  		if (!id_ast) -			log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str()); +			log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", str.c_str());  		if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) {  			if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {  				this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; @@ -624,7 +624,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  			if (id_ast->children[0]->type == AST_CONSTANT)  				this_width = id_ast->children[0]->bits.size();  			else -				log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str()); +				log_file_error(filename, location.first_line, "Failed to detect width for parameter %s!\n", str.c_str());  			if (children.size() != 0)  				range = children[0];  		} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { @@ -636,7 +636,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  					// log("---\n");  					// id_ast->dumpAst(NULL, "decl> ");  					// dumpAst(NULL, "ref> "); -					log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str()); +					log_file_error(filename, location.first_line, "Failed to detect width of signal access `%s'!\n", str.c_str());  				}  			} else {  				this_width = id_ast->range_left - id_ast->range_right + 1; @@ -647,12 +647,12 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  			this_width = 32;  		} else if (id_ast->type == AST_MEMORY) {  			if (!id_ast->children[0]->range_valid) -				log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); +				log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", str.c_str());  			this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;  			if (children.size() > 1)  				range = children[1];  		} else -			log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); +			log_file_error(filename, location.first_line, "Failed to detect width for identifier %s!\n", str.c_str());  		if (range) {  			if (range->children.size() == 1)  				this_width = 1; @@ -662,7 +662,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, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  				this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;  				delete left_at_zero_ast;  				delete right_at_zero_ast; @@ -678,7 +678,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	case AST_TO_BITS:  		while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }  		if (children[0]->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n"); +			log_file_error(filename, location.first_line, "Left operand of tobits expression is not constant!\n");  		children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);  		width_hint = max(width_hint, children[0]->bitsAsConst().as_int());  		break; @@ -706,7 +706,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	case AST_REPLICATE:  		while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }  		if (children[0]->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); +			log_file_error(filename, location.first_line, "Left operand of replicate expression is not constant!\n");  		children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);  		width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);  		sign_hint = false; @@ -780,7 +780,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  		if (!id2ast->is_signed)  			sign_hint = false;  		if (!id2ast->children[0]->range_valid) -			log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); +			log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", str.c_str());  		this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;  		width_hint = max(width_hint, this_width);  		break; @@ -790,7 +790,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  			if (GetSize(children) == 1) {  				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", +					log_file_error(filename, location.first_line, "System function %s called with non-const argument!\n",  							RTLIL::unescape_id(str).c_str());  				width_hint = max(width_hint, int(children[0]->asInt(true)));  			} @@ -812,7 +812,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	default:  		for (auto f : log_files)  			current_ast_mod->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, location.first_line, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());  	}  	if (*found_real) @@ -845,7 +845,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	std::string type_name;  	current_filename = filename; -	set_line_num(linenum);  	switch (type)  	{ @@ -874,7 +873,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		// 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->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  		wire->start_offset = 0;  		wire->port_id = port_id;  		wire->port_input = true; @@ -905,18 +904,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		if (flag_pwires)  		{  			if (GetSize(children) < 1 || children[0]->type != AST_CONSTANT) -				log_file_error(filename, linenum, "Parameter `%s' with non-constant value!\n", str.c_str()); +				log_file_error(filename, location.first_line, "Parameter `%s' with non-constant value!\n", str.c_str());  			RTLIL::Const val = children[0]->bitsAsConst();  			RTLIL::Wire *wire = current_module->addWire(str, GetSize(val));  			current_module->connect(wire, val); -			wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			wire->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			wire->attributes[type == AST_PARAMETER ? "\\parameter" : "\\localparam"] = 1;  			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, location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				wire->attributes[attr.first] = attr.second->asAttrConst();  			}  		} @@ -925,15 +924,15 @@ 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, location.first_line, "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, location.first_line, "Signal `%s' with non-constant width!\n", str.c_str());  			if (!(range_left >= range_right || (range_left == -1 && range_right == 0))) -				log_file_error(filename, linenum, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1); +				log_file_error(filename, location.first_line, "Signal `%s' with invalid width range %d!\n", str.c_str(), range_left - range_right + 1);  			RTLIL::Wire *wire = current_module->addWire(str, range_left - range_right + 1); -			wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			wire->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			wire->start_offset = range_right;  			wire->port_id = port_id;  			wire->port_input = is_input; @@ -942,7 +941,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, location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				wire->attributes[attr.first] = attr.second->asAttrConst();  			} @@ -954,17 +953,17 @@ 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, location.first_line, "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, location.first_line, "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); +			memory->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			memory->name = str;  			memory->width = children[0]->range_left - children[0]->range_right + 1;  			if (children[1]->range_right < children[1]->range_left) { @@ -978,7 +977,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, location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				memory->attributes[attr.first] = attr.second->asAttrConst();  			}  		} @@ -1001,7 +1000,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			}  			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, location.first_line, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));  			return sig;  		} @@ -1019,16 +1018,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) {  				RTLIL::Wire *wire = current_module->addWire(str); -				wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +				wire->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  				wire->name = str;  				if (flag_autowire) -					log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str()); +					log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str());  				else -					log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); +					log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());  			}  			else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM || id2ast->type == AST_ENUM_ITEM) {  				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, location.first_line, "Parameter %s does not evaluate to constant value!\n", str.c_str());  				chunk = RTLIL::Const(id2ast->children[0]->bits);  				goto use_const_chunk;  			} @@ -1043,11 +1042,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				is_interface = true;  			}  			else { -				log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str()); +				log_file_error(filename, location.first_line, "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, location.first_line, "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 @@ -1073,7 +1072,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		use_const_chunk:  			if (children.size() != 0) {  				if (children[0]->type != AST_RANGE) -					log_file_error(filename, linenum, "Single range expected.\n"); +					log_file_error(filename, location.first_line, "Single range expected.\n");  				int source_width = id2ast->range_left - id2ast->range_right + 1;  				int source_offset = id2ast->range_right;  				if (!children[0]->range_valid) { @@ -1082,7 +1081,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, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  					int width = abs(int(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()); @@ -1110,10 +1109,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  						chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);  					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", +							log_file_warning(filename, location.first_line, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",  									str.c_str());  						else -							log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", +							log_file_warning(filename, location.first_line, "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 { @@ -1127,10 +1126,10 @@ 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 [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", +							log_file_warning(filename, location.first_line, "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 [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", +							log_file_warning(filename, location.first_line, "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);  					}  				} @@ -1170,7 +1169,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			RTLIL::SigSpec left = children[0]->genRTLIL();  			RTLIL::SigSpec right = children[1]->genRTLIL();  			if (!left.is_fully_const()) -				log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); +				log_file_error(filename, location.first_line, "Left operand of replicate expression is not constant!\n");  			int count = left.as_int();  			RTLIL::SigSpec sig;  			for (int i = 0; i < count; i++) @@ -1360,13 +1359,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	case AST_MEMRD:  		{  			std::stringstream sstr; -			sstr << "$memrd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); +			sstr << "$memrd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  			RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memrd"); -			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), location.first_line);  			RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width); -			wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), location.first_line);  			int mem_width, mem_size, addr_bits;  			is_signed = id2ast->is_signed; @@ -1398,10 +1397,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	case AST_MEMINIT:  		{  			std::stringstream sstr; -			sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++); +			sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  			RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit"); -			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			cell->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			int mem_width, mem_size, addr_bits;  			id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -1409,7 +1408,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			int num_words = 1;  			if (type == AST_MEMINIT) {  				if (children[2]->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Memory init with non-constant word count!\n"); +					log_file_error(filename, location.first_line, "Memory init with non-constant word count!\n");  				num_words = int(children[2]->asInt(false));  				cell->parameters["\\WORDS"] = RTLIL::Const(num_words);  			} @@ -1461,18 +1460,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			IdString cellname;  			if (str.empty()) {  				std::stringstream sstr; -				sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); +				sstr << celltype << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  				cellname = sstr.str();  			} else {  				cellname = str;  			}  			RTLIL::Cell *cell = current_module->addCell(cellname, celltype); -			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			cell->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			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, location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str());  				cell->attributes[attr.first] = attr.second->asAttrConst();  			} @@ -1493,7 +1492,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  						new_left.append(left[i]);  						new_right.append(right[i]);  					} -				log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n" +				log_file_warning(filename, location.first_line, "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)); @@ -1510,10 +1509,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			int port_counter = 0, para_counter = 0;  			if (current_module->count_id(str) != 0) -				log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str()); +				log_file_error(filename, location.first_line, "Re-definition of cell `%s'!\n", str.c_str());  			RTLIL::Cell *cell = current_module->addCell(str, ""); -			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +			cell->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			// Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass  			cell->set_bool_attribute("\\module_not_derived"); @@ -1529,7 +1528,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					int extra_const_flags = 0;  					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_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)); @@ -1537,7 +1536,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  						delete strnode;  					}  					if (child->children[0]->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", +						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; @@ -1560,7 +1559,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, location.first_line, "Attribute `%s' with non-constant value.\n", attr.first.c_str());  				cell->attributes[attr.first] = attr.second->asAttrConst();  			}  			if (cell->type == "$specify2") { @@ -1568,7 +1567,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				int dst_width = GetSize(cell->getPort("\\DST"));  				bool full = cell->getParam("\\FULL").as_bool();  				if (!full && src_width != dst_width) -					log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n"); +					log_file_error(filename, location.first_line, "Parallel specify SRC width does not match DST width.\n");  				cell->setParam("\\SRC_WIDTH", Const(src_width));  				cell->setParam("\\DST_WIDTH", Const(dst_width));  			} @@ -1576,7 +1575,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				int dat_width = GetSize(cell->getPort("\\DAT"));  				int dst_width = GetSize(cell->getPort("\\DST"));  				if (dat_width != dst_width) -					log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); +					log_file_error(filename, location.first_line, "Specify DAT width does not match DST width.\n");  				int src_width = GetSize(cell->getPort("\\SRC"));  				cell->setParam("\\SRC_WIDTH", Const(src_width));  				cell->setParam("\\DST_WIDTH", Const(dst_width)); @@ -1608,30 +1607,30 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			int sz = children.size();  			if (str == "$info") {  				if (sz > 0) -					log_file_info(filename, linenum, "%s.\n", children[0]->str.c_str()); +					log_file_info(filename, location.first_line, "%s.\n", children[0]->str.c_str());  				else -					log_file_info(filename, linenum, "\n"); +					log_file_info(filename, location.first_line, "\n");  			} else if (str == "$warning") {  				if (sz > 0) -					log_file_warning(filename, linenum, "%s.\n", children[0]->str.c_str()); +					log_file_warning(filename, location.first_line, "%s.\n", children[0]->str.c_str());  				else -					log_file_warning(filename, linenum, "\n"); +					log_file_warning(filename, location.first_line, "\n");  			} else if (str == "$error") {  				if (sz > 0) -					log_file_error(filename, linenum, "%s.\n", children[0]->str.c_str()); +					log_file_error(filename, location.first_line, "%s.\n", children[0]->str.c_str());  				else -					log_file_error(filename, linenum, "\n"); +					log_file_error(filename, location.first_line, "\n");  			} else if (str == "$fatal") {  				// TODO: 1st parameter, if exists, is 0,1 or 2, and passed to $finish()  				// if no parameter is given, default value is 1  				// dollar_finish(sz ? children[0] : 1);  				// perhaps create & use log_file_fatal()  				if (sz > 0) -					log_file_error(filename, linenum, "FATAL: %s.\n", children[0]->str.c_str()); +					log_file_error(filename, location.first_line, "FATAL: %s.\n", children[0]->str.c_str());  				else -					log_file_error(filename, linenum, "FATAL.\n"); +					log_file_error(filename, location.first_line, "FATAL.\n");  			} else { -				log_file_error(filename, linenum, "Unknown elabortoon system task '%s'.\n", str.c_str()); +				log_file_error(filename, location.first_line, "Unknown elabortoon system task '%s'.\n", str.c_str());  			}  		} break; @@ -1642,32 +1641,32 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				int width = width_hint;  				if (GetSize(children) > 1) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 0.\n",  							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", +						log_file_error(filename, location.first_line, "System function %s called with non-const argument!\n",  								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, location.first_line, "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); +				cell->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  				cell->parameters["\\WIDTH"] = width;  				if (attributes.count("\\reg")) {  					auto &attr = attributes.at("\\reg");  					if (attr->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n"); +						log_file_error(filename, location.first_line, "Attribute `reg' with non-constant value!\n");  					cell->attributes["\\reg"] =  attr->asAttrConst();  				}  				Wire *wire = current_module->addWire(myid + "_wire", width); -				wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); +				wire->attributes["\\src"] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  				cell->setPort("\\Y", wire);  				is_signed = sign_hint; @@ -1680,7 +1679,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		for (auto f : log_files)  			current_ast_mod->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, location.first_line, "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 57107b76a..2c61f65f4 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -53,7 +53,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  		{  			// If there's no next character, that's a problem  			if (i+1 >= sformat.length()) -				log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); +				log_file_error(filename, location.first_line, "System task `%s' called with `%%' at end of string.\n", str.c_str());  			char cformat = sformat[++i]; @@ -77,13 +77,13 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  				case 'x':  				case 'X':  					if (next_arg >= GetSize(children)) -						log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", +						log_file_error(filename, location.first_line, "Missing argument for %%%c format specifier in system task `%s'.\n",  								cformat, str.c_str());  					node_arg = children[next_arg++];  					while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (node_arg->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); +						log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());  					break;  				case 'm': @@ -91,7 +91,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg  					break;  				default: -					log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); +					log_file_error(filename, location.first_line, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());  					break;  			} @@ -159,7 +159,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  #if 0  	log("-------------\n"); -	log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this); +	log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this);  	log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",  			int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));  	// dumpAst(NULL, "> "); @@ -251,7 +251,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  						if (it.first != ID(mem2reg))  							reg->attributes.emplace(it.first, it.second->clone());  					reg->filename = node->filename; -					reg->linenum = node->linenum; +					reg->location = node->location;  					children.push_back(reg);  					while (reg->simplify(true, false, false, 1, -1, false, false)) { }  				} @@ -273,7 +273,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	}  	current_filename = filename; -	set_line_num(linenum);  	// we do not look inside a task or function  	// (but as soon as a task or function is instantiated we process the generated AST as usual) @@ -286,13 +285,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list  	if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||  			str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { -		log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); +		log_file_warning(filename, location.first_line, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str());  		delete_children();  		str = std::string();  	}  	if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { -		log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); +		log_file_warning(filename, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str());  		delete_children();  		str = std::string();  	} @@ -304,14 +303,14 @@ 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", +			log_file_error(filename, location.first_line, "System task `%s' got %d arguments, expected >= 1.\n",  					str.c_str(), int(children.size()));  		// First argument is the format string  		AstNode *node_string = children[0];  		while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  		if (node_string->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); +			log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str());  		std::string sformat = node_string->bitsAsConst().decode_string();  		std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);  		// Finally, print the message (only include a \n for $display, not for $write) @@ -405,7 +404,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  					continue;  				wires_are_incompatible:  					if (stage > 1) -						log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str()); +						log_file_error(filename, location.first_line, "Incompatible re-declaration of wire %s.\n", node->str.c_str());  					continue;  				}  				this_wire_scope[node->str] = node; @@ -451,7 +450,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_ALWAYS || type == AST_INITIAL)  	{  		if (current_always != nullptr) -			log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n"); +			log_file_error(filename, location.first_line, "Invalid nesting of always blocks and/or initializations.\n");  		current_always = this;  		current_always_clocked = false; @@ -494,7 +493,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic)  				children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment  			if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) -				log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); +				log_warning("wire '%s' is assigned in a block at %s:%d.%d-%d.%d.\n", children[0]->str.c_str(), filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			if (type == AST_ASSIGN && children[0]->id2ast->is_reg) {  				bool is_rand_reg = false;  				if (children[1]->type == AST_FCALL) { @@ -508,7 +507,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  						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); +					log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.%d-%d.%d.\n", children[0]->str.c_str(), filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column);  			}  			children[0]->was_checked = true;  		} @@ -535,7 +534,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true)  				did_something = true;  			if (!children[1]->range_valid) -				log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); +				log_file_error(filename, location.first_line, "Non-constant width range on parameter decl.\n");  			width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);  		}  		break; @@ -547,7 +546,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param))  				did_something = true;  			if (!children[1]->range_valid) -				log_file_error(filename, linenum, "Non-constant width range on enum item decl.\n"); +				log_file_error(filename, location.first_line, "Non-constant width range on enum item decl.\n");  			width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);  		}  		break; @@ -786,7 +785,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	}  	current_filename = filename; -	set_line_num(linenum);  	if (type == AST_MODULE)  		current_scope.clear(); @@ -795,7 +793,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_DEFPARAM && !children.empty())  	{  		if (children[0]->type != AST_IDENTIFIER) -			log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n"); +			log_file_error(filename, location.first_line, "Module name in defparam contains non-constant expressions!\n");  		string modname, paramname = children[0]->str; @@ -812,12 +810,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		}  		if (pos == std::string::npos) -			log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str()); +			log_file_error(filename, location.first_line, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str());  		paramname = "\\" + paramname.substr(pos+1);  		if (current_scope.at(modname)->type != AST_CELL) -			log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n", +			log_file_error(filename, location.first_line, "Defparam argument `%s . %s` does not match a cell!\n",  					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); @@ -843,10 +841,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			log_assert(children.size() >= 1);  			log_assert(children[0]->type == AST_WIRETYPE);  			if (!current_scope.count(children[0]->str)) -				log_file_error(filename, linenum, "Unknown identifier `%s' used as type name\n", children[0]->str.c_str()); +				log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", children[0]->str.c_str());  			AstNode *resolved_type = current_scope.at(children[0]->str);  			if (resolved_type->type != AST_TYPEDEF) -				log_file_error(filename, linenum, "`%s' does not name a type\n", children[0]->str.c_str()); +				log_file_error(filename, location.first_line, "`%s' does not name a type\n", children[0]->str.c_str());  			log_assert(resolved_type->children.size() == 1);  			AstNode *templ = resolved_type->children[0];  			// Remove type reference @@ -949,10 +947,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			log_assert(children.size() == 2);  			log_assert(children[1]->type == AST_WIRETYPE);  			if (!current_scope.count(children[1]->str)) -				log_file_error(filename, linenum, "Unknown identifier `%s' used as type name\n", children[1]->str.c_str()); +				log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", children[1]->str.c_str());  			AstNode *resolved_type = current_scope.at(children[1]->str);  			if (resolved_type->type != AST_TYPEDEF) -				log_file_error(filename, linenum, "`%s' does not name a type\n", children[1]->str.c_str()); +				log_file_error(filename, location.first_line, "`%s' does not name a type\n", children[1]->str.c_str());  			log_assert(resolved_type->children.size() == 1);  			AstNode *templ = resolved_type->children[0];  			delete children[1]; @@ -962,7 +960,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			while(templ->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {};  			if (templ->type == AST_MEMORY) -				log_file_error(filename, linenum, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); +				log_file_error(filename, location.first_line, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str());  			is_signed = templ->is_signed;  			is_string = templ->is_string;  			is_custom_type = templ->is_custom_type; @@ -983,7 +981,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_PREFIX) {  		if (children[0]->type != AST_CONSTANT) {  			// dumpAst(NULL, ">   "); -			log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n"); +			log_file_error(filename, location.first_line, "Index in generate block prefix syntax is not constant!\n");  		}  		if (children[1]->type == AST_PREFIX)  			children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param); @@ -999,9 +997,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	// evaluate TO_BITS nodes  	if (type == AST_TO_BITS) {  		if (children[0]->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n"); +			log_file_error(filename, location.first_line, "Left operand of to_bits expression is not constant!\n");  		if (children[1]->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n"); +			log_file_error(filename, location.first_line, "Right operand of to_bits expression is not constant!\n");  		RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed);  		newNode = mkconst_bits(new_value.bits, children[1]->is_signed);  		goto apply_newNode; @@ -1065,7 +1063,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		multirange_dimensions.clear();  		for (auto range : children[1]->children) {  			if (!range->range_valid) -				log_file_error(filename, linenum, "Non-constant range on memory decl.\n"); +				log_file_error(filename, location.first_line, "Non-constant range on memory decl.\n");  			multirange_dimensions.push_back(min(range->range_left, range->range_right));  			multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);  			total_size *= multirange_dimensions.back(); @@ -1083,7 +1081,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)  		{  			if (GetSize(children[0]->children) < i) -				log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str)); +				log_file_error(filename, location.first_line, "Insufficient number of array indices for %s.\n", log_id(str));  			AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); @@ -1112,11 +1110,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM) {  		if (children.size() > 1 && children[1]->type == AST_RANGE) {  			if (!children[1]->range_valid) -				log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); +				log_file_error(filename, location.first_line, "Non-constant width range on parameter decl.\n");  			int width = std::abs(children[1]->range_left - children[1]->range_right) + 1;  			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", +				log_file_warning(filename, location.first_line, "converting real value %e to binary %s.\n",  						children[0]->realvalue, log_signal(constvalue));  				delete children[0];  				children[0] = mkconst_bits(constvalue.bits, sign_hint); @@ -1190,7 +1188,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				current_scope[str] = auto_wire;  				did_something = true;  			} else { -				log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); +				log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());  			}  		}  		if (id2ast != current_scope[str]) { @@ -1203,7 +1201,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue)  	{  		if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) -			log_file_error(filename, linenum, "Invalid bit-select on memory access!\n"); +			log_file_error(filename, location.first_line, "Invalid bit-select on memory access!\n");  		int mem_width, mem_size, addr_bits;  		id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -1215,7 +1213,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			std::swap(data_range_left, data_range_right);  		std::stringstream sstr; -		sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); +		sstr << "$mem2bits$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  		std::string wire_id = sstr.str();  		AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); @@ -1256,7 +1254,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	}  	if (type == AST_WHILE) -		log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); +		log_file_error(filename, location.first_line, "While loops are only allowed in constant functions!\n");  	if (type == AST_REPEAT)  	{ @@ -1267,7 +1265,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		while (count->simplify(true, false, false, stage, 32, true, false)) { }  		if (count->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n"); +			log_file_error(filename, location.first_line, "Repeat loops outside must have constant repeat counts!\n");  		// convert to a block with the body repeated n times  		type = AST_BLOCK; @@ -1293,24 +1291,24 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			body_ast = body_ast->children.at(0);  		if (init_ast->type != AST_ASSIGN_EQ) -			log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n"); +			log_file_error(filename, location.first_line, "Unsupported 1st expression of generate for-loop!\n");  		if (next_ast->type != AST_ASSIGN_EQ) -			log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n"); +			log_file_error(filename, location.first_line, "Unsupported 3rd expression of generate for-loop!\n");  		if (type == AST_GENFOR) {  			if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR) -				log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n"); +				log_file_error(filename, location.first_line, "Left hand side of 1st expression of generate for-loop is not a gen var!\n");  			if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR) -				log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n"); +				log_file_error(filename, location.first_line, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n");  		} else {  			if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE) -				log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n"); +				log_file_error(filename, location.first_line, "Left hand side of 1st expression of generate for-loop is not a register!\n");  			if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE) -				log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n"); +				log_file_error(filename, location.first_line, "Left hand side of 3rd expression of generate for-loop is not a register!\n");  		}  		if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) -			log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n"); +			log_file_error(filename, location.first_line, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n");  		// eval 1st expression  		AstNode *varbuf = init_ast->children[1]->clone(); @@ -1322,7 +1320,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		}  		if (varbuf->type != AST_CONSTANT) -			log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); +			log_file_error(filename, location.first_line, "Right hand side of 1st expression of generate for-loop is not constant!\n");  		varbuf = new AstNode(AST_LOCALPARAM, varbuf);  		varbuf->str = init_ast->children[0]->str; @@ -1357,7 +1355,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			}  			if (buf->type != AST_CONSTANT) -				log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); +				log_file_error(filename, location.first_line, "2nd expression of generate for-loop is not constant!\n");  			if (buf->integer == 0) {  				delete buf; @@ -1373,7 +1371,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				buf = new AstNode(AST_GENBLOCK, body_ast->clone());  			if (buf->str.empty()) {  				std::stringstream sstr; -				sstr << "$genblock$" << filename << ":" << linenum << "$" << (autoidx++); +				sstr << "$genblock$" << filename << ":" << location.first_line << "$" << (autoidx++);  				buf->str = sstr.str();  			}  			std::map<std::string, std::string> name_map; @@ -1403,7 +1401,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			}  			if (buf->type != AST_CONSTANT) -				log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant (%s)!\n", type2str(buf->type).c_str()); +				log_file_error(filename, location.first_line, "Right hand side of 3rd expression of generate for-loop is not constant (%s)!\n", type2str(buf->type).c_str());  			delete varbuf->children[0];  			varbuf->children[0] = buf; @@ -1427,7 +1425,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	{  		for (size_t i = 0; i < children.size(); i++)  			if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) -				log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n"); +				log_file_error(children[i]->filename, children[i]->location.first_line, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n");  	}  	// transform block with name @@ -1475,7 +1473,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		if (buf->type != AST_CONSTANT) {  			// for (auto f : log_files)  			// 	dumpAst(f, "verilog-ast> "); -			log_file_error(filename, linenum, "Condition for generate if is not constant!\n"); +			log_file_error(filename, location.first_line, "Condition for generate if is not constant!\n");  		}  		if (buf->asBool() != 0) {  			delete buf; @@ -1516,7 +1514,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		if (buf->type != AST_CONSTANT) {  			// for (auto f : log_files)  			// 	dumpAst(f, "verilog-ast> "); -			log_file_error(filename, linenum, "Condition for generate case is not constant!\n"); +			log_file_error(filename, location.first_line, "Condition for generate case is not constant!\n");  		}  		bool ref_signed = buf->is_signed; @@ -1550,7 +1548,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				if (buf->type != AST_CONSTANT) {  					// for (auto f : log_files)  					// 	dumpAst(f, "verilog-ast> "); -					log_file_error(filename, linenum, "Expression in generate case is not constant!\n"); +					log_file_error(filename, location.first_line, "Expression in generate case is not constant!\n");  				}  				bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); @@ -1591,7 +1589,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	if (type == AST_CELLARRAY)  	{  		if (!children.at(0)->range_valid) -			log_file_error(filename, linenum, "Non-constant array range on cell array.\n"); +			log_file_error(filename, location.first_line, "Non-constant array range on cell array.\n");  		newNode = new AstNode(AST_GENBLOCK);  		int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; @@ -1602,7 +1600,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			newNode->children.push_back(new_cell);  			new_cell->str += stringf("[%d]", idx);  			if (new_cell->type == AST_PRIMITIVE) { -				log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n"); +				log_file_error(filename, location.first_line, "Cell arrays of primitives are currently not supported.\n");  			} else {  				log_assert(new_cell->children.at(0)->type == AST_CELLTYPE);  				new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str()); @@ -1616,7 +1614,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, location.first_line, "Insufficient number of arguments for primitive `%s'!\n", str.c_str());  		std::vector<AstNode*> children_list;  		for (auto child : children) { @@ -1631,7 +1629,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, location.first_line, "Invalid number of arguments for primitive `%s'!\n", str.c_str());  			std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz); @@ -1718,7 +1716,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, location.first_line, "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; @@ -1740,7 +1738,7 @@ skip_dynamic_range_lvalue_expansion:;  	if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && current_block != NULL)  	{  		std::stringstream sstr; -		sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++); +		sstr << "$formal$" << filename << ":" << location.first_line << "$" << (autoidx++);  		std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";  		AstNode *wire_check = new AstNode(AST_WIRE); @@ -1848,7 +1846,7 @@ skip_dynamic_range_lvalue_expansion:;  			newNode = new AstNode(AST_BLOCK);  			AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); -			wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++); +			wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), location.first_line, autoidx++);  			current_ast_mod->children.push_back(wire_tmp);  			current_scope[wire_tmp->str] = wire_tmp;  			wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); @@ -1886,7 +1884,7 @@ skip_dynamic_range_lvalue_expansion:;  			(children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE)  	{  		std::stringstream sstr; -		sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); +		sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  		std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";  		int mem_width, mem_size, addr_bits; @@ -1997,7 +1995,7 @@ skip_dynamic_range_lvalue_expansion:;  				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, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());  				int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;  				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), @@ -2093,11 +2091,11 @@ skip_dynamic_range_lvalue_expansion:;  				int num_steps = 1;  				if (GetSize(children) != 1 && GetSize(children) != 2) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",  							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", +					log_file_error(filename, location.first_line, "System function %s is only allowed in clocked blocks.\n",  							RTLIL::unescape_id(str).c_str());  				if (GetSize(children) == 2) @@ -2105,7 +2103,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *buf = children[1]->clone();  					while (buf->simplify(true, false, false, stage, -1, false, false)) { }  					if (buf->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); +						log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());  					num_steps = buf->asInt(true);  					delete buf; @@ -2132,7 +2130,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,  							mkconst_int(width_hint-1, true), mkconst_int(0, true))); -					reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i); +					reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), location.first_line, myidx, i);  					reg->is_reg = true;  					current_ast_mod->children.push_back(reg); @@ -2167,11 +2165,11 @@ skip_dynamic_range_lvalue_expansion:;  			if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell" || str == "\\$changed")  			{  				if (GetSize(children) != 1) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",  							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", +					log_file_error(filename, location.first_line, "System function %s is only allowed in clocked blocks.\n",  							RTLIL::unescape_id(str).c_str());  				AstNode *present = children.at(0)->clone(); @@ -2209,13 +2207,13 @@ skip_dynamic_range_lvalue_expansion:;  			if (str == "\\$clog2")  			{  				if (children.size() != 1) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",  							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)) { }  				if (buf->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); +					log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());  				RTLIL::Const arg_value = buf->bitsAsConst();  				if (arg_value.as_bool()) @@ -2234,11 +2232,11 @@ skip_dynamic_range_lvalue_expansion:;  			if (str == "\\$size" || str == "\\$bits")  			{  				if (str == "\\$bits" && children.size() != 1) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",  							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", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1 or 2.\n",  							RTLIL::unescape_id(str).c_str(), int(children.size()));  				int dim = 1; @@ -2262,7 +2260,7 @@ skip_dynamic_range_lvalue_expansion:;  					if (id_ast == NULL && current_scope.count(buf->str))  						id_ast = current_scope.at(buf->str);  					if (!id_ast) -						log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); +						log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str());  					if (id_ast->type == AST_MEMORY) {  						// We got here only if the argument is a memory  						// Otherwise $size() and $bits() return the expression width @@ -2270,15 +2268,15 @@ skip_dynamic_range_lvalue_expansion:;  						if (str == "\\$bits") {  							if (mem_range->type == AST_RANGE) {  								if (!mem_range->range_valid) -									log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); +									log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());  								mem_depth = mem_range->range_left - mem_range->range_right + 1;  							} else -								log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); +								log_file_error(filename, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());  						} else {  							// $size()  							if (mem_range->type == AST_RANGE) {  								if (!mem_range->range_valid) -									log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); +									log_file_error(filename, location.first_line, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());  								int dims;  								if (id_ast->multirange_dimensions.empty())  									dims = 1; @@ -2289,9 +2287,9 @@ skip_dynamic_range_lvalue_expansion:;  								else if (dim <= dims) {  									width_hint = id_ast->multirange_dimensions[2*dim-1];  								} else if ((dim > dims+1) || (dim < 0)) -									log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1); +									log_file_error(filename, location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);  							} else -								log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); +								log_file_error(filename, location.first_line, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());  						}  					}  				} @@ -2312,18 +2310,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", +						log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 2.\n",  								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", +						log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 1.\n",  								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", +						log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant argument.\n",  								RTLIL::unescape_id(str).c_str());  					int child_width_hint = width_hint;  					bool child_sign_hint = sign_hint; @@ -2334,7 +2332,7 @@ skip_dynamic_range_lvalue_expansion:;  				if (children.size() >= 2) {  					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", +						log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant argument.\n",  								RTLIL::unescape_id(str).c_str());  					int child_width_hint = width_hint;  					bool child_sign_hint = sign_hint; @@ -2377,7 +2375,7 @@ skip_dynamic_range_lvalue_expansion:;  				AstNode *node_string = children[0];  				while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  				if (node_string->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); +					log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());  				std::string sformat = node_string->bitsAsConst().decode_string();  				std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);  				newNode = AstNode::mkconst_str(sout); @@ -2398,14 +2396,14 @@ skip_dynamic_range_lvalue_expansion:;  				for (int i = 2; i < GetSize(dpi_decl->children); i++)  				{  					if (i-2 >= GetSize(children)) -						log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n"); +						log_file_error(filename, location.first_line, "Insufficient number of arguments in DPI function call.\n");  					argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));  					args.push_back(children.at(i-2)->clone());  					while (args.back()->simplify(true, false, false, stage, -1, false, true)) { }  					if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) -						log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n"); +						log_file_error(filename, location.first_line, "Failed to evaluate DPI function with non-constant argument.\n");  				}  				newNode = dpi_call(rtype, fname, argtypes, args); @@ -2417,7 +2415,7 @@ skip_dynamic_range_lvalue_expansion:;  			}  			if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) -				log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str()); +				log_file_error(filename, location.first_line, "Can't resolve function name `%s'.\n", str.c_str());  		}  		if (type == AST_TCALL) @@ -2425,26 +2423,26 @@ skip_dynamic_range_lvalue_expansion:;  			if (str == "$finish" || str == "$stop")  			{  				if (!current_always || current_always->type != AST_INITIAL) -					log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); +					log_file_error(filename, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str()); -				log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str()); +				log_file_error(filename, location.first_line, "System task `%s' executed.\n", str.c_str());  			}  			if (str == "\\$readmemh" || str == "\\$readmemb")  			{  				if (GetSize(children) < 2 || GetSize(children) > 4) -					log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n", +					log_file_error(filename, location.first_line, "System function %s got %d arguments, expected 2-4.\n",  							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)) { }  				if (node_filename->type != AST_CONSTANT) -					log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); +					log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());  				AstNode *node_memory = children[1]->clone();  				while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  				if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) -					log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); +					log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str());  				int start_addr = -1, finish_addr = -1; @@ -2452,7 +2450,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *node_addr = children[2]->clone();  					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (node_addr->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); +						log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str());  					start_addr = int(node_addr->asInt(false));  				} @@ -2460,7 +2458,7 @@ skip_dynamic_range_lvalue_expansion:;  					AstNode *node_addr = children[3]->clone();  					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (node_addr->type != AST_CONSTANT) -						log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); +						log_file_error(filename, location.first_line, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str());  					finish_addr = int(node_addr->asInt(false));  				} @@ -2488,13 +2486,13 @@ skip_dynamic_range_lvalue_expansion:;  			}  			if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) -				log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str()); +				log_file_error(filename, location.first_line, "Can't resolve task name `%s'.\n", str.c_str());  		}  		AstNode *decl = current_scope[str];  		std::stringstream sstr; -		sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$"; +		sstr << "$func$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++) << "$";  		std::string prefix = sstr.str();  		bool recommend_const_eval = false; @@ -2516,9 +2514,9 @@ skip_dynamic_range_lvalue_expansion:;  			}  			if (in_param) -				log_file_error(filename, linenum, "Non-constant function call in constant expression.\n"); +				log_file_error(filename, location.first_line, "Non-constant function call in constant expression.\n");  			if (require_const_eval) -				log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str()); +				log_file_error(filename, location.first_line, "Function %s can only be called with constant arguments.\n", str.c_str());  		}  		size_t arg_count = 0; @@ -2640,7 +2638,7 @@ skip_dynamic_range_lvalue_expansion:;  									goto tcall_incompatible_wires;  						} else {  					tcall_incompatible_wires: -							log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str()); +							log_file_error(filename, location.first_line, "Incompatible re-declaration of wire %s.\n", child->str.c_str());  						}  					}  				} @@ -2994,7 +2992,7 @@ apply_newNode:  		// newNode->dumpAst(stderr, "+ ");  		log_assert(newNode != NULL);  		newNode->filename = filename; -		newNode->linenum = linenum; +		newNode->location = location;  		newNode->cloneInto(this);  		delete newNode;  		did_something = true; @@ -3043,7 +3041,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  		yosys_input_files.insert(mem_filename);  	}  	if (f.fail() || GetSize(mem_filename) == 0) -		log_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str()); +		log_file_error(filename, location.first_line, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str());  	log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);  	int range_left =  memory->children[1]->range_left, range_right =  memory->children[1]->range_right; @@ -3089,7 +3087,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  				char *endptr;  				cursor = strtol(nptr, &endptr, 16);  				if (!*nptr || *endptr) -					log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str()); +					log_file_error(filename, location.first_line, "Can not parse address `%s` for %s.\n", nptr, str.c_str());  				continue;  			} @@ -3272,7 +3270,7 @@ static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &  	if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) {  		AstNode *mem = that->id2ast;  		if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) -			mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->linenum)); +			mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->location.first_line));  		mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS;  	}  } @@ -3300,14 +3298,14 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  			// activate mem2reg if this is assigned in an async proc  			if (flags & AstNode::MEM2REG_FL_ASYNC) {  				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ASYNC)) -					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); +					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));  				mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ASYNC;  			}  			// remember if this is assigned blocking (=)  			if (type == AST_ASSIGN_EQ) {  				if (!(proc_flags[mem] & AstNode::MEM2REG_FL_EQ1)) -					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); +					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));  				proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;  			} @@ -3324,11 +3322,11 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  			// remember where this is  			if (flags & MEM2REG_FL_INIT) {  				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) -					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); +					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));  				mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_INIT;  			} else {  				if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_ELSE)) -					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); +					mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));  				mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_SET_ELSE;  			}  		} @@ -3342,7 +3340,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg  		// flag if used after blocking assignment (in same proc)  		if ((proc_flags[mem] & AstNode::MEM2REG_FL_EQ1) && !(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_EQ2)) { -			mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), linenum)); +			mem2reg_places[mem].insert(stringf("%s:%d", filename.c_str(), location.first_line));  			mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_EQ2;  		}  	} @@ -3411,7 +3409,7 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)  		return false;  	if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1) -		log_file_error(filename, linenum, "Invalid array access.\n"); +		log_file_error(filename, location.first_line, "Invalid array access.\n");  	return true;  } @@ -3503,7 +3501,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  			children[0]->children[0]->children[0]->type != AST_CONSTANT)  	{  		std::stringstream sstr; -		sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); +		sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  		std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";  		int mem_width, mem_size, addr_bits; @@ -3582,7 +3580,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  		else  		{  			std::stringstream sstr; -			sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); +			sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++);  			std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA";  			int mem_width, mem_size, addr_bits; @@ -3726,13 +3724,13 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia  		int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();  		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); +				log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s:%d.%d-%d.%d: ...called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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); +				log_file_error(filename, location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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);  		} @@ -3763,8 +3761,8 @@ 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); +				log_file_error(child->filename, child->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n", +						child->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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; @@ -3803,24 +3801,24 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  				continue;  			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); +				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here. X\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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); +				log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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); +				log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			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());  			} else {  				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); +					log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n", +							fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  				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]; @@ -3851,8 +3849,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			while (cond->simplify(true, false, false, 1, -1, false, true)) { }  			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); +				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			if (cond->asBool()) {  				block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); @@ -3872,8 +3870,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			while (num->simplify(true, false, false, 1, -1, false, true)) { }  			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); +				log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +						fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  			block->children.erase(block->children.begin());  			for (int i = 0; i < num->bitsAsConst().as_int(); i++) @@ -3910,8 +3908,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  					while (cond->simplify(true, false, false, 1, -1, false, true)) { }  					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); +						log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +								fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  					found_match = cond->asBool();  					delete cond; @@ -3940,8 +3938,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			continue;  		} -		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); +		log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s:%d.%d-%d.%d: ... called from here.\n", +				fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);  		log_abort();  	} | 
