mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +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
|
@ -53,7 +53,9 @@ Yosys 0.9 .. Yosys 0.9-dev
|
||||||
- Added support for flip-flops with synchronous reset to synth_xilinx
|
- Added support for flip-flops with synchronous reset to synth_xilinx
|
||||||
- Added support for flip-flops with reset and enable to synth_xilinx
|
- Added support for flip-flops with reset and enable to synth_xilinx
|
||||||
- Added "check -mapped"
|
- Added "check -mapped"
|
||||||
- Added checking of SystemVerilog always block types (always_comb, always_latch and always_ff)
|
- Added checking of SystemVerilog always block types (always_comb,
|
||||||
|
always_latch and always_ff)
|
||||||
|
- Added support for SystemVerilog wildcard port connections (.*)
|
||||||
- Added "xilinx_dffopt" pass
|
- Added "xilinx_dffopt" pass
|
||||||
- Added "scratchpad" pass
|
- Added "scratchpad" pass
|
||||||
- Added "abc9 -dff"
|
- Added "abc9 -dff"
|
||||||
|
|
|
@ -387,6 +387,10 @@ Verilog Attributes and non-standard features
|
||||||
according to the type of the always. These are checked for correctness in
|
according to the type of the always. These are checked for correctness in
|
||||||
``proc_dlatch``.
|
``proc_dlatch``.
|
||||||
|
|
||||||
|
- The cell attribute ``wildcard_port_conns`` represents wildcard port
|
||||||
|
connections (SystemVerilog ``.*``). These are resolved to concrete
|
||||||
|
connections to matching wires in ``hierarchy``.
|
||||||
|
|
||||||
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
- In addition to the ``(* ... *)`` attribute syntax, Yosys supports
|
||||||
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
the non-standard ``{* ... *}`` attribute syntax to set default attributes
|
||||||
for everything that comes after the ``{* ... *}`` statement. (Reset
|
for everything that comes after the ``{* ... *}`` statement. (Reset
|
||||||
|
|
|
@ -33,6 +33,7 @@ struct JsonWriter
|
||||||
std::ostream &f;
|
std::ostream &f;
|
||||||
bool use_selection;
|
bool use_selection;
|
||||||
bool aig_mode;
|
bool aig_mode;
|
||||||
|
bool compat_int_mode;
|
||||||
|
|
||||||
Design *design;
|
Design *design;
|
||||||
Module *module;
|
Module *module;
|
||||||
|
@ -42,8 +43,9 @@ struct JsonWriter
|
||||||
dict<SigBit, string> sigids;
|
dict<SigBit, string> sigids;
|
||||||
pool<Aig> aig_models;
|
pool<Aig> aig_models;
|
||||||
|
|
||||||
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) :
|
JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) :
|
||||||
f(f), use_selection(use_selection), aig_mode(aig_mode) { }
|
f(f), use_selection(use_selection), aig_mode(aig_mode),
|
||||||
|
compat_int_mode(compat_int_mode) { }
|
||||||
|
|
||||||
string get_string(string str)
|
string get_string(string str)
|
||||||
{
|
{
|
||||||
|
@ -102,8 +104,7 @@ struct JsonWriter
|
||||||
if (state < 2)
|
if (state < 2)
|
||||||
str += " ";
|
str += " ";
|
||||||
f << get_string(str);
|
f << get_string(str);
|
||||||
} else
|
} else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) {
|
||||||
if (GetSize(value) == 32 && value.is_fully_def()) {
|
|
||||||
if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
|
if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
|
||||||
f << stringf("%d", value.as_int());
|
f << stringf("%d", value.as_int());
|
||||||
else
|
else
|
||||||
|
@ -294,6 +295,10 @@ struct JsonBackend : public Backend {
|
||||||
log(" -aig\n");
|
log(" -aig\n");
|
||||||
log(" include AIG models for the different gate types\n");
|
log(" include AIG models for the different gate types\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -compat-int\n");
|
||||||
|
log(" emit 32-bit fully-defined parameter values directly\n");
|
||||||
|
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||||
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("The general syntax of the JSON output created by this command is as follows:\n");
|
log("The general syntax of the JSON output created by this command is as follows:\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -368,10 +373,9 @@ struct JsonBackend : public Backend {
|
||||||
log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
|
log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
|
||||||
log("\"z\" instead of a number.\n");
|
log("\"z\" instead of a number.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
|
log("Bit vectors (including integers) are written as string holding the binary");
|
||||||
log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
|
log("representation of the value. Strings are written as strings, with an appended");
|
||||||
log("as string holding the binary representation of the value. Strings are written\n");
|
log("blank in cases of strings of the form /[01xz]* */.\n");
|
||||||
log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
|
|
||||||
log("\n");
|
log("\n");
|
||||||
log("For example the following Verilog code:\n");
|
log("For example the following Verilog code:\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
@ -495,6 +499,7 @@ struct JsonBackend : public Backend {
|
||||||
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||||
{
|
{
|
||||||
bool aig_mode = false;
|
bool aig_mode = false;
|
||||||
|
bool compat_int_mode = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
@ -503,13 +508,17 @@ struct JsonBackend : public Backend {
|
||||||
aig_mode = true;
|
aig_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-compat-int") {
|
||||||
|
compat_int_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(f, filename, args, argidx);
|
extra_args(f, filename, args, argidx);
|
||||||
|
|
||||||
log_header(design, "Executing JSON backend.\n");
|
log_header(design, "Executing JSON backend.\n");
|
||||||
|
|
||||||
JsonWriter json_writer(*f, false, aig_mode);
|
JsonWriter json_writer(*f, false, aig_mode, compat_int_mode);
|
||||||
json_writer.write_design(design);
|
json_writer.write_design(design);
|
||||||
}
|
}
|
||||||
} JsonBackend;
|
} JsonBackend;
|
||||||
|
@ -530,6 +539,10 @@ struct JsonPass : public Pass {
|
||||||
log(" -aig\n");
|
log(" -aig\n");
|
||||||
log(" also include AIG models for the different gate types\n");
|
log(" also include AIG models for the different gate types\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log(" -compat-int\n");
|
||||||
|
log(" emit 32-bit fully-defined parameter values directly\n");
|
||||||
|
log(" as JSON numbers (for compatibility with old parsers)\n");
|
||||||
|
log("\n");
|
||||||
log("See 'help write_json' for a description of the JSON format used.\n");
|
log("See 'help write_json' for a description of the JSON format used.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
|
@ -537,6 +550,7 @@ struct JsonPass : public Pass {
|
||||||
{
|
{
|
||||||
std::string filename;
|
std::string filename;
|
||||||
bool aig_mode = false;
|
bool aig_mode = false;
|
||||||
|
bool compat_int_mode = false;
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
|
@ -549,6 +563,10 @@ struct JsonPass : public Pass {
|
||||||
aig_mode = true;
|
aig_mode = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (args[argidx] == "-compat-int") {
|
||||||
|
compat_int_mode = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
@ -569,7 +587,7 @@ struct JsonPass : public Pass {
|
||||||
f = &buf;
|
f = &buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonWriter json_writer(*f, true, aig_mode);
|
JsonWriter json_writer(*f, true, aig_mode, compat_int_mode);
|
||||||
json_writer.write_design(design);
|
json_writer.write_design(design);
|
||||||
|
|
||||||
if (!filename.empty()) {
|
if (!filename.empty()) {
|
||||||
|
|
|
@ -244,6 +244,7 @@ namespace AST
|
||||||
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
||||||
AstNode *eval_const_function(AstNode *fcall);
|
AstNode *eval_const_function(AstNode *fcall);
|
||||||
bool is_simple_const_expr();
|
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)
|
// create a human-readable text representation of the AST (for debugging)
|
||||||
void dumpAst(FILE *f, std::string indent) const;
|
void dumpAst(FILE *f, std::string indent) const;
|
||||||
|
|
|
@ -41,6 +41,103 @@ YOSYS_NAMESPACE_BEGIN
|
||||||
using namespace AST;
|
using namespace AST;
|
||||||
using namespace AST_INTERNAL;
|
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
|
// 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
|
// values, unrolled for-loops, expanded generate blocks, etc. when this function
|
||||||
// is done with an AST it can be converted into RTLIL using genRTLIL().
|
// 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)
|
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());
|
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();
|
std::string sformat = node_string->bitsAsConst().decode_string();
|
||||||
|
std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint);
|
||||||
// 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, print the message (only include a \n for $display, not for $write)
|
// Finally, print the message (only include a \n for $display, not for $write)
|
||||||
log("%s", sout.c_str());
|
log("%s", sout.c_str());
|
||||||
if (str == "$display")
|
if (str == "$display")
|
||||||
|
@ -2244,6 +2249,17 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
goto apply_newNode;
|
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)
|
if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION)
|
||||||
{
|
{
|
||||||
AstNode *dpi_decl = current_scope[str];
|
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_POS_INDEXED; }
|
||||||
"-:" { return TOK_NEG_INDEXED; }
|
"-:" { return TOK_NEG_INDEXED; }
|
||||||
|
|
||||||
|
".*" { return TOK_WILDCARD_CONNECT; }
|
||||||
|
|
||||||
[-+]?[=*]> {
|
[-+]?[=*]> {
|
||||||
if (!specify_mode) REJECT;
|
if (!specify_mode) REJECT;
|
||||||
frontend_verilog_yylval.string = new std::string(yytext);
|
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 ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
|
||||||
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||||
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
|
%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_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_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
|
||||||
%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
|
%token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH
|
||||||
|
@ -1580,6 +1580,11 @@ cell_port:
|
||||||
node->children.back()->str = *$3;
|
node->children.back()->str = *$3;
|
||||||
delete $3;
|
delete $3;
|
||||||
free_attr($1);
|
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:
|
always_comb_or_latch:
|
||||||
|
|
|
@ -548,6 +548,19 @@ RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find a matching wire for an implicit port connection; traversing generate block scope
|
||||||
|
RTLIL::Wire *find_implicit_port_wire(Module *module, Cell *cell, const std::string& port)
|
||||||
|
{
|
||||||
|
const std::string &cellname = cell->name.str();
|
||||||
|
size_t idx = cellname.size();
|
||||||
|
while ((idx = cellname.find_last_of('.', idx-1)) != std::string::npos) {
|
||||||
|
Wire *found = module->wire(cellname.substr(0, idx+1) + port.substr(1));
|
||||||
|
if (found != nullptr)
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
return module->wire(port);
|
||||||
|
}
|
||||||
|
|
||||||
struct HierarchyPass : public Pass {
|
struct HierarchyPass : public Pass {
|
||||||
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
|
HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { }
|
||||||
void help() YS_OVERRIDE
|
void help() YS_OVERRIDE
|
||||||
|
@ -970,15 +983,71 @@ struct HierarchyPass : public Pass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine default values
|
||||||
|
dict<IdString, dict<IdString, Const>> defaults_db;
|
||||||
if (!nodefaults)
|
if (!nodefaults)
|
||||||
{
|
{
|
||||||
dict<IdString, dict<IdString, Const>> defaults_db;
|
|
||||||
|
|
||||||
for (auto module : design->modules())
|
for (auto module : design->modules())
|
||||||
for (auto wire : module->wires())
|
for (auto wire : module->wires())
|
||||||
if (wire->port_input && wire->attributes.count("\\defaultvalue"))
|
if (wire->port_input && wire->attributes.count("\\defaultvalue"))
|
||||||
defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue");
|
defaults_db[module->name][wire->name] = wire->attributes.at("\\defaultvalue");
|
||||||
|
}
|
||||||
|
// Process SV implicit wildcard port connections
|
||||||
|
std::set<Module*> blackbox_derivatives;
|
||||||
|
std::vector<Module*> design_modules = design->modules();
|
||||||
|
|
||||||
|
for (auto module : design_modules)
|
||||||
|
{
|
||||||
|
for (auto cell : module->cells())
|
||||||
|
{
|
||||||
|
if (!cell->get_bool_attribute(ID(wildcard_port_conns)))
|
||||||
|
continue;
|
||||||
|
Module *m = design->module(cell->type);
|
||||||
|
|
||||||
|
if (m == nullptr)
|
||||||
|
log_error("Cell %s.%s (%s) has implicit port connections but the module it instantiates is unknown.\n",
|
||||||
|
RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||||
|
|
||||||
|
// Need accurate port widths for error checking; so must derive blackboxes with dynamic port widths
|
||||||
|
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
|
||||||
|
IdString new_m_name = m->derive(design, cell->parameters, true);
|
||||||
|
if (new_m_name.empty())
|
||||||
|
continue;
|
||||||
|
if (new_m_name != m->name) {
|
||||||
|
m = design->module(new_m_name);
|
||||||
|
blackbox_derivatives.insert(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto old_connections = cell->connections();
|
||||||
|
for (auto wire : m->wires()) {
|
||||||
|
// Find ports of the module that aren't explicitly connected
|
||||||
|
if (!wire->port_input && !wire->port_output)
|
||||||
|
continue;
|
||||||
|
if (old_connections.count(wire->name))
|
||||||
|
continue;
|
||||||
|
// Make sure a wire of correct name exists in the parent
|
||||||
|
Wire* parent_wire = find_implicit_port_wire(module, cell, wire->name.str());
|
||||||
|
|
||||||
|
// Missing wires are OK when a default value is set
|
||||||
|
if (!nodefaults && parent_wire == nullptr && defaults_db.count(cell->type) && defaults_db.at(cell->type).count(wire->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (parent_wire == nullptr)
|
||||||
|
log_error("No matching wire for implicit port connection `%s' of cell %s.%s (%s).\n",
|
||||||
|
RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||||
|
if (parent_wire->width != wire->width)
|
||||||
|
log_error("Width mismatch between wire (%d bits) and port (%d bits) for implicit port connection `%s' of cell %s.%s (%s).\n",
|
||||||
|
parent_wire->width, wire->width,
|
||||||
|
RTLIL::id2cstr(wire->name), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
|
||||||
|
cell->setPort(wire->name, parent_wire);
|
||||||
|
}
|
||||||
|
cell->attributes.erase(ID(wildcard_port_conns));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nodefaults)
|
||||||
|
{
|
||||||
for (auto module : design->modules())
|
for (auto module : design->modules())
|
||||||
for (auto cell : module->cells())
|
for (auto cell : module->cells())
|
||||||
{
|
{
|
||||||
|
@ -1000,9 +1069,6 @@ struct HierarchyPass : public Pass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<Module*> blackbox_derivatives;
|
|
||||||
std::vector<Module*> design_modules = design->modules();
|
|
||||||
|
|
||||||
for (auto module : design_modules)
|
for (auto module : design_modules)
|
||||||
{
|
{
|
||||||
pool<Wire*> wand_wor_index;
|
pool<Wire*> wand_wor_index;
|
||||||
|
|
|
@ -767,6 +767,9 @@ struct XilinxDspPass : public Pass {
|
||||||
log("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n");
|
log("to a maximum length of 20 cells, corresponding to the smallest Xilinx 7 Series\n");
|
||||||
log("device.\n");
|
log("device.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("This pass is a no-op if the scratchpad variable 'xilinx_dsp.multonly' is set\n");
|
||||||
|
log("to 1.\n");
|
||||||
|
log("\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n");
|
log("Experimental feature: addition/subtractions less than 12 or 24 bits with the\n");
|
||||||
log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n");
|
log("'(* use_dsp=\"simd\" *)' attribute attached to the output wire or attached to\n");
|
||||||
|
@ -805,6 +808,10 @@ struct XilinxDspPass : public Pass {
|
||||||
family = "xcu";
|
family = "xcu";
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto module : design->selected_modules()) {
|
||||||
|
|
||||||
|
if (design->scratchpad_get_bool("xilinx_dsp.multonly"))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Experimental feature: pack $add/$sub cells with
|
// Experimental feature: pack $add/$sub cells with
|
||||||
// (* use_dsp48="simd" *) into DSP48E1's using its
|
// (* use_dsp48="simd" *) into DSP48E1's using its
|
||||||
// SIMD feature
|
// SIMD feature
|
||||||
|
|
|
@ -153,7 +153,7 @@ endmatch
|
||||||
|
|
||||||
match $__XILINX_RAM32X2Q
|
match $__XILINX_RAM32X2Q
|
||||||
min bits 5
|
min bits 5
|
||||||
min rports 3
|
min rports 2
|
||||||
min wports 1
|
min wports 1
|
||||||
make_outreg
|
make_outreg
|
||||||
or_next_if_better
|
or_next_if_better
|
||||||
|
@ -161,7 +161,7 @@ endmatch
|
||||||
|
|
||||||
match $__XILINX_RAM64X1Q
|
match $__XILINX_RAM64X1Q
|
||||||
min bits 5
|
min bits 5
|
||||||
min rports 3
|
min rports 2
|
||||||
min wports 1
|
min wports 1
|
||||||
make_outreg
|
make_outreg
|
||||||
endmatch
|
endmatch
|
||||||
|
|
12
tests/various/sformatf.ys
Normal file
12
tests/various/sformatf.ys
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
read_verilog <<EOT
|
||||||
|
|
||||||
|
module top;
|
||||||
|
localparam a = $sformatf("0x%x", 8'h5A);
|
||||||
|
localparam b = $sformatf("%d", 4'b011);
|
||||||
|
generate
|
||||||
|
if (a != "0x5a") $error("a incorrect!");
|
||||||
|
if (b != "3") $error("b incorrect!");
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
EOT
|
124
tests/various/sv_implicit_ports.sh
Executable file
124
tests/various/sv_implicit_ports.sh
Executable file
|
@ -0,0 +1,124 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
trap 'echo "ERROR in sv_implicit_ports.sh" >&2; exit 1' ERR
|
||||||
|
|
||||||
|
# Simple case
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
wire [7:0] b = 8'd42;
|
||||||
|
add add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Generate block
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
generate
|
||||||
|
if (1) begin:ablock
|
||||||
|
wire [7:0] b = 8'd42;
|
||||||
|
add add_i(.*);
|
||||||
|
end
|
||||||
|
endgenerate
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Missing wire
|
||||||
|
((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
add add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
) 2>&1 | grep -F "ERROR: No matching wire for implicit port connection \`b' of cell top.add_i (add)." > /dev/null
|
||||||
|
|
||||||
|
# Incorrectly sized wire
|
||||||
|
((../../yosys -f "verilog -sv" -qp "hierarchy -top top" - || true) <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
wire [6:0] b = 6'd42;
|
||||||
|
add add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
) 2>&1 | grep -F "ERROR: Width mismatch between wire (7 bits) and port (8 bits) for implicit port connection \`b' of cell top.add_i (add)." > /dev/null
|
||||||
|
|
||||||
|
# Defaults
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add(input [7:0] a = 8'd00, input [7:0] b = 8'd01, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
add add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Parameterised module
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add #(parameter N=3) (input [N-1:0] a = 8'd00, input [N-1:0] b = 8'd01, output [N-1:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
add #(.N(8)) add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Parameterised blackbox module
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - <<EOT
|
||||||
|
(* blackbox *)
|
||||||
|
module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, b, output [7:0] q);
|
||||||
|
add #(.N(8)) add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Parameterised blackbox module - incorrect width
|
||||||
|
((../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:add" - || true) <<EOT
|
||||||
|
(* blackbox *)
|
||||||
|
module add #(parameter N=3) (input [N-1:0] a, b, output [N-1:0] q);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, b, output [7:0] q);
|
||||||
|
add #(.N(6)) add_i(.*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
) 2>&1 | grep -F "ERROR: Width mismatch between wire (8 bits) and port (6 bits) for implicit port connection \`q' of cell top.add_i (add)." > /dev/null
|
||||||
|
|
||||||
|
# Mixed implicit and explicit 1
|
||||||
|
../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, output [7:0] q);
|
||||||
|
add add_i(.b(8'd42), .*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
|
||||||
|
# Mixed implicit and explicit 2
|
||||||
|
(../../yosys -f "verilog -sv" -qp "prep -flatten -top top; select -assert-count 1 t:\$add" - <<EOT
|
||||||
|
module add(input [7:0] a, input [7:0] b, output [7:0] q);
|
||||||
|
assign q = a + b;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module top(input [7:0] a, input [9:0] b, output [7:0] q);
|
||||||
|
add add_i(.b, .*);
|
||||||
|
endmodule
|
||||||
|
EOT
|
||||||
|
) 2>&1 | grep -F "Warning: Resizing cell port top.add_i.b from 10 bits to 8 bits." > /dev/null
|
Loading…
Reference in a new issue