diff options
Diffstat (limited to 'frontends')
25 files changed, 1446 insertions, 368 deletions
| diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 68b3327f9..57de725d8 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -30,15 +30,6 @@  #include "libs/sha1/sha1.h"  #include "ast.h" -#include <sstream> -#include <stdarg.h> - -#if defined(__APPLE__) -#  include <cmath> -#else -#  include <math.h> -#endif -  YOSYS_NAMESPACE_BEGIN  using namespace AST; @@ -53,12 +44,12 @@ namespace AST {  // instanciate global variables (private API)  namespace AST_INTERNAL { -	bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; +	bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;  	AstNode *current_ast, *current_ast_mod;  	std::map<std::string, AstNode*> current_scope;  	const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;  	RTLIL::SigSpec ignoreThisSignalsInInitial; -	AstNode *current_top_block, *current_block, *current_block_child; +	AstNode *current_always, *current_top_block, *current_block, *current_block_child;  	AstModule *current_module;  } @@ -90,6 +81,7 @@ std::string AST::type2str(AstNodeType type)  	X(AST_IDENTIFIER)  	X(AST_PREFIX)  	X(AST_ASSERT) +	X(AST_ASSUME)  	X(AST_FCALL)  	X(AST_TO_BITS)  	X(AST_TO_SIGNED) @@ -132,6 +124,7 @@ std::string AST::type2str(AstNodeType type)  	X(AST_TERNARY)  	X(AST_MEMRD)  	X(AST_MEMWR) +	X(AST_MEMINIT)  	X(AST_TCALL)  	X(AST_ASSIGN)  	X(AST_CELL) @@ -144,6 +137,8 @@ std::string AST::type2str(AstNodeType type)  	X(AST_ASSIGN_LE)  	X(AST_CASE)  	X(AST_COND) +	X(AST_CONDX) +	X(AST_CONDZ)  	X(AST_DEFAULT)  	X(AST_FOR)  	X(AST_WHILE) @@ -156,6 +151,7 @@ std::string AST::type2str(AstNodeType type)  	X(AST_POSEDGE)  	X(AST_NEGEDGE)  	X(AST_EDGE) +	X(AST_PACKAGE)  #undef X  	default:  		log_abort(); @@ -327,7 +323,7 @@ static std::string id2vl(std::string txt)  	return txt;  } -// dump AST node as verilog pseudo-code +// dump AST node as Verilog pseudo-code  void AstNode::dumpVlog(FILE *f, std::string indent)  {  	bool first = true; @@ -499,7 +495,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent)  		break;  	case AST_CASE: -		fprintf(f, "%s" "case (", indent.c_str()); +		if (!children.empty() && children[0]->type == AST_CONDX) +			fprintf(f, "%s" "casex (", indent.c_str()); +		else if (!children.empty() && children[0]->type == AST_CONDZ) +			fprintf(f, "%s" "casez (", indent.c_str()); +		else +			fprintf(f, "%s" "case (", indent.c_str());  		children[0]->dumpVlog(f, "");  		fprintf(f, ")\n");  		for (size_t i = 1; i < children.size(); i++) { @@ -510,6 +511,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent)  		break;  	case AST_COND: +	case AST_CONDX: +	case AST_CONDZ:  		for (auto child : children) {  			if (child->type == AST_BLOCK) {  				fprintf(f, ":\n"); @@ -553,7 +556,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)  		children[1]->dumpVlog(f, "");  		fprintf(f, "}}");  		break; -	 +  	if (0) { case AST_BIT_NOT:     txt = "~";  }  	if (0) { case AST_REDUCE_AND:  txt = "&";  }  	if (0) { case AST_REDUCE_OR:   txt = "|";  } @@ -697,7 +700,7 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe  	for (size_t i = 0; i < 32; i++) {  		if (i < node->bits.size())  			node->integer |= (node->bits[i] == RTLIL::S1) << i; -		else if (is_signed) +		else if (is_signed && !node->bits.empty())  			node->integer |= (node->bits.back() == RTLIL::S1) << i;  	}  	node->range_valid = true; @@ -818,7 +821,7 @@ uint64_t AstNode::asInt(bool is_signed)  	}  	if (type == AST_REALVALUE) -		return realvalue; +		return uint64_t(realvalue);  	log_abort();  } @@ -829,7 +832,7 @@ double AstNode::asReal(bool is_signed)  	{  		RTLIL::Const val(bits); -		bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1; +		bool is_negative = is_signed && !val.bits.empty() && val.bits.back() == RTLIL::State::S1;  		if (is_negative)  			val = const_neg(val, val, false, false, val.bits.size()); @@ -892,7 +895,7 @@ static AstModule* process_module(AstNode *ast, bool defer)  	AstNode *ast_before_simplify = ast->clone();  	if (flag_dump_ast1) { -		log("Dumping verilog AST before simplification:\n"); +		log("Dumping Verilog AST before simplification:\n");  		ast->dumpAst(NULL, "    ");  		log("--- END OF AST DUMP ---\n");  	} @@ -902,13 +905,13 @@ static AstModule* process_module(AstNode *ast, bool defer)  		while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }  		if (flag_dump_ast2) { -			log("Dumping verilog AST after simplification:\n"); +			log("Dumping Verilog AST after simplification:\n");  			ast->dumpAst(NULL, "    ");  			log("--- END OF AST DUMP ---\n");  		}  		if (flag_dump_vlog) { -			log("Dumping verilog AST (as requested by dump_vlog option):\n"); +			log("Dumping Verilog AST (as requested by dump_vlog option):\n");  			ast->dumpVlog(NULL, "    ");  			log("--- END OF AST DUMP ---\n");  		} @@ -957,6 +960,7 @@ static AstModule* process_module(AstNode *ast, bool defer)  	current_module->ast = ast_before_simplify;  	current_module->nolatches = flag_nolatches; +	current_module->nomeminit = flag_nomeminit;  	current_module->nomem2reg = flag_nomem2reg;  	current_module->mem2reg = flag_mem2reg;  	current_module->lib = flag_lib; @@ -968,13 +972,14 @@ static AstModule* process_module(AstNode *ast, bool defer)  }  // create AstModule instances for all modules in the AST tree and add them to 'design' -void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire) +void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)  {  	current_ast = ast;  	flag_dump_ast1 = dump_ast1;  	flag_dump_ast2 = dump_ast2;  	flag_dump_vlog = dump_vlog;  	flag_nolatches = nolatches; +	flag_nomeminit = nomeminit;  	flag_nomem2reg = nomem2reg;  	flag_mem2reg = mem2reg;  	flag_lib = lib; @@ -992,6 +997,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump  			for (auto n : global_decls)  				(*it)->children.push_back(n->clone()); +			for (auto n : design->verilog_packages){ +				for (auto o : n->children) { +					AstNode *cloned_node = o->clone(); +					cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); +					(*it)->children.push_back(cloned_node); +				} +			} +  			if (flag_icells && (*it)->str.substr(0, 2) == "\\$")  				(*it)->str = (*it)->str.substr(1); @@ -1009,6 +1022,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump  			design->add(process_module(*it, defer));  		} +		else if ((*it)->type == AST_PACKAGE){ +			design->verilog_packages.push_back((*it)->clone()); +		}  		else  			global_decls.push_back(*it);  	} @@ -1029,13 +1045,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R  	if (stripped_name.substr(0, 9) == "$abstract")  		stripped_name = stripped_name.substr(9); -	log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); +	log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str());  	current_ast = NULL;  	flag_dump_ast1 = false;  	flag_dump_ast2 = false;  	flag_dump_vlog = false;  	flag_nolatches = nolatches; +	flag_nomeminit = nomeminit;  	flag_nomem2reg = nomem2reg;  	flag_mem2reg = mem2reg;  	flag_lib = lib; @@ -1102,6 +1119,7 @@ RTLIL::Module *AstModule::clone() const  	new_mod->ast = ast->clone();  	new_mod->nolatches = nolatches; +	new_mod->nomeminit = nomeminit;  	new_mod->nomem2reg = nomem2reg;  	new_mod->mem2reg = mem2reg;  	new_mod->lib = lib; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 180646267..3dcd32bd4 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -64,6 +64,7 @@ namespace AST  		AST_IDENTIFIER,  		AST_PREFIX,  		AST_ASSERT, +		AST_ASSUME,  		AST_FCALL,  		AST_TO_BITS, @@ -107,6 +108,7 @@ namespace AST  		AST_TERNARY,  		AST_MEMRD,  		AST_MEMWR, +		AST_MEMINIT,  		AST_TCALL,  		AST_ASSIGN, @@ -120,6 +122,8 @@ namespace AST  		AST_ASSIGN_LE,  		AST_CASE,  		AST_COND, +		AST_CONDX, +		AST_CONDZ,  		AST_DEFAULT,  		AST_FOR,  		AST_WHILE, @@ -133,7 +137,9 @@ namespace AST  		AST_POSEDGE,  		AST_NEGEDGE, -		AST_EDGE +		AST_EDGE, + +		AST_PACKAGE  	};  	// convert an node type to a string (e.g. for debug output) @@ -208,13 +214,14 @@ namespace AST  		// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.  		// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()  		bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); -		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr); +		AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init);  		void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);  		void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);  		void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,  				dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags); -		void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block); +		bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);  		bool mem2reg_check(pool<AstNode*> &mem2reg_set); +		void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes);  		void meminfo(int &mem_width, int &mem_size, int &addr_bits);  		// additional functionality for evaluating constant functions @@ -264,13 +271,13 @@ namespace AST  	};  	// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code -	void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire); +	void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);  	// parametric modules are supported directly by the AST library -	// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions +	// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions  	struct AstModule : RTLIL::Module {  		AstNode *ast; -		bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire; +		bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;  		virtual ~AstModule();  		virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);  		virtual RTLIL::Module *clone() const; @@ -294,12 +301,12 @@ namespace AST  namespace AST_INTERNAL  {  	// internal state variables -	extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; +	extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;  	extern AST::AstNode *current_ast, *current_ast_mod;  	extern std::map<std::string, AST::AstNode*> current_scope;  	extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;  	extern RTLIL::SigSpec ignoreThisSignalsInInitial; -	extern AST::AstNode *current_top_block, *current_block, *current_block_child; +	extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;  	extern AST::AstModule *current_module;  	struct ProcessGenerator;  } diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index e566d653d..e241142d3 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 71248663e..3e359170b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -176,13 +176,13 @@ struct AST_INTERNAL::ProcessGenerator  	RTLIL::Process *proc;  	RTLIL::SigSpec outputSignals; -	// This always points to the RTLIL::CaseRule beeing filled at the moment +	// This always points to the RTLIL::CaseRule being filled at the moment  	RTLIL::CaseRule *current_case;  	// This map contains the replacement pattern to be used in the right hand side  	// of an assignment. E.g. in the code "foo = bar; foo = func(foo);" the foo in the right  	// hand side of the 2nd assignment needs to be replace with the temporary signal holding -	// the value assigned in the first assignment. So when the first assignement is processed +	// the value assigned in the first assignment. So when the first assignment is processed  	// the according information is appended to subst_rvalue_from and subst_rvalue_to.  	stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_rvalue_map; @@ -192,7 +192,7 @@ struct AST_INTERNAL::ProcessGenerator  	// signal that is used as input for the register that drives the signal foo.  	stackmap<RTLIL::SigBit, RTLIL::SigBit> subst_lvalue_map; -	// The code here generates a number of temprorary signal for each output register. This +	// The code here generates a number of temporary signal for each output register. This  	// map helps generating nice numbered names for all this temporary signals.  	std::map<RTLIL::Wire*, int> new_temp_count; @@ -338,12 +338,14 @@ struct AST_INTERNAL::ProcessGenerator  		case AST_CASE:  			for (auto child : ast->children)  				if (child != ast->children[0]) { -					log_assert(child->type == AST_COND); +					log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);  					collect_lvalues(reg, child, type_eq, type_le, false);  				}  			break;  		case AST_COND: +		case AST_CONDX: +		case AST_CONDZ:  		case AST_ALWAYS:  		case AST_INITIAL:  			for (auto child : ast->children) @@ -379,7 +381,7 @@ struct AST_INTERNAL::ProcessGenerator  	// e.g. when the last statement in the code "a = 23; if (b) a = 42; a = 0;" is processed this  	// function is called to clean up the first two assignments as they are overwritten by  	// the third assignment. -	void removeSignalFromCaseTree(const std::set<RTLIL::SigBit> &pattern, RTLIL::CaseRule *cs) +	void removeSignalFromCaseTree(const RTLIL::SigSpec &pattern, RTLIL::CaseRule *cs)  	{  		for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)  			it->first.remove2(pattern, &it->second); @@ -427,6 +429,17 @@ struct AST_INTERNAL::ProcessGenerator  			{  				RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue;  				RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); + +				pool<SigBit> lvalue_sigbits; +				for (int i = 0; i < GetSize(lvalue); i++) { +					if (lvalue_sigbits.count(lvalue[i]) > 0) { +						unmapped_lvalue.remove(i); +						lvalue.remove(i); +						rvalue.remove(i--); +					} else +						lvalue_sigbits.insert(lvalue[i]); +				} +  				lvalue.replace(subst_lvalue_map.stdmap());  				if (ast->type == AST_ASSIGN_EQ) { @@ -434,7 +447,7 @@ struct AST_INTERNAL::ProcessGenerator  						subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);  				} -				removeSignalFromCaseTree(lvalue.to_sigbit_set(), current_case); +				removeSignalFromCaseTree(lvalue, current_case);  				remove_unwanted_lvalue_bits(lvalue, rvalue);  				current_case->actions.push_back(RTLIL::SigSig(lvalue, rvalue));  			} @@ -467,7 +480,7 @@ struct AST_INTERNAL::ProcessGenerator  				{  					if (child == ast->children[0])  						continue; -					log_assert(child->type == AST_COND); +					log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);  					subst_lvalue_map.save();  					subst_rvalue_map.save(); @@ -511,7 +524,7 @@ struct AST_INTERNAL::ProcessGenerator  					subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);  				this_case_eq_lvalue.replace(subst_lvalue_map.stdmap()); -				removeSignalFromCaseTree(this_case_eq_lvalue.to_sigbit_set(), current_case); +				removeSignalFromCaseTree(this_case_eq_lvalue, current_case);  				addChunkActions(current_case->actions, this_case_eq_lvalue, this_case_eq_ltemp);  			}  			break; @@ -520,6 +533,11 @@ struct AST_INTERNAL::ProcessGenerator  			log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);  			break; +		case AST_PARAMETER: +		case AST_LOCALPARAM: +			log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); +			break; +  		case AST_TCALL:  		case AST_FOR:  			break; @@ -547,14 +565,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	switch (type)  	{  	case AST_CONSTANT: -		width_hint = std::max(width_hint, int(bits.size())); +		width_hint = max(width_hint, int(bits.size()));  		if (!is_signed)  			sign_hint = false;  		break;  	case AST_REALVALUE:  		*found_real = true; -		width_hint = std::max(width_hint, 32); +		width_hint = max(width_hint, 32);  		break;  	case AST_IDENTIFIER: @@ -567,9 +585,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  			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;  			} else -			if (id_ast->children[0]->type == AST_CONSTANT) { +			if (id_ast->children[0]->type != AST_CONSTANT) +				while (id_ast->simplify(true, false, false, 1, -1, false, true)) { } +			if (id_ast->children[0]->type == AST_CONSTANT)  				this_width = id_ast->children[0]->bits.size(); -			} else +			else  				log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);  			if (children.size() != 0)  				range = children[0]; @@ -582,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  					// log("---\n");  					// id_ast->dumpAst(NULL, "decl> ");  					// dumpAst(NULL, "ref> "); -					log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); +					log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);  				}  			} else {  				this_width = id_ast->range_left - id_ast->range_right + 1; @@ -593,7 +613,7 @@ 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_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); +				log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);  			this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;  		} else  			log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); @@ -615,7 +635,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  				this_width = range->range_left - range->range_right + 1;  			sign_hint = false;  		} -		width_hint = std::max(width_hint, this_width); +		width_hint = max(width_hint, this_width);  		if (!id_ast->is_signed)  			sign_hint = false;  		break; @@ -625,7 +645,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  		if (children[0]->type != AST_CONSTANT)  			log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);  		children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); -		width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int()); +		width_hint = max(width_hint, children[0]->bitsAsConst().as_int());  		break;  	case AST_TO_SIGNED: @@ -644,7 +664,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  			child->detectSignWidthWorker(sub_width_hint, sub_sign_hint);  			this_width += sub_width_hint;  		} -		width_hint = std::max(width_hint, this_width); +		width_hint = max(width_hint, this_width);  		sign_hint = false;  		break; @@ -653,7 +673,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  		if (children[0]->type != AST_CONSTANT)  			log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);  		children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); -		width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); +		width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);  		sign_hint = false;  		break; @@ -676,7 +696,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	case AST_REDUCE_XOR:  	case AST_REDUCE_XNOR:  	case AST_REDUCE_BOOL: -		width_hint = std::max(width_hint, 1); +		width_hint = max(width_hint, 1);  		sign_hint = false;  		break; @@ -696,7 +716,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	case AST_NEX:  	case AST_GE:  	case AST_GT: -		width_hint = std::max(width_hint, 1); +		width_hint = max(width_hint, 1);  		sign_hint = false;  		break; @@ -712,7 +732,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun  	case AST_LOGIC_AND:  	case AST_LOGIC_OR:  	case AST_LOGIC_NOT: -		width_hint = std::max(width_hint, 1); +		width_hint = max(width_hint, 1);  		sign_hint = false;  		break; @@ -725,9 +745,9 @@ 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_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); +			log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);  		this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; -		width_hint = std::max(width_hint, this_width); +		width_hint = max(width_hint, this_width);  		break;  	// everything should have been handled above -> print error if not. @@ -764,7 +784,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	// in the following big switch() statement there are some uses of  	// Clifford's Device (http://www.clifford.at/cfun/cliffdev/). In this  	// cases this variable is used to hold the type of the cell that should -	// be instanciated for this type of AST node. +	// be instantiated for this type of AST node.  	std::string type_name;  	current_filename = filename; @@ -773,7 +793,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	switch (type)  	{  	// simply ignore this nodes. -	// they are eighter leftovers from simplify() or are referenced by other nodes +	// they are either leftovers from simplify() or are referenced by other nodes  	// and are only accessed here thru this references  	case AST_TASK:  	case AST_FUNCTION: @@ -786,6 +806,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	case AST_GENBLOCK:  	case AST_GENIF:  	case AST_GENCASE: +	case AST_PACKAGE:  		break;  	// remember the parameter, needed for example in techmap @@ -1052,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				detectSignWidth(width_hint, sign_hint);  			RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);  			RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); -			int width = std::max(left.size(), right.size()); +			int width = max(left.size(), right.size());  			if (width_hint > 0)  				width = width_hint;  			is_signed = children[0]->is_signed && children[1]->is_signed; @@ -1066,16 +1087,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; }  		{  			RTLIL::SigSpec arg = children[0]->genRTLIL(); -			RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg); +			RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg);  			return sig;  		}  	// generate cells for unary operations: $reduce_bool -	// (this is actually just an $reduce_or, but for clearity a different cell type is used) +	// (this is actually just an $reduce_or, but for clarity a different cell type is used)  	if (0) { case AST_REDUCE_BOOL:  type_name = "$reduce_bool"; }  		{  			RTLIL::SigSpec arg = children[0]->genRTLIL(); -			RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg; +			RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg;  			return sig;  		} @@ -1121,7 +1142,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	if (0) { case AST_GE:  type_name = "$ge"; }  	if (0) { case AST_GT:  type_name = "$gt"; }  		{ -			int width = std::max(width_hint, 1); +			int width = max(width_hint, 1);  			width_hint = -1, sign_hint = true;  			children[0]->detectSignWidthWorker(width_hint, sign_hint);  			children[1]->detectSignWidthWorker(width_hint, sign_hint); @@ -1143,7 +1164,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint);  			RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint);  		#if 0 -			int width = std::max(left.size(), right.size()); +			int width = max(left.size(), right.size());  			if (width > width_hint && width_hint > 0)  				width = width_hint;  			if (width < width_hint) { @@ -1152,10 +1173,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  				if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed))  					width = width_hint;  				if (type == AST_MUL) -					width = std::min(left.size() + right.size(), width_hint); +					width = min(left.size() + right.size(), width_hint);  			}  		#else -			int width = std::max(std::max(left.size(), right.size()), width_hint); +			int width = max(max(left.size(), right.size()), width_hint);  		#endif  			is_signed = children[0]->is_signed && children[1]->is_signed;  			return binop2rtlil(this, type_name, width, left, right); @@ -1167,14 +1188,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  		{  			RTLIL::SigSpec left = children[0]->genRTLIL();  			RTLIL::SigSpec right = children[1]->genRTLIL(); -			return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right); +			return binop2rtlil(this, type_name, max(width_hint, 1), left, right);  		}  	// generate cells for unary operations: $logic_not  	case AST_LOGIC_NOT:  		{  			RTLIL::SigSpec arg = children[0]->genRTLIL(); -			return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg); +			return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg);  		}  	// generate multiplexer for ternary operator (aka ?:-operator) @@ -1190,7 +1211,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			if (cond.size() > 1)  				cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); -			int width = std::max(val1.size(), val2.size()); +			int width = max(val1.size(), val2.size());  			is_signed = children[1]->is_signed && children[2]->is_signed;  			widthExtend(this, val1, width, is_signed);  			widthExtend(this, val2, width, is_signed); @@ -1214,11 +1235,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  			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); -			int addr_bits = 1; -			while ((1 << addr_bits) < current_module->memories[str]->size) -				addr_bits++; +			int mem_width, mem_size, addr_bits; +			id2ast->meminfo(mem_width, mem_size, addr_bits);  			cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); +			cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1));  			cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));  			cell->setPort("\\DATA", RTLIL::SigSpec(wire)); @@ -1235,28 +1256,38 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	// generate $memwr cells for memory write ports  	case AST_MEMWR: +	case AST_MEMINIT:  		{  			std::stringstream sstr; -			sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); +			sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++); -			RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr"); +			RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");  			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); -			int addr_bits = 1; -			while ((1 << addr_bits) < current_module->memories[str]->size) -				addr_bits++; +			int mem_width, mem_size, addr_bits; +			id2ast->meminfo(mem_width, mem_size, addr_bits); + +			int num_words = 1; +			if (type == AST_MEMINIT) { +				if (children[2]->type != AST_CONSTANT) +					log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum); +				num_words = int(children[2]->asInt(false)); +				cell->parameters["\\WORDS"] = RTLIL::Const(num_words); +			} -			cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));  			cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); -			cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width)); -			cell->setPort("\\EN", children[2]->genRTLIL()); +			cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words));  			cell->parameters["\\MEMID"] = RTLIL::Const(str);  			cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);  			cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width); -			cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); -			cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); +			if (type == AST_MEMWR) { +				cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); +				cell->setPort("\\EN", children[2]->genRTLIL()); +				cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); +				cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); +			}  			cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);  		} @@ -1264,19 +1295,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  	// generate $assert cells  	case AST_ASSERT: +	case AST_ASSUME:  		{  			log_assert(children.size() == 2);  			RTLIL::SigSpec check = children[0]->genRTLIL(); -			log_assert(check.size() == 1); +			if (GetSize(check) != 1) +				check = current_module->ReduceBool(NEW_ID, check);  			RTLIL::SigSpec en = children[1]->genRTLIL(); -			log_assert(en.size() == 1); +			if (GetSize(en) != 1) +				en = current_module->ReduceBool(NEW_ID, en);  			std::stringstream sstr; -			sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); +			sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++); -			RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert"); +			RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");  			cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);  			for (auto &attr : attributes) { @@ -1335,16 +1369,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  					continue;  				}  				if (child->type == AST_PARASET) { -					if (child->children[0]->type != AST_CONSTANT) -						log_error("Parameter `%s' with non-constant value at %s:%d!\n", -								child->str.c_str(), filename.c_str(), linenum); -					if (child->str.size() == 0) { -						char buf[100]; -						snprintf(buf, 100, "$%d", ++para_counter); -						cell->parameters[buf] = child->children[0]->asParaConst(); -					} else { -						cell->parameters[child->str] = child->children[0]->asParaConst(); +					IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; +					if (child->children[0]->type == AST_REALVALUE) { +						log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n", +							log_id(cell), log_id(paraname), child->children[0]->realvalue, +							filename.c_str(), linenum); +						auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); +						strnode->cloneInto(child->children[0]); +						delete strnode;  					} +					if (child->children[0]->type != AST_CONSTANT) +						log_error("Parameter %s.%s with non-constant value at %s:%d!\n", +								log_id(cell), log_id(paraname), filename.c_str(), linenum); +					cell->parameters[paraname] = child->children[0]->asParaConst();  					continue;  				}  				if (child->type == AST_ARGUMENT) { @@ -1398,7 +1435,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)  }  // this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or -// signals must be substituted before beeing used as input values (used by ProcessGenerator) +// signals must be substituted before being used as input values (used by ProcessGenerator)  // note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().  RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)  { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e9750eba6..c09b912c2 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -41,7 +41,7 @@ YOSYS_NAMESPACE_BEGIN  using namespace AST;  using namespace AST_INTERNAL; -// convert the AST into a simpler AST that has all parameters subsitited by their +// convert the AST into a simpler AST that has all parameters substituted by their  // values, unrolled for-loops, expanded generate blocks, etc. when this function  // is done with an AST it can be converted into RTLIL using genRTLIL().  // @@ -49,15 +49,24 @@ using namespace AST_INTERNAL;  // nodes that link to a different node using names and lexical scoping.  bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)  { +	static int recursion_counter = 0; +	static pair<string, int> last_blocking_assignment_warn; +	static bool deep_recursion_warning = false; + +	if (recursion_counter++ == 1000 && deep_recursion_warning) { +		log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n"); +		deep_recursion_warning = false; +	} +  	AstNode *newNode = NULL;  	bool did_something = false; -	static pair<string, int> last_blocking_assignment_warn;  #if 0  	log("-------------\n"); +	log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);  	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, "> "); +	// dumpAst(NULL, "> ");  #endif  	if (stage == 0) @@ -65,6 +74,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		log_assert(type == AST_MODULE);  		last_blocking_assignment_warn = pair<string, int>(); +		deep_recursion_warning = true;  		while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }  		if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg")) @@ -79,11 +89,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			{  				AstNode *mem = it.first;  				uint32_t memflags = it.second; +				bool this_nomeminit = flag_nomeminit;  				log_assert((memflags & ~0x00ffff00) == 0);  				if (mem->get_bool_attribute("\\nomem2reg"))  					continue; +				if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit")) +					this_nomeminit = true; +  				if (memflags & AstNode::MEM2REG_FL_FORCED)  					goto silent_activate; @@ -93,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)  					goto verbose_activate; -				if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE)) +				if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)  					goto verbose_activate;  				if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) @@ -134,17 +148,17 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				}  			} -			mem2reg_as_needed_pass2(mem2reg_set, this, NULL); +			while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { } -			for (size_t i = 0; i < children.size(); i++) { -				if (mem2reg_set.count(children[i]) > 0) { -					delete children[i]; -					children.erase(children.begin() + (i--)); -				} -			} +			vector<AstNode*> delnodes; +			mem2reg_remove(mem2reg_set, delnodes); + +			for (auto node : delnodes) +				delete node;  		}  		while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { } +		recursion_counter--;  		return false;  	} @@ -152,18 +166,144 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	set_line_num(linenum);  	// we do not look inside a task or function -	// (but as soon as a task of function is instanciated we process the generated AST as usual) -	if (type == AST_FUNCTION || type == AST_TASK) +	// (but as soon as a task or function is instantiated we process the generated AST as usual) +	if (type == AST_FUNCTION || type == AST_TASK) { +		recursion_counter--;  		return false; +	} -	// deactivate all calls to non-synthesis system taks -	if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" || +	// deactivate all calls to non-synthesis system tasks +	// 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_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);  		delete_children();  		str = std::string();  	} +	if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { +		log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +		delete_children(); +		str = std::string(); +	} + +	// print messages if this a call to $display() or $write() +	// This code implements only a small subset of Verilog-2005 $display() format specifiers, +	// but should be good enough for most uses +	if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) +	{ +		int nargs = GetSize(children); +		if (nargs < 1) +			log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n", +					str.c_str(), int(children.size()), filename.c_str(), linenum); + +		// 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_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +		std::string sformat = node_string->bitsAsConst().decode_string(); + +		// Other arguments are placeholders. Process the string as we go through it +		std::string sout; +		int next_arg = 1; +		for (size_t i = 0; i < sformat.length(); i++) +		{ +			// format specifier +			if (sformat[i] == '%') +			{ +				// If there's no next character, that's a problem +				if (i+1 >= sformat.length()) +					log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + +				char cformat = sformat[++i]; + +				// %% is special, does not need a matching argument +				if (cformat == '%') +				{ +					sout += '%'; +					continue; +				} + +				// Simplify the argument +				AstNode *node_arg = nullptr; + +				// Everything from here on depends on the format specifier +				switch (cformat) +				{ +					case 's': +					case 'S': +					case 'd': +					case 'D': +					case 'x': +					case 'X': +						if (next_arg >= GetSize(children)) +							log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n", +									cformat, str.c_str(), filename.c_str(), linenum); + +						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_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +						break; + +					case 'm': +					case 'M': +						break; + +					default: +						log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +						break; +				} + +				switch (cformat) +				{ +					case 's': +					case 'S': +						sout += node_arg->bitsAsConst().decode_string(); +						break; + +					case 'd': +					case 'D': +						{ +							char tmp[128]; +							snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); +							sout += tmp; +						} +						break; + +					case 'x': +					case 'X': +						{ +							char tmp[128]; +							snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); +							sout += tmp; +						} +						break; + +					case 'm': +					case 'M': +						sout += log_id(current_module->name); +						break; + +					default: +						log_abort(); +				} +			} + +			// not a format specifier +			else +				sout += sformat[i]; +		} + +		// Finally, print the message (only include a \n for $display, not for $write) +		log("%s", sout.c_str()); +		if (str == "$display") +			log("\n"); +		delete_children(); +		str = std::string(); +	} +  	// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)  	if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX)  		const_fold = true; @@ -255,6 +395,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	auto backup_current_block = current_block;  	auto backup_current_block_child = current_block_child;  	auto backup_current_top_block = current_top_block; +	auto backup_current_always = current_always; + +	if (type == AST_ALWAYS || type == AST_INITIAL) +		current_always = this;  	int backup_width_hint = width_hint;  	bool backup_sign_hint = sign_hint; @@ -277,7 +421,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			did_something = true;  		children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);  		children[1]->detectSignWidth(width_hint, sign_hint); -		width_hint = std::max(width_hint, backup_width_hint); +		width_hint = max(width_hint, backup_width_hint);  		child_0_is_self_determined = true;  		break; @@ -291,7 +435,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  				did_something = true;  			if (!children[1]->range_valid)  				log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); -			width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1); +			width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);  		}  		break; @@ -362,7 +506,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		detect_width_simple = true;  		child_0_is_self_determined = true;  		break; -	 +  	case AST_MEMRD:  		detect_width_simple = true;  		children_are_self_determined = true; @@ -395,6 +539,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		}  	} +	if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { +		for (auto &bit : children.at(0)->bits) +			if (bit == State::Sz || bit == State::Sx) +				bit = State::Sa; +	} + +	if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { +		for (auto &bit : children.at(0)->bits) +			if (bit == State::Sz) +				bit = State::Sa; +	} +  	if (const_fold && type == AST_CASE)  	{  		while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } @@ -403,7 +559,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			new_children.push_back(children[0]);  			for (int i = 1; i < GetSize(children); i++) {  				AstNode *child = children[i]; -				log_assert(child->type == AST_COND); +				log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ);  				for (auto v : child->children) {  					if (v->type == AST_DEFAULT)  						goto keep_const_cond; @@ -494,6 +650,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	current_block = backup_current_block;  	current_block_child = backup_current_block_child;  	current_top_block = backup_current_top_block; +	current_always = backup_current_always;  	for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {  		if (it->second == NULL) @@ -530,6 +687,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			// dumpAst(NULL, ">   ");  			log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);  		} +		if (children[1]->type == AST_PREFIX) +			children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);  		log_assert(children[1]->type == AST_IDENTIFIER);  		newNode = children[1]->clone();  		const char *second_part = children[1]->str.c_str(); @@ -609,8 +768,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		for (auto range : children[1]->children) {  			if (!range->range_valid)  				log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum); -			multirange_dimensions.push_back(std::min(range->range_left, range->range_right)); -			multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1); +			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();  		}  		delete children[1]; @@ -636,10 +795,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			if (i == 0)  				index_expr = new_index_expr;  			else -				index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr); +				index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i+1], true)), new_index_expr);  		} -		for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++) +		for (int i = GetSize(id2ast->multirange_dimensions)/2; i < GetSize(children[0]->children); i++)  			children.push_back(children[0]->children[i]->clone());  		delete children[0]; @@ -656,7 +815,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		if (children.size() > 1 && children[1]->type == AST_RANGE) {  			if (!children[1]->range_valid)  				log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); -			int width = children[1]->range_left - children[1]->range_right + 1; +			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_warning("converting real value %e to binary %s at %s:%d.\n", @@ -670,7 +829,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  					RTLIL::SigSpec sig(children[0]->bits);  					sig.extend_u0(width, children[0]->is_signed);  					AstNode *old_child_0 = children[0]; -					children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed); +					children[0] = mkconst_bits(sig.as_const().bits, is_signed);  					delete old_child_0;  				}  				children[0]->is_signed = is_signed; @@ -803,7 +962,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		// eval 1st expression  		AstNode *varbuf = init_ast->children[1]->clone(); -		while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } +		while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }  		if (varbuf->type != AST_CONSTANT)  			log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); @@ -866,7 +1025,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			// eval 3rd expression  			buf = next_ast->children[1]->clone(); -			while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } +			while (buf->simplify(true, false, false, stage, 32, true, false)) { }  			if (buf->type != AST_CONSTANT)  				log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); @@ -889,7 +1048,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		std::vector<AstNode*> new_children;  		for (size_t i = 0; i < children.size(); i++) -			if (children[i]->type == AST_WIRE) { +			if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) {  				children[i]->simplify(false, false, false, stage, -1, false, false);  				current_ast_mod->children.push_back(children[i]);  				current_scope[children[i]->str] = children[i]; @@ -977,7 +1136,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		AstNode *selected_case = NULL;  		for (size_t i = 1; i < children.size(); i++)  		{ -			log_assert(children.at(i)->type == AST_COND); +			log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ);  			AstNode *this_genblock = NULL;  			for (auto child : children.at(i)->children) { @@ -1045,7 +1204,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  			log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);  		newNode = new AstNode(AST_GENBLOCK); -		int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1; +		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;  		for (int i = 0; i < num; i++) {  			int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i; @@ -1063,7 +1222,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  		goto apply_newNode;  	} -	// replace primitives with assignmens +	// replace primitives with assignments  	if (type == AST_PRIMITIVE)  	{  		if (children.size() < 2) @@ -1189,7 +1348,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	}  skip_dynamic_range_lvalue_expansion:; -	if (stage > 1 && type == AST_ASSERT && current_block != NULL) +	if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)  	{  		std::stringstream sstr;  		sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); @@ -1233,7 +1392,7 @@ skip_dynamic_range_lvalue_expansion:;  		newNode->children.push_back(assign_check);  		newNode->children.push_back(assign_en); -		AstNode *assertnode = new AstNode(AST_ASSERT); +		AstNode *assertnode = new AstNode(type);  		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));  		assertnode->children.push_back(new AstNode(AST_IDENTIFIER));  		assertnode->children[0]->str = id_check; @@ -1244,16 +1403,15 @@ skip_dynamic_range_lvalue_expansion:;  		goto apply_newNode;  	} -	if (stage > 1 && type == AST_ASSERT && children.size() == 1) +	if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)  	{ -		children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());  		children.push_back(mkconst_int(1, false, 1));  		did_something = true;  	}  	// found right-hand side identifier for memory -> replace with memory read port  	if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue && -			children[0]->type == AST_RANGE && children[0]->children.size() == 1) { +			children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) {  		newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone());  		newNode->str = str;  		newNode->id2ast = id2ast; @@ -1293,11 +1451,14 @@ skip_dynamic_range_lvalue_expansion:;  		current_scope[wire_data->str] = wire_data;  		while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } -		AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); -		wire_en->str = id_en; -		current_ast_mod->children.push_back(wire_en); -		current_scope[wire_en->str] = wire_en; -		while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } +		AstNode *wire_en = nullptr; +		if (current_always->type != AST_INITIAL) { +			wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); +			wire_en->str = id_en; +			current_ast_mod->children.push_back(wire_en); +			current_scope[wire_en->str] = wire_en; +			while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } +		}  		std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;  		for (int i = 0; i < addr_bits; i++) @@ -1313,13 +1474,17 @@ skip_dynamic_range_lvalue_expansion:;  		AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));  		assign_data->children[0]->str = id_data; -		AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); -		assign_en->children[0]->str = id_en; +		AstNode *assign_en = nullptr; +		if (current_always->type != AST_INITIAL) { +			assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); +			assign_en->children[0]->str = id_en; +		}  		AstNode *default_signals = new AstNode(AST_BLOCK);  		default_signals->children.push_back(assign_addr);  		default_signals->children.push_back(assign_data); -		default_signals->children.push_back(assign_en); +		if (current_always->type != AST_INITIAL) +			default_signals->children.push_back(assign_en);  		current_top_block->children.insert(current_top_block->children.begin(), default_signals);  		assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); @@ -1334,15 +1499,16 @@ skip_dynamic_range_lvalue_expansion:;  				std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx); -				for (int i = 0; i < mem_width; i++) -					set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; -  				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),  						new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));  				assign_data->children[0]->str = id_data; -				assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); -				assign_en->children[0]->str = id_en; +				if (current_always->type != AST_INITIAL) { +					for (int i = 0; i < mem_width; i++) +						set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; +					assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); +					assign_en->children[0]->str = id_en; +				}  			}  			else  			{ @@ -1357,16 +1523,17 @@ skip_dynamic_range_lvalue_expansion:;  					log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);  				int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; -				for (int i = 0; i < mem_width; i++) -					set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; -  				assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),  						new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));  				assign_data->children[0]->str = id_data; -				assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), -						new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); -				assign_en->children[0]->str = id_en; +				if (current_always->type != AST_INITIAL) { +					for (int i = 0; i < mem_width; i++) +						set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; +					assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), +							new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); +					assign_en->children[0]->str = id_en; +				}  				delete left_at_zero_ast;  				delete right_at_zero_ast; @@ -1378,23 +1545,31 @@ skip_dynamic_range_lvalue_expansion:;  			assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());  			assign_data->children[0]->str = id_data; -			assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); -			assign_en->children[0]->str = id_en; +			if (current_always->type != AST_INITIAL) { +				assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); +				assign_en->children[0]->str = id_en; +			}  		}  		newNode = new AstNode(AST_BLOCK);  		newNode->children.push_back(assign_addr);  		newNode->children.push_back(assign_data); -		newNode->children.push_back(assign_en); +		if (current_always->type != AST_INITIAL) +			newNode->children.push_back(assign_en); -		AstNode *wrnode = new AstNode(AST_MEMWR); -		wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); +		AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);  		wrnode->children.push_back(new AstNode(AST_IDENTIFIER));  		wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); +		if (current_always->type != AST_INITIAL) +			wrnode->children.push_back(new AstNode(AST_IDENTIFIER)); +		else +			wrnode->children.push_back(AstNode::mkconst_int(1, false));  		wrnode->str = children[0]->str; +		wrnode->id2ast = children[0]->id2ast;  		wrnode->children[0]->str = id_addr;  		wrnode->children[1]->str = id_data; -		wrnode->children[2]->str = id_en; +		if (current_always->type != AST_INITIAL) +			wrnode->children[2]->str = id_en;  		current_ast_mod->children.push_back(wrnode);  		goto apply_newNode; @@ -1531,7 +1706,17 @@ skip_dynamic_range_lvalue_expansion:;  			if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)  				log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);  		} -		if (type == AST_TCALL) { + +		if (type == AST_TCALL) +		{ +			if (str == "$finish" || str == "$stop") +			{ +				if (!current_always || current_always->type != AST_INITIAL) +					log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + +				log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +			} +  			if (str == "\\$readmemh" || str == "\\$readmemb")  			{  				if (GetSize(children) < 2 || GetSize(children) > 4) @@ -1555,7 +1740,7 @@ skip_dynamic_range_lvalue_expansion:;  					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (node_addr->type != AST_CONSTANT)  						log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); -					start_addr = node_addr->asInt(false); +					start_addr = int(node_addr->asInt(false));  				}  				if (GetSize(children) > 3) { @@ -1563,10 +1748,27 @@ skip_dynamic_range_lvalue_expansion:;  					while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }  					if (node_addr->type != AST_CONSTANT)  						log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); -					finish_addr = node_addr->asInt(false); +					finish_addr = int(node_addr->asInt(false));  				} -				newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr); +				bool unconditional_init = false; +				if (current_always->type == AST_INITIAL) { +					pool<AstNode*> queue; +					log_assert(current_always->children[0]->type == AST_BLOCK); +					queue.insert(current_always->children[0]); +					while (!unconditional_init && !queue.empty()) { +						pool<AstNode*> next_queue; +						for (auto n : queue) +						for (auto c : n->children) { +							if (c == this) +								unconditional_init = true; +							next_queue.insert(c); +						} +						next_queue.swap(queue); +					} +				} + +				newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);  				goto apply_newNode;  			} @@ -1606,6 +1808,8 @@ skip_dynamic_range_lvalue_expansion:;  		size_t arg_count = 0;  		std::map<std::string, std::string> replace_rules; +		vector<AstNode*> added_mod_children; +		dict<std::string, AstNode*> wire_cache;  		if (current_block == NULL)  		{ @@ -1698,17 +1902,41 @@ skip_dynamic_range_lvalue_expansion:;  		}  		for (auto child : decl->children) -			if (child->type == AST_WIRE) +			if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)  			{ -				AstNode *wire = child->clone(); -				wire->str = prefix + wire->str; -				wire->port_id = 0; -				wire->is_input = false; -				wire->is_output = false; -				current_ast_mod->children.push_back(wire); -				while (wire->simplify(true, false, false, 1, -1, false, false)) { } +				AstNode *wire = nullptr; + +				if (wire_cache.count(child->str)) +				{ +					wire = wire_cache.at(child->str); +					if (wire->children.empty()) { +						for (auto c : child->children) +							wire->children.push_back(c->clone()); +					} else { +						if (!child->children.empty()) +							log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum); +					} +				} +				else +				{ +					wire = child->clone(); +					wire->str = prefix + wire->str; +					wire->port_id = 0; +					wire->is_input = false; +					wire->is_output = false; +					if (!child->is_output) +						wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); +					wire_cache[child->str] = wire; + +					current_ast_mod->children.push_back(wire); +					added_mod_children.push_back(wire); +				} + +				if (child->type == AST_WIRE) +					while (wire->simplify(true, false, false, 1, -1, false, false)) { }  				replace_rules[child->str] = wire->str; +				current_scope[wire->str] = wire;  				if ((child->is_input || child->is_output) && arg_count < children.size())  				{ @@ -1728,8 +1956,13 @@ skip_dynamic_range_lvalue_expansion:;  				}  			} +		for (auto child : added_mod_children) { +			child->replace_ids(prefix, replace_rules); +			while (child->simplify(true, false, false, 1, -1, false, false)) { } +		} +  		for (auto child : decl->children) -			if (child->type != AST_WIRE) +			if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM)  			{  				AstNode *stmt = child->clone();  				stmt->replace_ids(prefix, replace_rules); @@ -1876,7 +2109,7 @@ skip_dynamic_range_lvalue_expansion:;  		if (0) { case AST_GE:  const_func = RTLIL::const_ge; }  		if (0) { case AST_GT:  const_func = RTLIL::const_gt; }  			if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { -				int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size()); +				int cmp_width = max(children[0]->bits.size(), children[1]->bits.size());  				bool cmp_signed = children[0]->is_signed && children[1]->is_signed;  				RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed),  						children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); @@ -2036,6 +2269,7 @@ apply_newNode:  	if (!did_something)  		basic_prep = true; +	recursion_counter--;  	return did_something;  } @@ -2048,10 +2282,18 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro  }  // replace a readmem[bh] TCALL ast node with a block of memory assignments -AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr) +AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init)  { +	int mem_width, mem_size, addr_bits; +	memory->meminfo(mem_width, mem_size, addr_bits); +  	AstNode *block = new AstNode(AST_BLOCK); +	AstNode *meminit = nullptr; +	int next_meminit_cursor=0; +	vector<State> meminit_bits; +	int meminit_size=0; +  	std::ifstream f;  	f.open(mem_filename.c_str()); @@ -2060,13 +2302,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  	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; -	int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right); +	int range_min = min(range_left, range_right), range_max = max(range_left, range_right);  	if (start_addr < 0)  		start_addr = range_min;  	if (finish_addr < 0) -		finish_addr = range_max; +		finish_addr = range_max + 1;  	bool in_comment = false;  	int increment = start_addr <= finish_addr ? +1 : -1; @@ -2106,21 +2348,56 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m  				continue;  			} -			AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token); +			AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); + +			if (unconditional_init) +			{ +				if (meminit == nullptr || cursor != next_meminit_cursor) +				{ +					if (meminit != nullptr) { +						meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); +						meminit->children[2] = AstNode::mkconst_int(meminit_size, false); +					} + +					meminit = new AstNode(AST_MEMINIT); +					meminit->children.push_back(AstNode::mkconst_int(cursor, false)); +					meminit->children.push_back(nullptr); +					meminit->children.push_back(nullptr); +					meminit->str = memory->str; +					meminit->id2ast = memory; +					meminit_bits.clear(); +					meminit_size = 0; + +					current_ast_mod->children.push_back(meminit); +					next_meminit_cursor = cursor; +				} -			block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); -			block->children.back()->children[0]->str = memory->str; -			block->children.back()->children[0]->id2ast = memory; +				meminit_size++; +				next_meminit_cursor++; +				meminit_bits.insert(meminit_bits.end(), value->bits.begin(), value->bits.end()); +				delete value; +			} +			else +			{ +				block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); +				block->children.back()->children[0]->str = memory->str; +				block->children.back()->children[0]->id2ast = memory; +			} -			if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min)) +			if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))  				break;  			cursor += increment;  		} -		if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min)) +		if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min))  			break;  	} +	if (meminit != nullptr) { +		meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); +		meminit->children[2] = AstNode::mkconst_int(meminit_size, false); +	} +  	return block;  } @@ -2171,7 +2448,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma  		name_map.swap(backup_name_map);  } -// rename stuff (used when tasks of functions are instanciated) +// rename stuff (used when tasks of functions are instantiated)  void AstNode::replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules)  {  	if (type == AST_BLOCK) @@ -2328,9 +2605,28 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)  	return true;  } +void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes) +{ +	log_assert(mem2reg_set.count(this) == 0); + +	if (mem2reg_set.count(id2ast)) +		id2ast = nullptr; + +	for (size_t i = 0; i < children.size(); i++) { +		if (mem2reg_set.count(children[i]) > 0) { +			delnodes.push_back(children[i]); +			children.erase(children.begin() + (i--)); +		} else { +			children[i]->mem2reg_remove(mem2reg_set, delnodes); +		} +	} +} +  // actually replace memories with registers -void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block) +bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)  { +	bool did_something = false; +  	if (type == AST_BLOCK)  		block = this; @@ -2389,6 +2685,8 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  		children[0]->id2ast = NULL;  		children[0]->str = id_data;  		type = AST_ASSIGN_EQ; + +		did_something = true;  	}  	if (mem2reg_check(mem2reg_set)) @@ -2489,10 +2787,13 @@ void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,  	auto children_list = children;  	for (size_t i = 0; i < children_list.size(); i++) -		children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block); +		if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block)) +			did_something = true; + +	return did_something;  } -// calulate memory dimensions +// calculate memory dimensions  void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)  {  	log_assert(type == AST_MEMORY); @@ -2502,7 +2803,7 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)  	if (mem_size < 0)  		mem_size *= -1; -	mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1; +	mem_size += min(children[1]->range_left, children[1]->range_right) + 1;  	addr_bits = 1;  	while ((1 << addr_bits) < mem_size) @@ -2538,8 +2839,8 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia  			if (!children.at(0)->range_valid)  				log_error("Non-constant range in %s:%d (called from %s:%d).\n",  						filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); -			offset = std::min(children.at(0)->range_left, children.at(0)->range_right); -			width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); +			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);  		}  		offset -= variables.at(str).offset;  		std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits; @@ -2579,7 +2880,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  				log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",  						child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);  			variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); -			variables[child->str].offset = std::min(child->range_left, child->range_right); +			variables[child->str].offset = min(child->range_left, child->range_right);  			variables[child->str].is_signed = child->is_signed;  			if (child->is_input && argidx < fcall->children.size())  				variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size()); @@ -2610,6 +2911,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  		if (stmt->type == AST_ASSIGN_EQ)  		{ +			if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 && +					stmt->children.at(0)->children.at(0)->type == AST_RANGE) +				stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall);  			stmt->children.at(1)->replace_variables(variables, fcall);  			while (stmt->simplify(true, false, false, 1, -1, false, true)) { } @@ -2635,7 +2939,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  				if (!range->range_valid)  					log_error("Non-constant range in %s:%d (called from %s:%d).\n",  							range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum); -				int offset = std::min(range->range_left, range->range_right); +				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];  				RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size()); @@ -2708,7 +3012,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)  			for (size_t i = 1; i < stmt->children.size(); i++)  			{  				bool found_match = false; -				log_assert(stmt->children.at(i)->type == AST_COND); +				log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ);  				if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) {  					sel_case = stmt->children.at(i)->children.back(); diff --git a/frontends/blif/Makefile.inc b/frontends/blif/Makefile.inc new file mode 100644 index 000000000..9729184eb --- /dev/null +++ b/frontends/blif/Makefile.inc @@ -0,0 +1,3 @@ + +OBJS += frontends/blif/blifparse.o + diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc new file mode 100644 index 000000000..1f6d0ee37 --- /dev/null +++ b/frontends/blif/blifparse.cc @@ -0,0 +1,485 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "blifparse.h" + +YOSYS_NAMESPACE_BEGIN + +static bool read_next_line(char *&buffer, size_t &buffer_size, int &line_count, std::istream &f) +{ +	int buffer_len = 0; +	buffer[0] = 0; + +	while (1) +	{ +		buffer_len += strlen(buffer + buffer_len); +		while (buffer_len > 0 && (buffer[buffer_len-1] == ' ' || buffer[buffer_len-1] == '\t' || +				buffer[buffer_len-1] == '\r' || buffer[buffer_len-1] == '\n')) +			buffer[--buffer_len] = 0; + +		if (buffer_size-buffer_len < 4096) { +			buffer_size *= 2; +			buffer = (char*)realloc(buffer, buffer_size); +		} + +		if (buffer_len == 0 || buffer[buffer_len-1] == '\\') { +			if (buffer_len > 0 && buffer[buffer_len-1] == '\\') +				buffer[--buffer_len] = 0; +			line_count++; +			if (!f.getline(buffer+buffer_len, buffer_size-buffer_len)) +				return false; +		} else +			return true; +	} +} + +void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode) +{ +	RTLIL::Module *module = nullptr; +	RTLIL::Const *lutptr = NULL; +	RTLIL::Cell *sopcell = NULL; +	RTLIL::State lut_default_state = RTLIL::State::Sx; +	int blif_maxnum = 0, sopmode = -1; + +	auto blif_wire = [&](const std::string &wire_name) -> Wire* +	{ +		if (wire_name[0] == '$') +		{ +			for (int i = 0; i+1 < GetSize(wire_name); i++) +			{ +				if (wire_name[i] != '$') +					continue; + +				int len = 0; +				while (i+len+1 < GetSize(wire_name) && '0' <= wire_name[i+len+1] && wire_name[i+len+1] <= '9') +					len++; + +				if (len > 0) { +					string num_str = wire_name.substr(i+1, len); +					int num = atoi(num_str.c_str()) & 0x0fffffff; +					blif_maxnum = std::max(blif_maxnum, num); +				} +			} +		} + +		IdString wire_id = RTLIL::escape_id(wire_name); +		Wire *wire = module->wire(wire_id); + +		if (wire == nullptr) +			wire = module->addWire(wire_id); + +		return wire; +	}; + +	dict<RTLIL::IdString, RTLIL::Const> *obj_attributes = nullptr; +	dict<RTLIL::IdString, RTLIL::Const> *obj_parameters = nullptr; + +	size_t buffer_size = 4096; +	char *buffer = (char*)malloc(buffer_size); +	int line_count = 0; + +	while (1) +	{ +		if (!read_next_line(buffer, buffer_size, line_count, f)) { +			if (module != nullptr) +				goto error; +			free(buffer); +			return; +		} + +	continue_without_read: +		if (buffer[0] == '#') +			continue; + +		if (buffer[0] == '.') +		{ +			if (lutptr) { +				for (auto &bit : lutptr->bits) +					if (bit == RTLIL::State::Sx) +						bit = lut_default_state; +				lutptr = NULL; +				lut_default_state = RTLIL::State::Sx; +			} + +			if (sopcell) { +				sopcell = NULL; +				sopmode = -1; +			} + +			char *cmd = strtok(buffer, " \t\r\n"); + +			if (!strcmp(cmd, ".model")) { +				if (module != nullptr) +					goto error; +				module = new RTLIL::Module; +				module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n")); +				obj_attributes = &module->attributes; +				obj_parameters = nullptr; +				if (design->module(module->name)) +					log_error("Duplicate definition of module %s in line %d!\n", log_id(module->name), line_count); +				design->add(module); +				continue; +			} + +			if (module == nullptr) +				goto error; + +			if (!strcmp(cmd, ".end")) +			{ +				module->fixup_ports(); + +				if (run_clean) +				{ +					Const buffer_lut(vector<RTLIL::State>({State::S0, State::S1})); +					vector<Cell*> remove_cells; + +					for (auto cell : module->cells()) +						if (cell->type == "$lut" && cell->getParam("\\LUT") == buffer_lut) { +							module->connect(cell->getPort("\\Y"), cell->getPort("\\A")); +							remove_cells.push_back(cell); +						} + +					for (auto cell : remove_cells) +						module->remove(cell); + +					Wire *true_wire = module->wire("$true"); +					Wire *false_wire = module->wire("$false"); +					Wire *undef_wire = module->wire("$undef"); + +					if (true_wire != nullptr) +						module->rename(true_wire, stringf("$true$%d", ++blif_maxnum)); + +					if (false_wire != nullptr) +						module->rename(false_wire, stringf("$false$%d", ++blif_maxnum)); + +					if (undef_wire != nullptr) +						module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum)); + +					autoidx = std::max(autoidx, blif_maxnum+1); +					blif_maxnum = 0; +				} + +				module = nullptr; +				obj_attributes = nullptr; +				obj_parameters = nullptr; +				continue; +			} + +			if (!strcmp(cmd, ".inputs") || !strcmp(cmd, ".outputs")) { +				char *p; +				while ((p = strtok(NULL, " \t\r\n")) != NULL) { +					RTLIL::IdString wire_name(stringf("\\%s", p)); +					RTLIL::Wire *wire = module->wire(wire_name); +					if (wire == nullptr) +						wire = module->addWire(wire_name); +					if (!strcmp(cmd, ".inputs")) +						wire->port_input = true; +					else +						wire->port_output = true; +				} +				obj_attributes = nullptr; +				obj_parameters = nullptr; +				continue; +			} + +			if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) { +				char *n = strtok(NULL, " \t\r\n"); +				char *v = strtok(NULL, "\r\n"); +				IdString id_n = RTLIL::escape_id(n); +				Const const_v; +				if (v[0] == '"') { +					std::string str(v+1); +					if (str.back() == '"') +						str.resize(str.size()-1); +					const_v = Const(str); +				} else { +					int n = strlen(v); +					const_v.bits.resize(n); +					for (int i = 0; i < n; i++) +						const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0; +				} +				if (!strcmp(cmd, ".attr")) { +					if (obj_attributes == nullptr) +						goto error; +					(*obj_attributes)[id_n] = const_v; +				} else { +					if (obj_parameters == nullptr) +						goto error; +					(*obj_parameters)[id_n] = const_v; +				} +				continue; +			} + +			if (!strcmp(cmd, ".latch")) +			{ +				char *d = strtok(NULL, " \t\r\n"); +				char *q = strtok(NULL, " \t\r\n"); +				char *edge = strtok(NULL, " \t\r\n"); +				char *clock = strtok(NULL, " \t\r\n"); +				char *init = strtok(NULL, " \t\r\n"); +				RTLIL::Cell *cell = nullptr; + +				if (clock == nullptr && edge != nullptr) { +					init = edge; +					edge = nullptr; +				} + +				if (init != nullptr && (init[0] == '0' || init[0] == '1')) +					blif_wire(d)->attributes["\\init"] = Const(init[0] == '1' ? 1 : 0, 1); + +				if (clock == nullptr) +					goto no_latch_clock; + +				if (!strcmp(edge, "re")) +					cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); +				else if (!strcmp(edge, "fe")) +					cell = module->addDff(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); +				else if (!strcmp(edge, "ah")) +					cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q)); +				else if (!strcmp(edge, "al")) +					cell = module->addDlatch(NEW_ID, blif_wire(clock), blif_wire(d), blif_wire(q), false); +				else { +			no_latch_clock: +					cell = module->addCell(NEW_ID, dff_name); +					cell->setPort("\\D", blif_wire(d)); +					cell->setPort("\\Q", blif_wire(q)); +				} + +				obj_attributes = &cell->attributes; +				obj_parameters = &cell->parameters; +				continue; +			} + +			if (!strcmp(cmd, ".gate") || !strcmp(cmd, ".subckt")) +			{ +				char *p = strtok(NULL, " \t\r\n"); +				if (p == NULL) +					goto error; + +				IdString celltype = RTLIL::escape_id(p); +				RTLIL::Cell *cell = module->addCell(NEW_ID, celltype); + +				while ((p = strtok(NULL, " \t\r\n")) != NULL) { +					char *q = strchr(p, '='); +					if (q == NULL || !q[0]) +						goto error; +					*(q++) = 0; +					cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); +				} + +				obj_attributes = &cell->attributes; +				obj_parameters = &cell->parameters; +				continue; +			} + +			obj_attributes = nullptr; +			obj_parameters = nullptr; + +			if (!strcmp(cmd, ".barbuf")) +			{ +				char *p = strtok(NULL, " \t\r\n"); +				if (p == NULL) +					goto error; + +				char *q = strtok(NULL, " \t\r\n"); +				if (q == NULL) +					goto error; + +				module->connect(blif_wire(q), blif_wire(p)); +				continue; +			} + +			if (!strcmp(cmd, ".names")) +			{ +				char *p; +				RTLIL::SigSpec input_sig, output_sig; +				while ((p = strtok(NULL, " \t\r\n")) != NULL) +					input_sig.append(blif_wire(p)); +				output_sig = input_sig.extract(input_sig.size()-1, 1); +				input_sig = input_sig.extract(0, input_sig.size()-1); + +				if (input_sig.size() == 0) +				{ +					RTLIL::State state = RTLIL::State::Sa; +					while (1) { +						if (!read_next_line(buffer, buffer_size, line_count, f)) +							goto error; +						for (int i = 0; buffer[i]; i++) { +							if (buffer[i] == ' ' || buffer[i] == '\t') +								continue; +							if (i == 0 && buffer[i] == '.') +								goto finished_parsing_constval; +							if (buffer[i] == '0') { +								if (state == RTLIL::State::S1) +									goto error; +								state = RTLIL::State::S0; +								continue; +							} +							if (buffer[i] == '1') { +								if (state == RTLIL::State::S0) +									goto error; +								state = RTLIL::State::S1; +								continue; +							} +							goto error; +						} +					} + +				finished_parsing_constval: +					if (state == RTLIL::State::Sa) +						state = RTLIL::State::S0; +					if (output_sig.as_wire()->name == "$undef") +						state = RTLIL::State::Sx; +					module->connect(RTLIL::SigSig(output_sig, state)); +					goto continue_without_read; +				} + +				if (sop_mode) +				{ +					sopcell = module->addCell(NEW_ID, "$sop"); +					sopcell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); +					sopcell->parameters["\\DEPTH"] = 0; +					sopcell->parameters["\\TABLE"] = RTLIL::Const(); +					sopcell->setPort("\\A", input_sig); +					sopcell->setPort("\\Y", output_sig); +					sopmode = -1; +				} +				else +				{ +					RTLIL::Cell *cell = module->addCell(NEW_ID, "$lut"); +					cell->parameters["\\WIDTH"] = RTLIL::Const(input_sig.size()); +					cell->parameters["\\LUT"] = RTLIL::Const(RTLIL::State::Sx, 1 << input_sig.size()); +					cell->setPort("\\A", input_sig); +					cell->setPort("\\Y", output_sig); +					lutptr = &cell->parameters.at("\\LUT"); +					lut_default_state = RTLIL::State::Sx; +				} +				continue; +			} + +			goto error; +		} + +		if (lutptr == NULL && sopcell == NULL) +			goto error; + +		char *input = strtok(buffer, " \t\r\n"); +		char *output = strtok(NULL, " \t\r\n"); + +		if (input == NULL || output == NULL || (strcmp(output, "0") && strcmp(output, "1"))) +			goto error; + +		int input_len = strlen(input); + +		if (sopcell) +		{ +			log_assert(sopcell->parameters["\\WIDTH"].as_int() == input_len); +			sopcell->parameters["\\DEPTH"] = sopcell->parameters["\\DEPTH"].as_int() + 1; + +			for (int i = 0; i < input_len; i++) +				switch (input[i]) { +					case '0': +						sopcell->parameters["\\TABLE"].bits.push_back(State::S1); +						sopcell->parameters["\\TABLE"].bits.push_back(State::S0); +						break; +					case '1': +						sopcell->parameters["\\TABLE"].bits.push_back(State::S0); +						sopcell->parameters["\\TABLE"].bits.push_back(State::S1); +						break; +					default: +						sopcell->parameters["\\TABLE"].bits.push_back(State::S0); +						sopcell->parameters["\\TABLE"].bits.push_back(State::S0); +						break; +				} + +			if (sopmode == -1) { +				sopmode = (*output == '1'); +				if (!sopmode) { +					SigSpec outnet = sopcell->getPort("\\Y"); +					SigSpec tempnet = module->addWire(NEW_ID); +					module->addNotGate(NEW_ID, tempnet, outnet); +					sopcell->setPort("\\Y", tempnet); +				} +			} else +				log_assert(sopmode == (*output == '1')); +		} + +		if (lutptr) +		{ +			if (input_len > 8) +				goto error; + +			for (int i = 0; i < (1 << input_len); i++) { +				for (int j = 0; j < input_len; j++) { +					char c1 = input[j]; +					if (c1 != '-') { +						char c2 = (i & (1 << j)) != 0 ? '1' : '0'; +						if (c1 != c2) +							goto try_next_value; +					} +				} +				lutptr->bits.at(i) = !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1; +			try_next_value:; +			} + +			lut_default_state = !strcmp(output, "0") ? RTLIL::State::S1 : RTLIL::State::S0; +		} +	} + +error: +	log_error("Syntax error in line %d!\n", line_count); +} + +struct BlifFrontend : public Frontend { +	BlifFrontend() : Frontend("blif", "read BLIF file") { } +	virtual void help() +	{ +		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +		log("\n"); +		log("    read_blif [filename]\n"); +		log("\n"); +		log("Load modules from a BLIF file into the current design.\n"); +		log("\n"); +		log("    -sop\n"); +		log("        Create $sop cells instead of $lut cells\n"); +		log("\n"); +	} +	virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) +	{ +		bool sop_mode = false; + +		log_header(design, "Executing BLIF frontend.\n"); + +		size_t argidx; +		for (argidx = 1; argidx < args.size(); argidx++) { +			std::string arg = args[argidx]; +			if (arg == "-sop") { +				sop_mode = true; +				continue; +			} +			break; +		} +		extra_args(f, filename, args, argidx); + +		parse_blif(design, *f, "\\DFF", true, sop_mode); +	} +} BlifFrontend; + +YOSYS_NAMESPACE_END + diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h new file mode 100644 index 000000000..058087d81 --- /dev/null +++ b/frontends/blif/blifparse.h @@ -0,0 +1,31 @@ +/* + *  yosys -- Yosys Open SYnthesis Suite + * + *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> + * + *  Permission to use, copy, modify, and/or distribute this software for any + *  purpose with or without fee is hereby granted, provided that the above + *  copyright notice and this permission notice appear in all copies. + * + *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef ABC_BLIFPARSE +#define ABC_BLIFPARSE + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean = false, bool sop_mode = false); + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc index c15e2cc47..e2a476c93 100644 --- a/frontends/ilang/Makefile.inc +++ b/frontends/ilang/Makefile.inc @@ -5,13 +5,15 @@ GENFILES += frontends/ilang/ilang_parser.output  GENFILES += frontends/ilang/ilang_lexer.cc  frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y -	$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser frontends/ilang/ilang_parser.y +	$(Q) mkdir -p $(dir $@) +	$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $<  	$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc  frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc  frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l -	$(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l +	$(Q) mkdir -p $(dir $@) +	$(P) flex -o frontends/ilang/ilang_lexer.cc $<  OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o  OBJS += frontends/ilang/ilang_frontend.o diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index 7a4687a3c..ed6789987 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -47,7 +47,7 @@ struct IlangFrontend : public Frontend {  	}  	virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)  	{ -		log_header("Executing ILANG frontend.\n"); +		log_header(design, "Executing ILANG frontend.\n");  		extra_args(f, filename, args, 1);  		log("Input filename: %s\n", filename.c_str()); diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h index b04d6c512..ad3ffec90 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/ilang/ilang_frontend.h @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l index ace992fbd..415de74eb 100644 --- a/frontends/ilang/ilang_lexer.l +++ b/frontends/ilang/ilang_lexer.l @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -29,7 +29,7 @@  #pragma clang diagnostic ignored "-Wdeprecated-register"  #endif -#include "ilang_frontend.h" +#include "frontends/ilang/ilang_frontend.h"  #include "ilang_parser.tab.h"  USING_YOSYS_NAMESPACE diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 4661d5772..cc31c8642 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -24,7 +24,7 @@  %{  #include <list> -#include "ilang_frontend.h" +#include "frontends/ilang/ilang_frontend.h"  YOSYS_NAMESPACE_BEGIN  namespace ILANG_FRONTEND {  	std::istream *lexin; @@ -50,6 +50,7 @@ USING_YOSYS_NAMESPACE  	int integer;  	YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;  	YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; +	std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;  }  %token <string> TOK_ID TOK_VALUE TOK_STRING @@ -60,6 +61,7 @@ USING_YOSYS_NAMESPACE  %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET  %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO +%type <rsigspec> sigspec_list_reversed  %type <sigspec> sigspec sigspec_list  %type <integer> sync_type  %type <data> constant @@ -121,7 +123,7 @@ attr_stmt:  autoidx_stmt:  	TOK_AUTOIDX TOK_INT EOL { -		autoidx = std::max(autoidx, $2); +		autoidx = max(autoidx, $2);  	};  wire_stmt: @@ -274,8 +276,8 @@ compare_list:  	/* empty */;  case_body: -	switch_stmt case_body | -	assign_stmt case_body | +	case_body switch_stmt | +	case_body assign_stmt |  	/* empty */;  assign_stmt: @@ -389,16 +391,20 @@ sigspec:  		$$ = $2;  	}; -sigspec_list: -	sigspec_list sigspec { -		$$ = new RTLIL::SigSpec; -		$$->append(*$2); -		$$->append(*$1); -		delete $1; +sigspec_list_reversed: +	sigspec_list_reversed sigspec { +		$$->push_back(*$2);  		delete $2;  	} |  	/* empty */ { +		$$ = new std::vector<RTLIL::SigSpec>; +	}; + +sigspec_list: sigspec_list_reversed {  		$$ = new RTLIL::SigSpec; +		for (auto it = $1->rbegin(); it != $1->rend(); it++) +			$$->append(*it); +		delete $1;  	};  conn_stmt: diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index 464c5c942..0be58b6da 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -40,7 +40,7 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&  	if (id_len == 0)  		log_error("Expected identifier at `%s'.\n", expr); -	 +  	if (id_len == 1 && (*expr == '0' || *expr == '1'))  		return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1; @@ -437,7 +437,7 @@ struct LibertyFrontend : public Frontend {  		bool flag_ignore_miss_dir  = false;  		std::vector<std::string> attributes; -		log_header("Executing Liberty frontend.\n"); +		log_header(design, "Executing Liberty frontend.\n");  		size_t argidx;  		for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc index 13f242c4b..68ef9aed1 100644 --- a/frontends/verific/Makefile.inc +++ b/frontends/verific/Makefile.inc @@ -8,8 +8,9 @@ EXTRA_TARGETS += share/verific  share/verific:  	$(P) rm -rf share/verific.new  	$(Q) mkdir -p share/verific.new -	$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs share/verific.new/vhdl_vdbs_1993 -	$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008 share/verific.new/vhdl_vdbs_2008 +	$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987 +	$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993 +	$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008  	$(Q) mv share/verific.new share/verific  endif diff --git a/frontends/verific/build_amd64.txt b/frontends/verific/build_amd64.txt index 9bb6e3203..d6952820e 100644 --- a/frontends/verific/build_amd64.txt +++ b/frontends/verific/build_amd64.txt @@ -8,8 +8,6 @@ only have the i386 eval version of Verific:  --snip--  CONFIG := clang  ENABLE_TCL := 0 -ENABLE_QT4 := 0 -ENABLE_ABC := 0  ENABLE_PLUGINS := 0  ENABLE_VERIFIC := 1  CXXFLAGS += -m32 @@ -21,7 +19,7 @@ VERIFIC_DIR = /usr/local/src/verific_lib_eval  2.) Install the necessary multilib packages  Hint: On debian/ubuntu the multilib packages have names such as -libreadline-dev:amd64 or lib32readline6-dev, depending on the +libreadline-dev:i386 or lib32readline6-dev, depending on the  exact version of debian/ubuntu you are working with. diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 79abcf245..7dd36a747 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -65,7 +65,7 @@ static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type  	log("\n");  } -static void import_attributes(std::map<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj) +static void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)  {  	MapIter mi;  	Att *attr; @@ -186,6 +186,16 @@ static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*,  		return true;  	} +	if (inst->Type() == PRIM_XNOR) { +		module->addXnorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput())); +		return true; +	} + +	if (inst->Type() == PRIM_BUF) { +		module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput())); +		return true; +	} +  	if (inst->Type() == PRIM_INV) {  		module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));  		return true; @@ -314,6 +324,16 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,  		return true;  	} +	if (inst->Type() == PRIM_DLATCHRS) +	{ +		if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) +			module->addDlatch(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput())); +		else +			module->addDlatchsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetControl()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()), +					net_map.at(inst->GetInput()), net_map.at(inst->GetOutput())); +		return true; +	} +  	#define IN  operatorInput(inst, net_map)  	#define IN1 operatorInput1(inst, net_map)  	#define IN2 operatorInput2(inst, net_map) @@ -359,6 +379,26 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,  		return true;  	} +	if (inst->Type() == OPER_ENABLED_DECODER) { +		RTLIL::SigSpec vec; +		vec.append(net_map.at(inst->GetControl())); +		for (unsigned i = 1; i < inst->OutputSize(); i++) { +			vec.append(RTLIL::State::S0); +		} +		module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false); +		return true; +	} + +	if (inst->Type() == OPER_DECODER) { +		RTLIL::SigSpec vec; +		vec.append(RTLIL::State::S1); +		for (unsigned i = 1; i < inst->OutputSize(); i++) { +			vec.append(RTLIL::State::S0); +		} +		module->addShl(RTLIL::escape_id(inst->Name()), vec, IN, OUT, false); +		return true; +	} +  	if (inst->Type() == OPER_SHIFT_RIGHT) {  		Net *net_cin = inst->GetCin();  		Net *net_a_msb = inst->GetInput1Bit(0); @@ -541,7 +581,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  		// log("  importing portbus %s.\n", portbus->Name());  		RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size()); -		wire->start_offset = std::min(portbus->LeftIndex(), portbus->RightIndex()); +		wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex());  		import_attributes(wire->attributes, portbus);  		if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN) @@ -580,11 +620,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  			int bits_in_word = number_of_bits;  			FOREACH_PORTREF_OF_NET(net, si, pr) {  				if (pr->GetInst()->Type() == OPER_READ_PORT) { -					bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->OutputSize()); +					bits_in_word = min<int>(bits_in_word, pr->GetInst()->OutputSize());  					continue;  				}  				if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) { -					bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->Input2Size()); +					bits_in_word = min<int>(bits_in_word, pr->GetInst()->Input2Size());  					continue;  				}  				log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n", @@ -630,7 +670,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  			RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));  			RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size()); -			wire->start_offset = std::min(netbus->LeftIndex(), netbus->RightIndex()); +			wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());  			import_attributes(wire->attributes, netbus);  			for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) { @@ -666,6 +706,11 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  			continue;  		} +		if (inst->Type() == PRIM_BUF) { +			module->addBufGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput())); +			continue; +		} +  		if (inst->Type() == PRIM_X) {  			module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);  			continue; @@ -692,7 +737,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  			cell->parameters["\\TRANSPARENT"] = false;  			cell->parameters["\\ABITS"] = GetSize(addr);  			cell->parameters["\\WIDTH"] = GetSize(data); -			cell->setPort("\\CLK", RTLIL::State::S0); +			cell->setPort("\\CLK", RTLIL::State::Sx); +			cell->setPort("\\EN", RTLIL::State::Sx);  			cell->setPort("\\ADDR", addr);  			cell->setPort("\\DATA", data);  			continue; @@ -737,13 +783,15 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  		}  		if (inst->IsPrimitive()) -			log_error("Unsupported Verific primitive: %s\n", inst->View()->Owner()->Name()); +			log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());  		nl_todo.insert(inst->View());  		RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?  				std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name())); +		dict<IdString, vector<SigBit>> cell_port_conns; +  		FOREACH_PORTREF_OF_INST(inst, mi2, pr) {  			// log("      .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());  			const char *port_name = pr->GetPort()->Name(); @@ -751,18 +799,21 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*  			if (pr->GetPort()->Bus()) {  				port_name = pr->GetPort()->Bus()->Name();  				port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) - -						std::min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex()); +						min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());  			} -			RTLIL::SigSpec conn; -			if (cell->hasPort(RTLIL::escape_id(port_name))) -				conn = cell->getPort(RTLIL::escape_id(port_name)); -			while (GetSize(conn) <= port_offset) { -				if (pr->GetPort()->GetDir() != DIR_IN) -					conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn))); -				conn.append(RTLIL::State::Sz); +			IdString port_name_id = RTLIL::escape_id(port_name); +			auto &sigvec = cell_port_conns[port_name_id]; +			if (GetSize(sigvec) <= port_offset) { +				SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec)); +				for (auto bit : zwires) +					sigvec.push_back(bit);  			} -			conn.replace(port_offset, net_map.at(pr->GetNet())); -			cell->setPort(RTLIL::escape_id(port_name), conn); +			sigvec[port_offset] = net_map.at(pr->GetNet()); +		} + +		for (auto &it : cell_port_conns) { +			// log("      .%s(%s)\n", log_id(it.first), log_signal(it.second)); +			cell->setPort(it.first, it.second);  		}  	}  } @@ -789,7 +840,7 @@ struct VerificPass : public Pass {  		log("\n");  		log("    verific -import [-gates] {-all | <top-module>..}\n");  		log("\n"); -		log("Elaborate the design for the sepcified top modules, import to Yosys and\n"); +		log("Elaborate the design for the specified top modules, import to Yosys and\n");  		log("reset the internal state of Verific. A gate-level netlist is created\n");  		log("when called with -gates.\n");  		log("\n"); @@ -799,7 +850,7 @@ struct VerificPass : public Pass {  #ifdef YOSYS_ENABLE_VERIFIC  	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)  	{ -		log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n"); +		log_header(design, "Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");  		Message::SetConsoleOutput(0);  		Message::RegisterCallBackMsg(msg_func); @@ -840,7 +891,7 @@ struct VerificPass : public Pass {  		}  		if (args.size() > 1 && args[1] == "-vhdl87") { -			vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); +			vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str());  			for (size_t argidx = 2; argidx < args.size(); argidx++)  				if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))  					log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str()); @@ -917,10 +968,12 @@ struct VerificPass : public Pass {  			for (; argidx < args.size(); argidx++) {  				if (veri_file::GetModule(args[argidx].c_str())) { +					log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str());  					if (!veri_file::Elaborate(args[argidx].c_str()))  						log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());  					nl_todo.insert(Netlist::PresentDesign());  				} else { +					log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str());  					if (!vhdl_file::Elaborate(args[argidx].c_str()))  						log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());  					nl_todo.insert(Netlist::PresentDesign()); @@ -947,6 +1000,6 @@ struct VerificPass : public Pass {  	}  #endif  } VerificPass; -  +  YOSYS_NAMESPACE_END diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 92cbd0b87..a06c1d5ab 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -5,13 +5,15 @@ GENFILES += frontends/verilog/verilog_parser.output  GENFILES += frontends/verilog/verilog_lexer.cc  frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y -	$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y +	$(Q) mkdir -p $(dir $@) +	$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $<  	$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc  frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc  frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l -	$(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l +	$(Q) mkdir -p $(dir $@) +	$(P) flex -o frontends/verilog/verilog_lexer.cc $<  OBJS += frontends/verilog/verilog_parser.tab.o  OBJS += frontends/verilog/verilog_lexer.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 735bc5f99..4a58357bf 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -48,7 +48,9 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)  {  	int carry = 0;  	for (size_t i = 0; i < digits.size(); i++) { -		log_assert(digits[i] < 10); +		if (digits[i] >= 10) +			log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n", +				current_filename.c_str(), get_line_num());  		digits[i] += carry * 10;  		carry = digits[i] % 2;  		digits[i] /= 2; @@ -91,54 +93,67 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le  		str++;  	} +	if (base == 10 && GetSize(digits) == 1 && digits.front() >= 0xf0) +		base = 2; + +	data.clear(); +  	if (base == 10) { -		data.clear(); -		if (len_in_bits < 0) { -			while (!digits.empty()) -				data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); -			while (data.size() < 32) -				data.push_back(RTLIL::S0); -		} else { -			for (int i = 0; i < len_in_bits; i++) -				data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); +		while (!digits.empty()) +			data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); +	} else { +		int bits_per_digit = my_ilog2(base-1); +		for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { +			if (*it > (base-1) && *it < 0xf0) +				log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n", +					base-1, base, current_filename.c_str(), get_line_num()); +			for (int i = 0; i < bits_per_digit; i++) { +				int bitmask = 1 << i; +				if (*it == 0xf0) +					data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); +				else if (*it == 0xf1) +					data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); +				else if (*it == 0xf2) +					data.push_back(RTLIL::Sa); +				else +					data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0); +			}  		} -		return;  	} -	int bits_per_digit = my_ilog2(base-1); -	if (len_in_bits < 0) -		len_in_bits = std::max<int>(digits.size() * bits_per_digit, 32); +	int len = GetSize(data); +	RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back(); -	data.clear(); -	data.resize(len_in_bits); - -	for (int i = 0; i < len_in_bits; i++) { -		int bitmask = 1 << (i % bits_per_digit); -		int digitidx = digits.size() - (i / bits_per_digit) - 1; -		if (digitidx < 0) { -			if (i > 0 && (data[i-1] == RTLIL::Sz || data[i-1] == RTLIL::Sx || data[i-1] == RTLIL::Sa)) -				data[i] = data[i-1]; -			else -				data[i] = RTLIL::S0; -		} else if (digits[digitidx] == 0xf0) -			data[i] = case_type == 'x' ? RTLIL::Sa : RTLIL::Sx; -		else if (digits[digitidx] == 0xf1) -			data[i] = case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz; -		else if (digits[digitidx] == 0xf2) -			data[i] = RTLIL::Sa; -		else -			data[i] = (digits[digitidx] & bitmask) ? RTLIL::S1 : RTLIL::S0; +	if (len_in_bits < 0) { +		if (len < 32) +			data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb); +		return; +	} + +	for (len = len - 1; len >= 0; len--) +		if (data[len] == RTLIL::S1) +			break; +	if (msb == RTLIL::S0 || msb == RTLIL::S1) { +		len += 1; +		data.resize(len_in_bits, RTLIL::S0); +	} else { +		len += 2; +		data.resize(len_in_bits, msb);  	} + +	if (len > len_in_bits) +		log_warning("Literal has a width of %d bit, but value requires %d bit. (%s:%d)\n", +			len_in_bits, len, current_filename.c_str(), get_line_num());  } -// convert the verilog code for a constant to an AST node +// convert the Verilog code for a constant to an AST node  AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)  {  	if (warn_z) {  		AstNode *ret = const2ast(code, case_type);  		if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) -			log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n", -				current_filename.c_str(), frontend_verilog_yyget_lineno()); +			log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", +				current_filename.c_str(), get_line_num());  		return ret;  	} @@ -215,8 +230,6 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn  		if (len_in_bits < 0) {  			if (is_signed && data.back() == RTLIL::S1)  				data.push_back(RTLIL::S0); -			while (data.size() < 32) -				data.push_back(RTLIL::S0);  		}  		return AstNode::mkconst_bits(data, is_signed);  	} diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 4e5d16599..997920b89 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -39,6 +39,7 @@  #include <string.h>  YOSYS_NAMESPACE_BEGIN +using namespace VERILOG_FRONTEND;  static std::list<std::string> output_code;  static std::list<std::string> input_buffer; @@ -109,7 +110,7 @@ static std::string next_token(bool pass_newline = false)  		}  		return token;  	} -	 +  	if (ch == ' ' || ch == '\t')  	{  		while ((ch = next_char()) != 0) { @@ -201,7 +202,7 @@ static void input_file(std::istream &f, std::string filename)  	insert_input("");  	auto it = input_buffer.begin(); -	input_buffer.insert(it, "`file_push " + filename + "\n"); +	input_buffer.insert(it, "`file_push \"" + filename + "\"\n");  	while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {  		buffer[rc] = 0;  		input_buffer.insert(it, buffer); @@ -222,7 +223,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons  	input_file(f, filename);  	defines_map["YOSYS"] = "1"; -	defines_map["SYNTHESIS"] = "1"; +	defines_map[formal_mode ? "FORMAL" : "SYNTHESIS"] = "1";  	while (!input_buffer.empty())  	{ diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 23d35f682..576f068b3 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -39,21 +39,33 @@ using namespace VERILOG_FRONTEND;  static std::vector<std::string> verilog_defaults;  static std::list<std::vector<std::string>> verilog_defaults_stack; +static void error_on_dpi_function(AST::AstNode *node) +{ +	if (node->type == AST::AST_DPI_FUNCTION) +		log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum); +	for (auto child : node->children) +		error_on_dpi_function(child); +} +  struct VerilogFrontend : public Frontend { -	VerilogFrontend() : Frontend("verilog", "read modules from verilog file") { } +	VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { }  	virtual void help()  	{  		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|  		log("\n");  		log("    read_verilog [options] [filename]\n");  		log("\n"); -		log("Load modules from a verilog file to the current design. A large subset of\n"); +		log("Load modules from a Verilog file to the current design. A large subset of\n");  		log("Verilog-2005 is supported.\n");  		log("\n");  		log("    -sv\n");  		log("        enable support for SystemVerilog features. (only a small subset\n");  		log("        of SystemVerilog is supported)\n");  		log("\n"); +		log("    -formal\n"); +		log("        enable support for assert() and assume() from SystemVerilog\n"); +		log("        replace the implicit -D SYNTHESIS with -D FORMAL\n"); +		log("\n");  		log("    -dump_ast1\n");  		log("        dump abstract syntax tree (before simplification)\n");  		log("\n"); @@ -61,7 +73,7 @@ struct VerilogFrontend : public Frontend {  		log("        dump abstract syntax tree (after simplification)\n");  		log("\n");  		log("    -dump_vlog\n"); -		log("        dump ast as verilog code (after simplification)\n"); +		log("        dump ast as Verilog code (after simplification)\n");  		log("\n");  		log("    -yydebug\n");  		log("        enable parser debug output\n"); @@ -83,19 +95,31 @@ struct VerilogFrontend : public Frontend {  		log("        this can also be achieved by setting the 'nomem2reg'\n");  		log("        attribute on the respective module or register.\n");  		log("\n"); +		log("        This is potentially dangerous. Usually the front-end has good\n"); +		log("        reasons for converting an array to a list of registers.\n"); +		log("        Prohibiting this step will likely result in incorrect synthesis\n"); +		log("        results.\n"); +		log("\n");  		log("    -mem2reg\n");  		log("        always convert memories to registers. this can also be\n");  		log("        achieved by setting the 'mem2reg' attribute on the respective\n");  		log("        module or register.\n");  		log("\n"); +		log("    -nomeminit\n"); +		log("        do not infer $meminit cells and instead convert initialized\n"); +		log("        memories to registers directly in the front-end.\n"); +		log("\n");  		log("    -ppdump\n"); -		log("        dump verilog code after pre-processor\n"); +		log("        dump Verilog code after pre-processor\n");  		log("\n");  		log("    -nopp\n");  		log("        do not run the pre-processor\n");  		log("\n"); +		log("    -nodpi\n"); +		log("        disable DPI-C support\n"); +		log("\n");  		log("    -lib\n"); -		log("        only create empty blackbox modules\n"); +		log("        only create empty blackbox modules. This implies -DBLACKBOX.\n");  		log("\n");  		log("    -noopt\n");  		log("        don't perform basic optimizations (such as const folding) in the\n"); @@ -113,6 +137,9 @@ struct VerilogFrontend : public Frontend {  		log("        to a later 'hierarchy' command. Useful in cases where the default\n");  		log("        parameters of modules yield invalid or not synthesizable code.\n");  		log("\n"); +		log("    -noautowire\n"); +		log("        make the default of `default_nettype be \"none\" instead of \"wire\".\n"); +		log("\n");  		log("    -setattr <attribute_name>\n");  		log("        set the specified attribute (to the value 1) on all loaded modules\n");  		log("\n"); @@ -129,9 +156,12 @@ struct VerilogFrontend : public Frontend {  		log("\n");  		log("Note that the Verilog frontend does a pretty good job of processing valid\n");  		log("verilog input, but has not very good error reporting. It generally is\n"); -		log("recommended to use a simulator (for example icarus verilog) for checking\n"); +		log("recommended to use a simulator (for example Icarus Verilog) for checking\n");  		log("the syntax of the code, rather than to rely on read_verilog for that.\n");  		log("\n"); +		log("See the Yosys README file for a list of non-standard Verilog features\n"); +		log("supported by the Yosys Verilog front-end.\n"); +		log("\n");  	}  	virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)  	{ @@ -139,10 +169,12 @@ struct VerilogFrontend : public Frontend {  		bool flag_dump_ast2 = false;  		bool flag_dump_vlog = false;  		bool flag_nolatches = false; +		bool flag_nomeminit = false;  		bool flag_nomem2reg = false;  		bool flag_mem2reg = false;  		bool flag_ppdump = false;  		bool flag_nopp = false; +		bool flag_nodpi = false;  		bool flag_lib = false;  		bool flag_noopt = false;  		bool flag_icells = false; @@ -154,8 +186,10 @@ struct VerilogFrontend : public Frontend {  		frontend_verilog_yydebug = false;  		sv_mode = false; +		formal_mode = false; +		default_nettype_wire = true; -		log_header("Executing Verilog-2005 frontend.\n"); +		log_header(design, "Executing Verilog-2005 frontend.\n");  		args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); @@ -166,6 +200,10 @@ struct VerilogFrontend : public Frontend {  				sv_mode = true;  				continue;  			} +			if (arg == "-formal") { +				formal_mode = true; +				continue; +			}  			if (arg == "-dump_ast1") {  				flag_dump_ast1 = true;  				continue; @@ -186,6 +224,10 @@ struct VerilogFrontend : public Frontend {  				flag_nolatches = true;  				continue;  			} +			if (arg == "-nomeminit") { +				flag_nomeminit = true; +				continue; +			}  			if (arg == "-nomem2reg") {  				flag_nomem2reg = true;  				continue; @@ -202,8 +244,13 @@ struct VerilogFrontend : public Frontend {  				flag_nopp = true;  				continue;  			} +			if (arg == "-nodpi") { +				flag_nodpi = true; +				continue; +			}  			if (arg == "-lib") {  				flag_lib = true; +				defines_map["BLACKBOX"] = string();  				continue;  			}  			if (arg == "-noopt") { @@ -222,6 +269,10 @@ struct VerilogFrontend : public Frontend {  				flag_defer = true;  				continue;  			} +			if (arg == "-noautowire") { +				default_nettype_wire = false; +				continue; +			}  			if (arg == "-setattr" && argidx+1 < args.size()) {  				attributes.push_back(RTLIL::escape_id(args[++argidx]));  				continue; @@ -257,14 +308,14 @@ struct VerilogFrontend : public Frontend {  		}  		extra_args(f, filename, args, argidx); -		log("Parsing %s input from `%s' to AST representation.\n", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); +		log("Parsing %s%s input from `%s' to AST representation.\n", +				formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());  		AST::current_filename = filename;  		AST::set_line_num = &frontend_verilog_yyset_lineno;  		AST::get_line_num = &frontend_verilog_yyget_lineno;  		current_ast = new AST::AstNode(AST::AST_DESIGN); -		default_nettype_wire = true;  		lexin = f;  		std::string code_after_preproc; @@ -288,7 +339,10 @@ struct VerilogFrontend : public Frontend {  						child->attributes[attr] = AST::AstNode::mkconst_int(1, false);  		} -		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire); +		if (flag_nodpi) +			error_on_dpi_function(current_ast); + +		AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);  		if (!flag_nopp)  			delete lexin; @@ -308,16 +362,16 @@ struct VerilogDefaults : public Pass {  		log("\n");  		log("    verilog_defaults -add [options]\n");  		log("\n"); -		log("Add the sepcified options to the list of default options to read_verilog.\n"); +		log("Add the specified options to the list of default options to read_verilog.\n");  		log("\n");  		log("\n"); -		log("    verilog_defaults -clear"); +		log("    verilog_defaults -clear\n");  		log("\n"); -		log("Clear the list of verilog default options.\n"); +		log("Clear the list of Verilog default options.\n");  		log("\n");  		log("\n"); -		log("    verilog_defaults -push"); -		log("    verilog_defaults -pop"); +		log("    verilog_defaults -push\n"); +		log("    verilog_defaults -pop\n");  		log("\n");  		log("Push or pop the list of default options to a stack. Note that -push does\n");  		log("not imply -clear.\n"); diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index e277f3e3c..fb98f4afb 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND  	// running in SystemVerilog mode  	extern bool sv_mode; +	// running in -formal mode +	extern bool formal_mode; +  	// lexer input stream  	extern std::istream *lexin;  } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index cb8fafcb2..107a2dfdd 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -40,7 +40,7 @@  #endif  #include "kernel/log.h" -#include "verilog_frontend.h" +#include "frontends/verilog/verilog_frontend.h"  #include "frontends/ast/ast.h"  #include "verilog_parser.tab.h" @@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END  	fn_stack.push_back(current_filename);  	ln_stack.push_back(frontend_verilog_yyget_lineno());  	current_filename = yytext+11; +	if (!current_filename.empty() && current_filename.front() == '"') +		current_filename = current_filename.substr(1); +	if (!current_filename.empty() && current_filename.back() == '"') +		current_filename = current_filename.substr(0, current_filename.size()-1);  	frontend_verilog_yyset_lineno(0);  } @@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END  "`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */ +"`celldefine"[^\n]* /* ignore `celldefine */ +"`endcelldefine"[^\n]* /* ignore `endcelldefine */ +  "`default_nettype"[ \t]+[^ \t\r\n/]+ {  	char *p = yytext;  	while (*p != 0 && *p != ' ' && *p != '\t') p++; @@ -134,6 +141,8 @@ YOSYS_NAMESPACE_END  "endfunction"  { return TOK_ENDFUNCTION; }  "task"         { return TOK_TASK; }  "endtask"      { return TOK_ENDTASK; } +"package"      { SV_KEYWORD(TOK_PACKAGE); } +"endpackage"   { SV_KEYWORD(TOK_ENDPACKAGE); }  "parameter"    { return TOK_PARAMETER; }  "localparam"   { return TOK_LOCALPARAM; }  "defparam"     { return TOK_DEFPARAM; } @@ -162,8 +171,9 @@ YOSYS_NAMESPACE_END  "always_ff"    { SV_KEYWORD(TOK_ALWAYS); }  "always_latch" { SV_KEYWORD(TOK_ALWAYS); } -"assert"   { SV_KEYWORD(TOK_ASSERT); } -"property" { SV_KEYWORD(TOK_PROPERTY); } +"assert"   { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } +"assume"   { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } +"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }  "logic"    { SV_KEYWORD(TOK_REG); }  "bit"      { SV_KEYWORD(TOK_REG); } @@ -240,7 +250,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {  supply0 { return TOK_SUPPLY0; }  supply1 { return TOK_SUPPLY1; } -"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { +"$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {  	frontend_verilog_yylval.string = new std::string(yytext);  	return TOK_ID;  } @@ -273,7 +283,7 @@ supply1 { return TOK_SUPPLY1; }  	static bool printed_warning = false;  	if (!printed_warning) {  		log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n" -				"Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n"); +				"Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n");  		printed_warning = true;  	}  	return TOK_SYNOPSYS_FULL_CASE; @@ -282,7 +292,7 @@ supply1 { return TOK_SUPPLY1; }  	static bool printed_warning = false;  	if (!printed_warning) {  		log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n" -				"Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n"); +				"Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n");  		printed_warning = true;  	}  	return TOK_SYNOPSYS_PARALLEL_CASE; @@ -343,6 +353,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {  "<<<" { return OP_SSHL; }  ">>>" { return OP_SSHR; } +"::"  { SV_KEYWORD(TOK_PACKAGESEP); } +  "+:" { return TOK_POS_INDEXED; }  "-:" { return TOK_NEG_INDEXED; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 621b6cc18..e7c3578c7 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -36,7 +36,7 @@  %{  #include <list>  #include <string.h> -#include "verilog_frontend.h" +#include "frontends/verilog/verilog_frontend.h"  #include "kernel/log.h"  USING_YOSYS_NAMESPACE @@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND {  	std::vector<char> case_type_stack;  	bool do_not_require_port_stubs;  	bool default_nettype_wire; -	bool sv_mode; +	bool sv_mode, formal_mode;  	std::istream *lexin;  }  YOSYS_NAMESPACE_END @@ -102,6 +102,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)  %token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE  %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END  %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM +%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP  %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG  %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL  %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT @@ -111,7 +112,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)  %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL  %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE  %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY  %type <ast> range range_or_multirange  non_opt_range non_opt_multirange range_or_signed_int  %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list @@ -139,6 +140,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)  %%  input: { +	ast_stack.clear();  	ast_stack.push_back(current_ast);  } design {  	ast_stack.pop_back(); @@ -152,6 +154,9 @@ design:  	module design |  	defattr design |  	task_func_decl design | +	param_decl design | +	localparam_decl design | +	package design |  	/* empty */;  attr: @@ -209,6 +214,14 @@ hierarchical_id:  	TOK_ID {  		$$ = $1;  	} | +	hierarchical_id TOK_PACKAGESEP TOK_ID { +		if ($3->substr(0, 1) == "\\") +			*$1 += "::" + $3->substr(1); +		else +			*$1 += "::" + *$3; +		delete $3; +		$$ = $1; +	} |  	hierarchical_id '.' TOK_ID {  		if ($3->substr(0, 1) == "\\")  			*$1 += "." + $3->substr(1); @@ -243,11 +256,10 @@ module_para_opt:  	'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;  module_para_list: -	single_module_para | -	single_module_para ',' module_para_list | -	/* empty */; +	single_module_para | module_para_list ',' single_module_para;  single_module_para: +	/* empty */ |  	TOK_PARAMETER {  		if (astbuf1) delete astbuf1;  		astbuf1 = new AstNode(AST_PARAMETER); @@ -299,7 +311,7 @@ module_arg:  			node->children.push_back($3);  		if (!node->is_input && !node->is_output)  			frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $4->c_str()); -		if (node->is_reg && node->is_input && !node->is_output) +		if (node->is_reg && node->is_input && !node->is_output && !sv_mode)  			frontend_verilog_yyerror("Input port `%s' is declared as register.", $4->c_str());  		ast_stack.back()->children.push_back(node);  		append_attr(node, $1); @@ -309,10 +321,36 @@ module_arg:  		do_not_require_port_stubs = true;  	}; +package: +	attr TOK_PACKAGE TOK_ID { +		AstNode *mod = new AstNode(AST_PACKAGE); +		ast_stack.back()->children.push_back(mod); +		ast_stack.push_back(mod); +		current_ast_mod = mod; +		mod->str = *$3; +		append_attr(mod, $1); +	} ';' package_body TOK_ENDPACKAGE { +		ast_stack.pop_back(); +		current_ast_mod = NULL; +	}; + +package_body: +	package_body package_body_stmt |; + +package_body_stmt: +	localparam_decl; + +non_opt_delay: +	'#' '(' expr ')' { delete $3; } | +	'#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; + +delay: +	non_opt_delay | /* empty */; +  wire_type:  	{  		astbuf3 = new AstNode(AST_WIRE); -	} wire_type_token_list { +	} wire_type_token_list delay {  		$$ = astbuf3;  	}; @@ -700,6 +738,8 @@ wire_name_and_opt_assign:  wire_name:  	TOK_ID range_or_multirange { +		if (astbuf1 == nullptr) +			frontend_verilog_yyerror("Syntax error.");  		AstNode *node = astbuf1->clone();  		node->str = *$1;  		append_attr_clone(node, albuf); @@ -724,7 +764,7 @@ wire_name:  			if (port_stubs.count(*$1) != 0) {  				if (!node->is_input && !node->is_output)  					frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str()); -				if (node->is_reg && node->is_input && !node->is_output) +				if (node->is_reg && node->is_input && !node->is_output && !sv_mode)  					frontend_verilog_yyerror("Input port `%s' is declared as register.", $1->c_str());  				node->port_id = port_stubs[*$1];  				port_stubs.erase(*$1); @@ -741,13 +781,13 @@ wire_name:  	};  assign_stmt: -	TOK_ASSIGN assign_expr_list ';'; +	TOK_ASSIGN delay assign_expr_list ';';  assign_expr_list:  	assign_expr | assign_expr_list ',' assign_expr;  assign_expr: -	expr '=' expr { +	lvalue '=' expr {  		ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, $1, $3));  	}; @@ -761,7 +801,7 @@ cell_stmt:  	} cell_parameter_list_opt cell_list ';' {  		delete astbuf1;  	} | -	attr tok_prim_wrapper { +	attr tok_prim_wrapper delay {  		astbuf1 = new AstNode(AST_PRIMITIVE);  		astbuf1->str = *$2;  		append_attr(astbuf1, $1); @@ -813,10 +853,10 @@ cell_parameter_list_opt:  	'#' '(' cell_parameter_list ')' | /* empty */;  cell_parameter_list: -	/* empty */ | cell_parameter | -	cell_parameter ',' cell_parameter_list; +	cell_parameter | cell_parameter_list ',' cell_parameter;  cell_parameter: +	/* empty */ |  	expr {  		AstNode *node = new AstNode(AST_PARASET);  		astbuf1->children.push_back(node); @@ -831,14 +871,10 @@ cell_parameter:  	};  cell_port_list: -	/* empty */ | cell_port | -	cell_port ',' cell_port_list | -	/* empty */ ',' { -		AstNode *node = new AstNode(AST_ARGUMENT); -		astbuf2->children.push_back(node); -	} cell_port_list; +	cell_port | cell_port_list ',' cell_port;  cell_port: +	/* empty */ |  	expr {  		AstNode *node = new AstNode(AST_ARGUMENT);  		astbuf2->children.push_back(node); @@ -926,27 +962,34 @@ opt_label:  assert:  	TOK_ASSERT '(' expr ')' ';' {  		ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); +	} | +	TOK_ASSUME '(' expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));  	};  assert_property:  	TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {  		ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4)); +	} | +	TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { +		ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));  	};  simple_behavioral_stmt: -	lvalue '=' expr { -		AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); +	lvalue '=' delay expr { +		AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);  		ast_stack.back()->children.push_back(node);  	} | -	lvalue OP_LE expr { -		AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3); +	lvalue OP_LE delay expr { +		AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);  		ast_stack.back()->children.push_back(node);  	};  // this production creates the obligatory if-else shift/reduce conflict  behavioral_stmt: -	defattr | assert | wire_decl | -	simple_behavioral_stmt ';' | +	defattr | assert | wire_decl | param_decl | localparam_decl | +	non_opt_delay behavioral_stmt | +	simple_behavioral_stmt ';' | ';' |  	hierarchical_id attr {  		AstNode *node = new AstNode(AST_TCALL);  		node->str = *$1; @@ -1039,13 +1082,13 @@ behavioral_stmt:  	};  case_type: -	TOK_CASE {  +	TOK_CASE {  		case_type_stack.push_back(0);  	} | -	TOK_CASEX {  +	TOK_CASEX {  		case_type_stack.push_back('x');  	} | -	TOK_CASEZ {  +	TOK_CASEZ {  		case_type_stack.push_back('z');  	}; @@ -1060,10 +1103,6 @@ opt_synopsys_attr:  	} |  	/* empty */; -behavioral_stmt_opt: -	behavioral_stmt | -	';' ; -  behavioral_stmt_list:  	behavioral_stmt_list behavioral_stmt |  	/* empty */; @@ -1084,7 +1123,9 @@ case_body:  case_item:  	{ -		AstNode *node = new AstNode(AST_COND); +		AstNode *node = new AstNode( +				case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : +				case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);  		ast_stack.back()->children.push_back(node);  		ast_stack.push_back(node);  	} case_select { @@ -1092,7 +1133,7 @@ case_item:  		ast_stack.back()->children.push_back(block);  		ast_stack.push_back(block);  		case_type_stack.push_back(0); -	} behavioral_stmt_opt { +	} behavioral_stmt {  		case_type_stack.pop_back();  		ast_stack.pop_back();  		ast_stack.pop_back(); @@ -1104,7 +1145,9 @@ gen_case_body:  gen_case_item:  	{ -		AstNode *node = new AstNode(AST_COND); +		AstNode *node = new AstNode( +				case_type_stack.size() && case_type_stack.back() == 'x' ? AST_CONDX : +				case_type_stack.size() && case_type_stack.back() == 'z' ? AST_CONDZ : AST_COND);  		ast_stack.back()->children.push_back(node);  		ast_stack.push_back(node);  	} case_select { @@ -1330,6 +1373,11 @@ basic_expr:  	'(' expr ')' {  		$$ = $2;  	} | +	'(' expr ':' expr ':' expr ')' { +		delete $2; +		$$ = $4; +		delete $6; +	} |  	'{' concat_list '}' {  		$$ = $2;  	} | diff --git a/frontends/vhdl2verilog/vhdl2verilog.cc b/frontends/vhdl2verilog/vhdl2verilog.cc index 82ff7b502..6f9c0e3f5 100644 --- a/frontends/vhdl2verilog/vhdl2verilog.cc +++ b/frontends/vhdl2verilog/vhdl2verilog.cc @@ -2,11 +2,11 @@   *  yosys -- Yosys Open SYnthesis Suite   *   *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at> - *   + *   *  Permission to use, copy, modify, and/or distribute this software for any   *  purpose with or without fee is hereby granted, provided that the above   *  copyright notice and this permission notice appear in all copies. - *   + *   *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES   *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF   *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR @@ -74,7 +74,7 @@ struct Vhdl2verilogPass : public Pass {  	}  	virtual void execute(std::vector<std::string> args, RTLIL::Design *design)  	{ -		log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n"); +		log_header(design, "Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");  		log_push();  		std::string out_file, top_entity; @@ -173,11 +173,11 @@ struct Vhdl2verilogPass : public Pass {  			Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "verilog");  		} -		log_header("Removing temp directory `%s':\n", tempdir_name.c_str()); +		log_header(design, "Removing temp directory `%s':\n", tempdir_name.c_str());  		remove_directory(tempdir_name);  		log_pop();  	}  } Vhdl2verilogPass; -  +  YOSYS_NAMESPACE_END | 
