diff options
Diffstat (limited to 'frontends/verilog')
| -rw-r--r-- | frontends/verilog/Makefile.inc | 6 | ||||
| -rw-r--r-- | frontends/verilog/const2ast.cc | 93 | ||||
| -rw-r--r-- | frontends/verilog/preproc.cc | 11 | ||||
| -rw-r--r-- | frontends/verilog/verilog_frontend.cc | 88 | ||||
| -rw-r--r-- | frontends/verilog/verilog_frontend.h | 7 | ||||
| -rw-r--r-- | frontends/verilog/verilog_lexer.l | 28 | ||||
| -rw-r--r-- | frontends/verilog/verilog_parser.y | 124 | 
7 files changed, 245 insertions, 112 deletions
| 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;  	} | | 
