mirror of https://github.com/YosysHQ/yosys.git
Initial implementation of $display()
This commit is contained in:
parent
e446e651cb
commit
7141f65533
|
@ -174,13 +174,96 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
}
|
}
|
||||||
|
|
||||||
// deactivate all calls to non-synthesis system tasks
|
// 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" ||
|
// 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")) {
|
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);
|
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();
|
delete_children();
|
||||||
str = std::string();
|
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")))
|
||||||
|
{
|
||||||
|
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.)
|
// 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)
|
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;
|
const_fold = true;
|
||||||
|
|
Loading…
Reference in New Issue