diff options
| author | Clifford Wolf <clifford@clifford.at> | 2015-09-18 09:54:49 +0200 | 
|---|---|---|
| committer | Clifford Wolf <clifford@clifford.at> | 2015-09-18 09:54:49 +0200 | 
| commit | 7a230d3a8dd6f19ab403cc831bf57ca31fc7f3da (patch) | |
| tree | 638a93ba2e32fadb79b6f83f81c222743c5ba11f /frontends | |
| parent | d9cecabb877b1d58efc1bfcd962201eace67640d (diff) | |
| parent | 9db05d17feddf7615bb8944390fa7b535cd48b12 (diff) | |
| download | yosys-7a230d3a8dd6f19ab403cc831bf57ca31fc7f3da.tar.gz yosys-7a230d3a8dd6f19ab403cc831bf57ca31fc7f3da.tar.bz2 yosys-7a230d3a8dd6f19ab403cc831bf57ca31fc7f3da.zip | |
Merge branch 'feat-finish-disp'
Diffstat (limited to 'frontends')
| -rw-r--r-- | frontends/ast/simplify.cc | 100 | 
1 files changed, 98 insertions, 2 deletions
| diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e588df922..dd4f0797e 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -174,13 +174,99 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,  	}  	// deactivate all calls to non-synthesis system tasks -	if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" || +	// note that $display and $finish 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 == "$stop"  ||  			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();  	} +	// 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"))) +	{ +		if (!current_always || current_always->type != AST_INITIAL) +			log_error("System task `$display' outside initial block is unsupported at %s:%d.\n", filename.c_str(), linenum); + +		size_t nargs = GetSize(children); +		if(nargs < 1) +		{ +			log_error("System task `$display' got %d arguments, expected >= 1 at %s:%d.\n", +				int(children.size()), filename.c_str(), linenum); +		} + +		// First argument is the format string +		AstNode *node_string = children[0]->clone(); +		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; +		size_t next_arg = 1; +		for(size_t i=0; i<sformat.length(); i++) +		{ +			// format specifier +			if(sformat[i] == '%') +			{ +				// If we're out of arguments, that's a problem! +				if(next_arg >= nargs) +					log_error("System task `%s' called with more format specifiers than arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + +				// Simplify the argument +				AstNode *node_arg = children[next_arg ++]->clone(); +				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); + +				// 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); + +				// Everything from here on depends on the format specifier +				char cformat = sformat[++i]; +				switch(cformat) +				{ +					case '%': +						sout += '%'; +						break; + +					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; + +					default: +						log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); +						break; +				} +			} + +			// 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; @@ -1569,7 +1655,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") +			{ +				if (!current_always || current_always->type != AST_INITIAL) +					log_error("System task `$finish' outside initial block is unsupported at %s:%d.\n", filename.c_str(), linenum); + +				log_error("System task `$finish' executed at %s:%d.\n", filename.c_str(), linenum); +			} +  			if (str == "\\$readmemh" || str == "\\$readmemb")  			{  				if (GetSize(children) < 2 || GetSize(children) > 4) | 
