mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-26 10:35:38 +00:00
Merge branch 'master' of https://github.com/YosysHQ/yosys
Solved a conflict into the CHANGELOG Signed-off-by: Rodrigo Alejandro Melo <rmelo@inti.gob.ar>
This commit is contained in:
commit
313a425bd5
12 changed files with 369 additions and 112 deletions
|
@ -244,6 +244,7 @@ namespace AST
|
|||
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
||||
AstNode *eval_const_function(AstNode *fcall);
|
||||
bool is_simple_const_expr();
|
||||
std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint);
|
||||
|
||||
// create a human-readable text representation of the AST (for debugging)
|
||||
void dumpAst(FILE *f, std::string indent) const;
|
||||
|
|
|
@ -41,6 +41,103 @@ YOSYS_NAMESPACE_BEGIN
|
|||
using namespace AST;
|
||||
using namespace AST_INTERNAL;
|
||||
|
||||
// Process a format string and arguments for $display, $write, $sprintf, etc
|
||||
|
||||
std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) {
|
||||
// Other arguments are placeholders. Process the string as we go through it
|
||||
std::string sout;
|
||||
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_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
|
||||
|
||||
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_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
|
||||
cformat, str.c_str());
|
||||
|
||||
node_arg = children[next_arg++];
|
||||
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_arg->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
break;
|
||||
|
||||
default:
|
||||
log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
|
||||
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];
|
||||
}
|
||||
return sout;
|
||||
}
|
||||
|
||||
|
||||
// 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().
|
||||
|
@ -216,99 +313,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
if (node_string->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str());
|
||||
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_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
|
||||
|
||||
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_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
|
||||
cformat, str.c_str());
|
||||
|
||||
node_arg = children[next_arg++];
|
||||
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_arg->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
case 'M':
|
||||
break;
|
||||
|
||||
default:
|
||||
log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
|
||||
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];
|
||||
}
|
||||
|
||||
std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);
|
||||
// Finally, print the message (only include a \n for $display, not for $write)
|
||||
log("%s", sout.c_str());
|
||||
if (str == "$display")
|
||||
|
@ -2244,6 +2249,17 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (str == "\\$sformatf") {
|
||||
AstNode *node_string = children[0];
|
||||
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
|
||||
if (node_string->type != AST_CONSTANT)
|
||||
log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());
|
||||
std::string sformat = node_string->bitsAsConst().decode_string();
|
||||
std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);
|
||||
newNode = AstNode::mkconst_str(sout);
|
||||
goto apply_newNode;
|
||||
}
|
||||
|
||||
if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION)
|
||||
{
|
||||
AstNode *dpi_decl = current_scope[str];
|
||||
|
|
|
@ -431,6 +431,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
|
|||
"+:" { return TOK_POS_INDEXED; }
|
||||
"-:" { return TOK_NEG_INDEXED; }
|
||||
|
||||
".*" { return TOK_WILDCARD_CONNECT; }
|
||||
|
||||
[-+]?[=*]> {
|
||||
if (!specify_mode) REJECT;
|
||||
frontend_verilog_yylval.string = new std::string(yytext);
|
||||
|
|
|
@ -138,7 +138,7 @@ struct specify_rise_fall {
|
|||
%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_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
|
||||
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT
|
||||
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC
|
||||
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||
%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
|
||||
|
@ -1580,6 +1580,11 @@ cell_port:
|
|||
node->children.back()->str = *$3;
|
||||
delete $3;
|
||||
free_attr($1);
|
||||
} |
|
||||
attr TOK_WILDCARD_CONNECT {
|
||||
if (!sv_mode)
|
||||
frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode.");
|
||||
astbuf2->attributes[ID(wildcard_port_conns)] = AstNode::mkconst_int(1, false);
|
||||
};
|
||||
|
||||
always_comb_or_latch:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue