aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md19
-rw-r--r--backends/aiger/xaiger.cc2
-rw-r--r--backends/json/json.cc6
-rw-r--r--backends/verilog/verilog_backend.cc12
-rw-r--r--frontends/ast/ast.cc24
-rw-r--r--frontends/ast/ast.h7
-rw-r--r--frontends/ast/genrtlil.cc26
-rw-r--r--frontends/ast/simplify.cc198
-rw-r--r--frontends/verilog/verilog_lexer.l2
-rw-r--r--frontends/verilog/verilog_parser.y218
-rw-r--r--kernel/rtlil.cc8
-rw-r--r--passes/cmds/show.cc19
-rw-r--r--passes/opt/opt_clean.cc24
-rw-r--r--passes/techmap/abc9_ops.cc17
-rw-r--r--passes/techmap/iopadmap.cc9
-rw-r--r--[-rwxr-xr-x]techlibs/achronix/Makefile.inc0
-rw-r--r--[-rwxr-xr-x]techlibs/achronix/speedster22i/cells_arith.v0
-rw-r--r--[-rwxr-xr-x]techlibs/achronix/speedster22i/cells_map.v0
-rw-r--r--[-rwxr-xr-x]techlibs/achronix/speedster22i/cells_sim.v0
-rw-r--r--[-rwxr-xr-x]techlibs/achronix/synth_achronix.cc0
-rw-r--r--techlibs/xilinx/abc9_map.v23
-rw-r--r--tests/aiger/.gitignore2
-rw-r--r--tests/rpc/frontend.py7
-rwxr-xr-xtests/rpc/run-test.sh1
-rw-r--r--tests/rpc/unix.ys6
-rw-r--r--tests/svtypes/enum_simple.sv47
-rw-r--r--tests/svtypes/enum_simple.ys5
-rw-r--r--tests/svtypes/typedef_package.sv3
-rw-r--r--tests/svtypes/typedef_scopes.sv14
-rw-r--r--tests/techmap/iopadmap.ys37
-rw-r--r--tests/various/bug1614.ys5
-rw-r--r--tests/various/specify.v29
-rw-r--r--tests/various/specify.ys21
33 files changed, 674 insertions, 117 deletions
diff --git a/README.md b/README.md
index e4301e7bf..9c15fe3d9 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ prerequisites for building yosys:
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev zlib1g-dev
-Similarily, on Mac OS X Homebrew can be used to install dependencies:
+Similarily, on Mac OS X Homebrew can be used to install dependencies (from within cloned yosys repository):
$ brew tap Homebrew/bundle && brew bundle
@@ -446,6 +446,17 @@ Verilog Attributes and non-standard features
...
endmodule
+- The ``wiretype`` attribute is added by the verilog parser for wires of a
+ typedef'd type to indicate the type identifier.
+
+- Various ``enum_{width}_{value}`` attributes are added to wires of an
+ enumerated type to give a map of possible enum items to their values.
+
+- The ``enum_base_type`` attribute is added to enum items to indicate which
+ enum they belong to (enums -- anonymous and otherwise -- are
+ automatically named with an auto-incrementing counter). Note that enums
+ are currently not strongly typed.
+
- A limited subset of DPI-C functions is supported. The plugin mechanism
(see ``help plugin``) can be used to load .so files with implementations
of DPI-C routines. As a non-standard extension it is possible to specify
@@ -536,6 +547,12 @@ from SystemVerilog:
SystemVerilog files being read into the same design afterwards.
- typedefs are supported (including inside packages)
+ - type identifiers must currently be enclosed in (parentheses) when declaring
+ signals of that type (this is syntactically incorrect SystemVerilog)
+ - type casts are currently not supported
+
+- enums are supported (including inside packages)
+ - but are currently not strongly typed
- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether
ports are inputs or outputs are supported.
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 76b7efbfc..3cf36aca8 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -650,7 +650,7 @@ struct XAigerWriter
log_assert(mergeability > 0);
write_r_buffer(mergeability);
- Const init = cell->attributes.at(ID(abc9_init));
+ Const init = cell->attributes.at(ID(abc9_init), State::Sx);
log_assert(GetSize(init) == 1);
if (init == State::S1)
write_s_buffer(1);
diff --git a/backends/json/json.cc b/backends/json/json.cc
index 5c67cb857..6c924ff99 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -104,7 +104,7 @@ struct JsonWriter
if (state < 2)
str += " ";
f << get_string(str);
- } else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) {
+ } else if (compat_int_mode && GetSize(value) <= 32 && value.is_fully_def()) {
if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
f << stringf("%d", value.as_int());
else
@@ -296,7 +296,7 @@ struct JsonBackend : public Backend {
log(" include AIG models for the different gate types\n");
log("\n");
log(" -compat-int\n");
- log(" emit 32-bit fully-defined parameter values directly\n");
+ log(" emit 32-bit or smaller fully-defined parameter values directly\n");
log(" as JSON numbers (for compatibility with old parsers)\n");
log("\n");
log("\n");
@@ -540,7 +540,7 @@ struct JsonPass : public Pass {
log(" also include AIG models for the different gate types\n");
log("\n");
log(" -compat-int\n");
- log(" emit 32-bit fully-defined parameter values directly\n");
+ log(" emit 32-bit or smaller 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");
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 682c47a1f..19541f1c4 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -1417,11 +1417,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
decimal = 1;
f << ", ";
- dump_const(f, cell->getParam("\\T_LIMIT"));
+ dump_const(f, cell->getParam("\\T_LIMIT_MIN"));
+ f << ": ";
+ dump_const(f, cell->getParam("\\T_LIMIT_TYP"));
+ f << ": ";
+ dump_const(f, cell->getParam("\\T_LIMIT_MAX"));
if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
f << ", ";
- dump_const(f, cell->getParam("\\T_LIMIT2"));
+ dump_const(f, cell->getParam("\\T_LIMIT2_MIN"));
+ f << ": ";
+ dump_const(f, cell->getParam("\\T_LIMIT2_TYP"));
+ f << ": ";
+ dump_const(f, cell->getParam("\\T_LIMIT2_MAX"));
}
f << ");\n";
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 5bbea0faf..239813810 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -88,6 +88,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_LIVE)
X(AST_FAIR)
X(AST_COVER)
+ X(AST_ENUM)
+ X(AST_ENUM_ITEM)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@@ -202,6 +204,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch
is_logic = false;
is_signed = false;
is_string = false;
+ is_enum = false;
is_wand = false;
is_wor = false;
is_unsized = false;
@@ -321,6 +324,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const
fprintf(f, " %d", v);
fprintf(f, " ]");
}
+ if (is_enum) {
+ fprintf(f, " type=enum");
+ }
fprintf(f, "\n");
for (auto &it : attributes) {
@@ -1174,7 +1180,15 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
for (auto n : design->verilog_packages){
for (auto o : n->children) {
AstNode *cloned_node = o->clone();
- cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
+ log("cloned node %s\n", type2str(cloned_node->type).c_str());
+ if (cloned_node->type == AST_ENUM){
+ for (auto e : cloned_node->children){
+ log_assert(e->type == AST_ENUM_ITEM);
+ e->str = n->str + std::string("::") + e->str.substr(1);
+ }
+ } else {
+ cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1);
+ }
(*it)->children.push_back(cloned_node);
}
}
@@ -1203,10 +1217,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
design->add(process_module(*it, defer));
}
- else if ((*it)->type == AST_PACKAGE)
+ else if ((*it)->type == AST_PACKAGE) {
design->verilog_packages.push_back((*it)->clone());
- else
+ }
+ else {
+ // must be global definition
+ (*it)->simplify(false, false, false, 1, -1, false, false); //process enum/other declarations
design->verilog_globals.push_back((*it)->clone());
+ }
}
}
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 14e1cec5e..a50ae306d 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -68,6 +68,8 @@ namespace AST
AST_LIVE,
AST_FAIR,
AST_COVER,
+ AST_ENUM,
+ AST_ENUM_ITEM,
AST_FCALL,
AST_TO_BITS,
@@ -181,6 +183,8 @@ namespace AST
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
+ // set for IDs typed to an enumeration, not used
+ bool is_enum;
// if this is a multirange memory then this vector contains offset and length of each dimension
std::vector<int> multirange_dimensions;
@@ -286,6 +290,9 @@ namespace AST
int isConst() const; // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
double asReal(bool is_signed);
RTLIL::Const realAsConst(int width);
+
+ // helpers for enum
+ void allocateDefaultEnumValues();
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 94f5c0a04..3fb6b3e5c 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -595,6 +595,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
switch (type)
{
+ case AST_NONE:
+ // unallocated enum, ignore
+ break;
case AST_CONSTANT:
width_hint = max(width_hint, int(bits.size()));
if (!is_signed)
@@ -612,7 +615,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
id_ast = current_scope.at(str);
if (!id_ast)
log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
- if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
+ if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) {
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
} else
@@ -861,6 +864,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_GENIF:
case AST_GENCASE:
case AST_PACKAGE:
+ case AST_ENUM:
case AST_MODPORT:
case AST_MODPORTMEMBER:
case AST_TYPEDEF:
@@ -1022,7 +1026,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
else
log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
}
- else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
+ else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM || id2ast->type == AST_ENUM_ITEM) {
if (id2ast->children[0]->type != AST_CONSTANT)
log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str());
chunk = RTLIL::Const(id2ast->children[0]->bits);
@@ -1559,21 +1563,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
- if (cell->type.in("$specify2", "$specify3")) {
+ if (cell->type == "$specify2") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
bool full = cell->getParam("\\FULL").as_bool();
if (!full && src_width != dst_width)
log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
- if (cell->type == "$specify3") {
- int dat_width = GetSize(cell->getPort("\\DAT"));
- if (dat_width != dst_width)
- log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
- }
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
- if (cell->type == "$specrule") {
+ else if (cell->type == "$specify3") {
+ int dat_width = GetSize(cell->getPort("\\DAT"));
+ int dst_width = GetSize(cell->getPort("\\DST"));
+ if (dat_width != dst_width)
+ log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
+ int src_width = GetSize(cell->getPort("\\SRC"));
+ cell->setParam("\\SRC_WIDTH", Const(src_width));
+ cell->setParam("\\DST_WIDTH", Const(dst_width));
+ }
+ else if (cell->type == "$specrule") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
cell->setParam("\\SRC_WIDTH", Const(src_width));
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index fe0412699..57107b76a 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -323,9 +323,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
// 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 || type == AST_TYPEDEF)
+ if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX || type == AST_TYPEDEF)
const_fold = true;
- if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
+ if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM))
const_fold = true;
// in certain cases a function must be evaluated constant. this is what in_param controls.
@@ -410,18 +410,35 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
this_wire_scope[node->str] = node;
}
+ // these nodes appear at the top level in a module and can define names
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL ||
node->type == AST_TYPEDEF) {
backup_scope[node->str] = current_scope[node->str];
current_scope[node->str] = node;
}
+ if (node->type == AST_ENUM) {
+ current_scope[node->str] = node;
+ for (auto enode : node->children) {
+ log_assert(enode->type==AST_ENUM_ITEM);
+ if (current_scope.count(enode->str) == 0) {
+ current_scope[enode->str] = enode;
+ }
+ }
+ }
}
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF)
while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM))
did_something = true;
+ if (node->type == AST_ENUM) {
+ for (auto enode : node->children){
+ log_assert(enode->type==AST_ENUM_ITEM);
+ while (node->simplify(true, false, false, 1, -1, false, in_param))
+ did_something = true;
+ }
+ }
}
}
@@ -497,6 +514,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
break;
+ case AST_ENUM:
+ //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep);
+ if (!basic_prep) {
+ for (auto item_node : children) {
+ while (!item_node->basic_prep && item_node->simplify(false, false, false, stage, -1, false, in_param))
+ did_something = true;
+ }
+ // allocate values (called more than once)
+ allocateDefaultEnumValues();
+ }
+ break;
+
case AST_PARAMETER:
case AST_LOCALPARAM:
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true)
@@ -510,6 +539,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
+ case AST_ENUM_ITEM:
+ while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, in_param))
+ did_something = true;
+ children[0]->detectSignWidth(width_hint, sign_hint);
+ if (children.size() > 1 && children[1]->type == AST_RANGE) {
+ while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param))
+ did_something = true;
+ if (!children[1]->range_valid)
+ log_file_error(filename, linenum, "Non-constant width range on enum item decl.\n");
+ width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
+ }
+ break;
case AST_TO_BITS:
case AST_TO_SIGNED:
@@ -827,11 +868,68 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
range_swapped = templ->range_swapped;
range_left = templ->range_left;
range_right = templ->range_right;
+ attributes["\\wiretype"] = mkconst_str(resolved_type->str);
+ //check if enum
+ if (templ->attributes.count("\\enum_type")){
+ //get reference to enum node:
+ std::string enum_type = templ->attributes["\\enum_type"]->str.c_str();
+ // log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type));
+ // log("current scope:\n");
+ // for (auto &it : current_scope)
+ // log(" %s\n", it.first.c_str());
+ log_assert(current_scope.count(enum_type) == 1);
+ AstNode *enum_node = current_scope.at(enum_type);
+ log_assert(enum_node->type == AST_ENUM);
+ //get width from 1st enum item:
+ log_assert(enum_node->children.size() >= 1);
+ AstNode *enum_item0 = enum_node->children[0];
+ log_assert(enum_item0->type == AST_ENUM_ITEM);
+ int width;
+ if (!enum_item0->range_valid)
+ width = 1;
+ else if (enum_item0->range_swapped)
+ width = enum_item0->range_right - enum_item0->range_left + 1;
+ else
+ width = enum_item0->range_left - enum_item0->range_right + 1;
+ log_assert(width > 0);
+ //add declared enum items:
+ for (auto enum_item : enum_node->children){
+ log_assert(enum_item->type == AST_ENUM_ITEM);
+ //get is_signed
+ bool is_signed;
+ if (enum_item->children.size() == 1){
+ is_signed = false;
+ } else if (enum_item->children.size() == 2){
+ log_assert(enum_item->children[1]->type == AST_RANGE);
+ is_signed = enum_item->children[1]->is_signed;
+ } else {
+ log_error("enum_item children size==%lu, expected 1 or 2 for %s (%s)\n",
+ enum_item->children.size(),
+ enum_item->str.c_str(), enum_node->str.c_str()
+ );
+ }
+ //start building attribute string
+ std::string enum_item_str = "\\enum_";
+ enum_item_str.append(std::to_string(width));
+ enum_item_str.append("_");
+ //get enum item value
+ if(enum_item->children[0]->type != AST_CONSTANT){
+ log_error("expected const, got %s for %s (%s)\n",
+ type2str(enum_item->children[0]->type).c_str(),
+ enum_item->str.c_str(), enum_node->str.c_str()
+ );
+ }
+ int val = enum_item->children[0]->asInt(is_signed);
+ enum_item_str.append(std::to_string(val));
+ //set attribute for available val to enum item name mappings
+ attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str);
+ }
+ }
// Insert clones children from template at beginning
for (int i = 0; i < GetSize(templ->children); i++)
children.insert(children.begin() + i, templ->children[i]->clone());
-
+
if (type == AST_MEMORY && GetSize(children) == 1) {
// Single-bit memories must have [0:0] range
AstNode *rng = new AstNode(AST_RANGE);
@@ -873,12 +971,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
range_swapped = templ->range_swapped;
range_left = templ->range_left;
range_right = templ->range_right;
+ attributes["\\wiretype"] = mkconst_str(resolved_type->str);
for (auto template_child : templ->children)
children.push_back(template_child->clone());
did_something = true;
}
log_assert(!is_custom_type);
- }
+ }
// resolve constant prefixes
if (type == AST_PREFIX) {
@@ -1010,7 +1109,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
// trim/extend parameters
- if (type == AST_PARAMETER || type == AST_LOCALPARAM) {
+ if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_ENUM_ITEM) {
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
@@ -1051,9 +1150,34 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_IDENTIFIER) {
if (current_scope.count(str) == 0) {
for (auto node : current_ast_mod->children) {
- if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR ||
- node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) {
+ //log("looking at mod scope child %s\n", type2str(node->type).c_str());
+ switch (node->type) {
+ case AST_PARAMETER:
+ case AST_LOCALPARAM:
+ case AST_WIRE:
+ case AST_AUTOWIRE:
+ case AST_GENVAR:
+ case AST_MEMORY:
+ case AST_FUNCTION:
+ case AST_TASK:
+ case AST_DPI_FUNCTION:
+ //log("found child %s, %s\n", type2str(node->type).c_str(), node->str.c_str());
+ if (str == node->str) {
+ log("add %s, type %s to scope\n", str.c_str(), type2str(node->type).c_str());
+ current_scope[node->str] = node;
+ }
+ break;
+ case AST_ENUM:
current_scope[node->str] = node;
+ for (auto enum_node : node->children) {
+ log_assert(enum_node->type==AST_ENUM_ITEM);
+ if (str == enum_node->str) {
+ //log("\nadding enum item %s to scope\n", str.c_str());
+ current_scope[str] = enum_node;
+ }
+ }
+ break;
+ default:
break;
}
}
@@ -1279,7 +1403,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (buf->type != AST_CONSTANT)
- log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
+ log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant (%s)!\n", type2str(buf->type).c_str());
delete varbuf->children[0];
varbuf->children[0] = buf;
@@ -2498,7 +2622,7 @@ skip_dynamic_range_lvalue_expansion:;
}
for (auto child : decl->children)
- if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
+ if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM || child->type == AST_ENUM_ITEM)
{
AstNode *wire = nullptr;
@@ -2529,6 +2653,9 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_output = false;
wire->is_reg = true;
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
+ if (child->type == AST_ENUM_ITEM)
+ wire->attributes["\\enum_base_type"] = child->attributes["\\enum_base_type"];
+
wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire);
@@ -2604,7 +2731,7 @@ replace_fcall_later:;
switch (type)
{
case AST_IDENTIFIER:
- if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM)) {
+ if (current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) {
if (current_scope[str]->children[0]->type == AST_CONSTANT) {
if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) {
std::vector<RTLIL::State> data;
@@ -3051,7 +3178,7 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i];
if (child->type == AST_WIRE || child->type == AST_MEMORY || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM ||
- child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF) {
+ child->type == AST_FUNCTION || child->type == AST_TASK || child->type == AST_CELL || child->type == AST_TYPEDEF || child->type == AST_ENUM_ITEM) {
if (backup_name_map.size() == 0)
backup_name_map = name_map;
std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
@@ -3070,6 +3197,27 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
child->str = new_name;
current_scope[new_name] = child;
}
+ if (child->type == AST_ENUM){
+ current_scope[child->str] = child;
+ for (auto enode : child->children){
+ log_assert(enode->type == AST_ENUM_ITEM);
+ if (backup_name_map.size() == 0)
+ backup_name_map = name_map;
+ std::string new_name = prefix[0] == '\\' ? prefix.substr(1) : prefix;
+ size_t pos = enode->str.rfind('.');
+ if (pos == std::string::npos)
+ pos = enode->str[0] == '\\' && prefix[0] == '\\' ? 1 : 0;
+ else
+ pos = pos + 1;
+ new_name = enode->str.substr(0, pos) + new_name + enode->str.substr(pos);
+ if (new_name[0] != '$' && new_name[0] != '\\')
+ new_name = prefix[0] + new_name;
+ name_map[enode->str] = new_name;
+
+ enode->str = new_name;
+ current_scope[new_name] = enode;
+ }
+ }
}
for (size_t i = 0; i < children.size(); i++) {
@@ -3808,4 +3956,32 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
}
+void AstNode::allocateDefaultEnumValues()
+{
+ log_assert(type==AST_ENUM);
+ int last_enum_int = -1;
+ for (auto node : children) {
+ log_assert(node->type==AST_ENUM_ITEM);
+ node->attributes["\\enum_base_type"] = mkconst_str(str);
+ for (size_t i = 0; i < node->children.size(); i++) {
+ switch (node->children[i]->type) {
+ case AST_NONE:
+ // replace with auto-incremented constant
+ delete node->children[i];
+ node->children[i] = AstNode::mkconst_int(++last_enum_int, true);
+ break;
+ case AST_CONSTANT:
+ // explicit constant (or folded expression)
+ // TODO: can't extend 'x or 'z item
+ last_enum_int = node->children[i]->integer;
+ break;
+ default:
+ // ignore ranges
+ break;
+ }
+ // TODO: range check
+ }
+ }
+}
+
YOSYS_NAMESPACE_END
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 9b43c250e..18fa2966b 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -440,7 +440,7 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
}
"&&&" {
- if (!specify_mode) REJECT;
+ if (!specify_mode) return TOK_IGNORED_SPECIFY_AND;
return TOK_SPECIFY_AND;
}
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index 2c7304cc4..bb2a10e9a 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -108,6 +108,20 @@ struct specify_rise_fall {
specify_triple fall;
};
+static AstNode *makeRange(int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = new AstNode(AST_RANGE);
+ range->children.push_back(AstNode::mkconst_int(msb, true));
+ range->children.push_back(AstNode::mkconst_int(lsb, true));
+ range->is_signed = isSigned;
+ return range;
+}
+
+static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = true)
+{
+ auto range = makeRange(msb, lsb, isSigned);
+ parent->children.push_back(range);
+}
%}
%define api.prefix {frontend_verilog_yy}
@@ -146,7 +160,7 @@ struct specify_rise_fall {
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
-%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND TOK_IGNORED_SPECIFY_AND
%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
@@ -157,13 +171,14 @@ struct specify_rise_fall {
%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
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id
+%type <ast> opt_enum_init
%type <boolean> opt_signed opt_property unique_case_attr always_comb_or_latch always_or_always_ff
%type <al> attr case_attr
%type <specify_target_ptr> specify_target
-%type <specify_triple_ptr> specify_triple
+%type <specify_triple_ptr> specify_triple specify_opt_triple
%type <specify_rise_fall_ptr> specify_rise_fall
-%type <ast> specify_if specify_condition specify_opt_arg
+%type <ast> specify_if specify_condition
%type <ch> specify_edge
// operator precedence from low to high
@@ -428,7 +443,9 @@ package:
};
package_body:
- package_body package_body_stmt |;
+ package_body package_body_stmt
+ | // optional
+ ;
package_body_stmt:
typedef_decl |
@@ -476,7 +493,7 @@ wire_type:
astbuf3 = new AstNode(AST_WIRE);
current_wire_rand = false;
current_wire_const = false;
- } wire_type_token_list delay {
+ } wire_type_token_list {
$$ = astbuf3;
};
@@ -604,6 +621,7 @@ module_body:
module_body_stmt:
task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
+ enum_decl |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
@@ -855,7 +873,7 @@ specify_item:
delete target;
delete timing;
} |
- TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
+ TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' specify_triple specify_opt_triple ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
@@ -868,8 +886,8 @@ specify_item:
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
- AstNode *limit = $11;
- AstNode *limit2 = $12;
+ specify_triple *limit = $11;
+ specify_triple *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
@@ -880,11 +898,23 @@ specify_item:
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
- cell->children.push_back(new AstNode(AST_PARASET, limit));
- cell->children.back()->str = "\\T_LIMIT";
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_min));
+ cell->children.back()->str = "\\T_LIMIT_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_avg));
+ cell->children.back()->str = "\\T_LIMIT_TYP";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit->t_max));
+ cell->children.back()->str = "\\T_LIMIT_MAX";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_min : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_MIN";
+
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_avg : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_TYP";
- cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
- cell->children.back()->str = "\\T_LIMIT2";
+ cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2->t_max : AstNode::mkconst_int(0, true)));
+ cell->children.back()->str = "\\T_LIMIT2_MAX";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
@@ -913,8 +943,8 @@ specify_item:
delete $1;
};
-specify_opt_arg:
- ',' expr {
+specify_opt_triple:
+ ',' specify_triple {
$$ = $2;
} |
/* empty */ {
@@ -983,7 +1013,46 @@ specify_rise_fall:
$$->fall = *$4;
delete $2;
delete $4;
- };
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $8;
+ delete $10;
+ delete $12;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ } |
+ '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' {
+ $$ = new specify_rise_fall;
+ $$->rise = *$2;
+ $$->fall = *$4;
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $8;
+ delete $10;
+ delete $12;
+ delete $14;
+ delete $16;
+ delete $18;
+ delete $20;
+ delete $22;
+ delete $24;
+ log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n");
+ }
specify_triple:
expr {
@@ -1031,7 +1100,7 @@ list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
- ignspec_id '=' constant_mintypmax_expression ;
+ ignspec_id '=' ignspec_expr ;
ignspec_opt_cond:
TOK_IF '(' ignspec_expr ')' | /* empty */;
@@ -1048,13 +1117,15 @@ simple_path_declaration :
;
path_delay_value :
- '(' path_delay_expression list_of_path_delay_extra_expressions ')'
- | path_delay_expression
- | path_delay_expression list_of_path_delay_extra_expressions
+ '(' ignspec_expr list_of_path_delay_extra_expressions ')'
+ | ignspec_expr
+ | ignspec_expr list_of_path_delay_extra_expressions
;
list_of_path_delay_extra_expressions :
- ',' path_delay_expression | ',' path_delay_expression list_of_path_delay_extra_expressions;
+ ',' ignspec_expr
+ | ',' ignspec_expr list_of_path_delay_extra_expressions
+ ;
specify_edge_identifier :
TOK_POSEDGE | TOK_NEGEDGE ;
@@ -1105,16 +1176,9 @@ system_timing_arg :
system_timing_args :
system_timing_arg |
+ system_timing_args TOK_IGNORED_SPECIFY_AND system_timing_arg |
system_timing_args ',' system_timing_arg ;
-path_delay_expression :
- ignspec_constant_expression;
-
-constant_mintypmax_expression :
- ignspec_constant_expression
- | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
- ;
-
// for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr'
@@ -1123,10 +1187,16 @@ ignspec_constant_expression:
expr { delete $1; };
ignspec_expr:
- expr { delete $1; };
+ expr { delete $1; } |
+ expr ':' expr ':' expr {
+ delete $1;
+ delete $3;
+ delete $5;
+ };
ignspec_id:
- TOK_ID { delete $1; };
+ TOK_ID { delete $1; }
+ range_or_multirange { delete $3; };
/**********************************************************************/
@@ -1224,6 +1294,85 @@ single_defparam_decl:
ast_stack.back()->children.push_back(node);
};
+enum_type: TOK_ENUM {
+ static int enum_count;
+ // create parent node for the enum
+ astbuf2 = new AstNode(AST_ENUM);
+ ast_stack.back()->children.push_back(astbuf2);
+ astbuf2->str = std::string("$enum");
+ astbuf2->str += std::to_string(enum_count++);
+ // create the template for the names
+ astbuf1 = new AstNode(AST_ENUM_ITEM);
+ astbuf1->children.push_back(AstNode::mkconst_int(0, true));
+ } param_signed enum_base_type '{' enum_name_list '}' { // create template for the enum vars
+ auto tnode = astbuf1->clone();
+ delete astbuf1;
+ astbuf1 = tnode;
+ tnode->type = AST_WIRE;
+ tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str);
+ // drop constant but keep any range
+ delete tnode->children[0];
+ tnode->children.erase(tnode->children.begin()); }
+ ;
+
+enum_base_type: int_vec param_range
+ | int_atom
+ | /* nothing */ {astbuf1->is_reg = true; addRange(astbuf1); }
+ ;
+
+int_atom: TOK_INTEGER {astbuf1->is_reg=true; addRange(astbuf1); } // probably should do byte, range [7:0] here
+ ;
+
+int_vec: TOK_REG {astbuf1->is_reg = true;}
+ | TOK_LOGIC {astbuf1->is_logic = true;}
+ ;
+
+enum_name_list:
+ enum_name_decl
+ | enum_name_list ',' enum_name_decl
+ ;
+
+enum_name_decl:
+ TOK_ID opt_enum_init {
+ // put in fn
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ node->str = *$1;
+ delete $1;
+ delete node->children[0];
+ node->children[0] = $2 ?: new AstNode(AST_NONE);
+ astbuf2->children.push_back(node);
+ }
+ ;
+
+opt_enum_init:
+ '=' basic_expr { $$ = $2; } // TODO: restrict this
+ | /* optional */ { $$ = NULL; }
+ ;
+
+enum_var_list:
+ enum_var
+ | enum_var_list ',' enum_var
+ ;
+
+enum_var: TOK_ID {
+ log_assert(astbuf1);
+ log_assert(astbuf2);
+ auto node = astbuf1->clone();
+ ast_stack.back()->children.push_back(node);
+ node->str = *$1;
+ delete $1;
+ node->is_enum = true;
+ }
+ ;
+
+enum_decl: enum_type enum_var_list ';' {
+ //enum_type creates astbuf1 for use by typedef only
+ delete astbuf1;
+ }
+ ;
+
wire_decl:
attr wire_type range {
albuf = $1;
@@ -1240,7 +1389,7 @@ wire_decl:
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]");
- } wire_name_list {
+ } delay wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
@@ -1434,7 +1583,12 @@ typedef_decl:
ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
ast_stack.back()->children.back()->str = *$4;
- };
+ } |
+ TOK_TYPEDEF enum_type TOK_ID ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_TYPEDEF, astbuf1));
+ ast_stack.back()->children.back()->str = *$3;
+ }
+ ;
cell_stmt:
attr TOK_ID {
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index f286d139f..5d7e61901 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1258,8 +1258,12 @@ namespace {
param_bool(ID(SRC_POL));
param_bool(ID(DST_PEN));
param_bool(ID(DST_POL));
- param(ID(T_LIMIT));
- param(ID(T_LIMIT2));
+ param(ID(T_LIMIT_MIN));
+ param(ID(T_LIMIT_TYP));
+ param(ID(T_LIMIT_MAX));
+ param(ID(T_LIMIT2_MIN));
+ param(ID(T_LIMIT2_TYP));
+ param(ID(T_LIMIT2_MAX));
port(ID(SRC_EN), 1);
port(ID(DST_EN), 1);
port(ID(SRC), param(ID(SRC_WIDTH)));
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc
index eeef24bde..e0d428811 100644
--- a/passes/cmds/show.cc
+++ b/passes/cmds/show.cc
@@ -668,6 +668,10 @@ struct ShowPass : public Pass {
log(" -notitle\n");
log(" do not add the module name as graph title to the dot file\n");
log("\n");
+ log(" -nobg\n");
+ log(" don't run viewer in the background, IE wait for the viewer tool to\n");
+ log(" exit before returning\n");
+ log("\n");
log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
log("\n");
@@ -706,6 +710,7 @@ struct ShowPass : public Pass {
bool flag_abbreviate = true;
bool flag_notitle = false;
bool custom_prefix = false;
+ std::string background = "&";
RTLIL::IdString colorattr;
size_t argidx;
@@ -787,6 +792,10 @@ struct ShowPass : public Pass {
flag_notitle = true;
continue;
}
+ if (arg == "-nobg") {
+ background= "";
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -859,21 +868,19 @@ struct ShowPass : public Pass {
// system()/cmd.exe does not understand single quotes nor
// background tasks on Windows. So we have to pause yosys
// until the viewer exits.
- #define VIEW_CMD "%s \"%s\""
+ std::string cmd = stringf("%s \"%s\"", viewer_exe.c_str(), out_file.c_str());
#else
- #define VIEW_CMD "%s '%s' &"
+ std::string cmd = stringf("%s '%s' %s", viewer_exe.c_str(), out_file.c_str(), background.c_str());
#endif
- std::string cmd = stringf(VIEW_CMD, viewer_exe.c_str(), out_file.c_str());
- #undef VIEW_CMD
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
log_cmd_error("Shell command failed!\n");
} else
if (format.empty()) {
#ifdef __APPLE__
- std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' %s", getuid(), dot_file.c_str(), dot_file.c_str(), background.c_str());
#else
- std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid' 2> /dev/null; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
+ std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid' 2> /dev/null; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' %s", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), background.c_str());
#endif
log("Exec: %s\n", cmd.c_str());
if (run_command(cmd) != 0)
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 2f69b3d4c..f5bb40050 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -51,20 +51,26 @@ struct keep_cache_t
if (cache.count(module))
return cache.at(module);
- cache[module] = true;
- if (!module->get_bool_attribute(ID::keep)) {
- bool found_keep = false;
+ bool found_keep = false;
+ if (module->get_bool_attribute(ID::keep))
+ found_keep = true;
+ else
for (auto cell : module->cells())
- if (query(cell)) found_keep = true;
- cache[module] = found_keep;
- }
+ if (query(cell, true /* ignore_specify */)) {
+ found_keep = true;
+ break;
+ }
+ cache[module] = found_keep;
- return cache[module];
+ return found_keep;
}
- bool query(Cell *cell)
+ bool query(Cell *cell, bool ignore_specify = false)
{
- if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($specify2), ID($specify3), ID($specrule)))
+ if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
+ return true;
+
+ if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule)))
return true;
if (cell->has_keep_attr())
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 7071f0de4..54605f90e 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -192,20 +192,9 @@ void prep_dff(RTLIL::Module *module)
clkdomain_t key(abc9_clock);
auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1));
- auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second));
- log_assert(r2.second);
-
- Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str()));
- if (abc9_init_wire == NULL)
- log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
- log_assert(GetSize(abc9_init_wire) == 1);
- SigSpec abc9_init = assign_map(abc9_init_wire);
- if (!abc9_init.is_fully_const())
- log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
- if (abc9_init == State::S1)
- log_error("'%s.init' in module '%s' has value 1'b1 which is not supported by 'abc9 -dff'.\n", cell->name.c_str(), log_id(module));
- r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
+ auto r2 = cell->attributes.insert(ID(abc9_mergeability));;
log_assert(r2.second);
+ r2.first->second = r.first->second;
}
RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str()));
@@ -763,13 +752,11 @@ void reintegrate(RTLIL::Module *module)
continue;
}
-#ifndef NDEBUG
RTLIL::Module* box_module = design->module(existing_cell->type);
IdString derived_type = box_module->derive(design, existing_cell->parameters);
RTLIL::Module* derived_module = design->module(derived_type);
log_assert(derived_module);
log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at("\\abc9_box_id").as_int()));
-#endif
mapped_cell->type = existing_cell->type;
RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 531ac2b99..a6e4fac14 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -423,6 +423,15 @@ struct IopadmapPass : public Pass {
}
}
+ if (wire->port_output) {
+ auto jt = new_wire->attributes.find(ID(init));
+ // For output ports, move \init attributes from old wire to new wire
+ if (jt != new_wire->attributes.end()) {
+ wire->attributes[ID(init)] = std::move(jt->second);
+ new_wire->attributes.erase(jt);
+ }
+ }
+
wire->port_id = 0;
wire->port_input = false;
wire->port_output = false;
diff --git a/techlibs/achronix/Makefile.inc b/techlibs/achronix/Makefile.inc
index 994cf0015..994cf0015 100755..100644
--- a/techlibs/achronix/Makefile.inc
+++ b/techlibs/achronix/Makefile.inc
diff --git a/techlibs/achronix/speedster22i/cells_arith.v b/techlibs/achronix/speedster22i/cells_arith.v
index e2194cbd7..e2194cbd7 100755..100644
--- a/techlibs/achronix/speedster22i/cells_arith.v
+++ b/techlibs/achronix/speedster22i/cells_arith.v
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v
index 9f647cbef..9f647cbef 100755..100644
--- a/techlibs/achronix/speedster22i/cells_map.v
+++ b/techlibs/achronix/speedster22i/cells_map.v
diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v
index a0c60b4be..a0c60b4be 100755..100644
--- a/techlibs/achronix/speedster22i/cells_sim.v
+++ b/techlibs/achronix/speedster22i/cells_sim.v
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc
index 1dc6bdb2f..1dc6bdb2f 100755..100644
--- a/techlibs/achronix/synth_achronix.cc
+++ b/techlibs/achronix/synth_achronix.cc
diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v
index 539fa4547..f2c401d66 100644
--- a/techlibs/xilinx/abc9_map.v
+++ b/techlibs/xilinx/abc9_map.v
@@ -68,9 +68,10 @@
// (c) a special abc9_ff.clock wire to capture its clock domain and polarity
// (indicated to `abc9' so that it only performs sequential synthesis
// (with reachability analysis) correctly on one domain at a time)
-// (d) a special abc9_ff.init wire to encode the flop's initial state
-// NOTE: in order to perform sequential synthesis, `abc9' also requires
-// that the initial value of all flops be zero
+// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its
+// initial state
+// NOTE: in order to perform sequential synthesis, `abc9' requires that
+// the initial value of all flops be zero
// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
@@ -103,11 +104,11 @@ module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
);
end
endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
@@ -130,11 +131,11 @@ module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
);
end
endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
@@ -166,11 +167,11 @@ module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
@@ -192,11 +193,11 @@ module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
@@ -242,11 +243,11 @@ module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
// Since this is an async flop, async behaviour is dealt with here
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
@@ -280,11 +281,11 @@ module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
@@ -328,11 +329,11 @@ module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
@@ -366,11 +367,11 @@ module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
`endif
diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore
index 9a26bb8f4..b76bdb653 100644
--- a/tests/aiger/.gitignore
+++ b/tests/aiger/.gitignore
@@ -1 +1,3 @@
/*_ref.v
+/*.aag.log
+/*.aig.log
diff --git a/tests/rpc/frontend.py b/tests/rpc/frontend.py
index eff41738a..eace07bf9 100644
--- a/tests/rpc/frontend.py
+++ b/tests/rpc/frontend.py
@@ -31,7 +31,7 @@ end
import json
import argparse
-import sys, socket, os
+import sys, socket, os, subprocess
try:
import msvcrt, win32pipe, win32file
except ImportError:
@@ -85,6 +85,7 @@ def main():
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(args.path)
try:
+ ys_proc = subprocess.Popen(["../../yosys", "-ql", "unix.log", "-p", "connect_rpc -path {}; read_verilog design.v; hierarchy -top top; flatten; select -assert-count 1 t:$neg".format(args.path)])
sock.listen(1)
conn, addr = sock.accept()
file = conn.makefile("rw")
@@ -93,7 +94,11 @@ def main():
if not input: break
file.write(call(input) + "\n")
file.flush()
+ ys_proc.wait(timeout=10)
+ if ys_proc.returncode:
+ raise subprocess.CalledProcessError(ys_proc.returncode, ys_proc.args)
finally:
+ ys_proc.kill()
sock.close()
os.unlink(args.path)
diff --git a/tests/rpc/run-test.sh b/tests/rpc/run-test.sh
index 44ce7e674..eeb309347 100755
--- a/tests/rpc/run-test.sh
+++ b/tests/rpc/run-test.sh
@@ -4,3 +4,4 @@ for x in *.ys; do
echo "Running $x.."
../../yosys -ql ${x%.ys}.log $x
done
+python3 frontend.py unix-socket frontend.sock
diff --git a/tests/rpc/unix.ys b/tests/rpc/unix.ys
deleted file mode 100644
index cc7ec14ab..000000000
--- a/tests/rpc/unix.ys
+++ /dev/null
@@ -1,6 +0,0 @@
-!python3 frontend.py unix-socket frontend.sock & sleep 0.1
-connect_rpc -path frontend.sock
-read_verilog design.v
-hierarchy -top top
-flatten
-select -assert-count 1 t:$neg
diff --git a/tests/svtypes/enum_simple.sv b/tests/svtypes/enum_simple.sv
new file mode 100644
index 000000000..ccaf50da0
--- /dev/null
+++ b/tests/svtypes/enum_simple.sv
@@ -0,0 +1,47 @@
+
+module enum_simple(input clk, input rst);
+
+ enum {s0, s1, s2, s3} test_enum;
+ typedef enum logic [1:0] {
+ ts0, ts1, ts2, ts3
+ } states_t;
+ (states_t) state;
+ (states_t) enum_const = ts1;
+
+ always @(posedge clk) begin
+ if (rst) begin
+ test_enum <= s3;
+ state <= ts0;
+ end else begin
+ //test_enum
+ if (test_enum == s0)
+ test_enum <= s1;
+ else if (test_enum == s1)
+ test_enum <= s2;
+ else if (test_enum == s2)
+ test_enum <= s3;
+ else if (test_enum == s3)
+ test_enum <= s0;
+ else
+ assert(1'b0); //should be unreachable
+
+ //state
+ if (state == ts0)
+ state <= ts1;
+ else if (state == ts1)
+ state <= ts2;
+ else if (state == ts2)
+ state <= ts0;
+ else
+ assert(1'b0); //should be unreachable
+ end
+ end
+
+ always @(*) begin
+ assert(state != 2'h3);
+ assert(s0 == '0);
+ assert(ts0 == '0);
+ assert(enum_const == ts1);
+ end
+
+endmodule
diff --git a/tests/svtypes/enum_simple.ys b/tests/svtypes/enum_simple.ys
new file mode 100644
index 000000000..79981657b
--- /dev/null
+++ b/tests/svtypes/enum_simple.ys
@@ -0,0 +1,5 @@
+
+read_verilog -sv enum_simple.sv
+hierarchy; proc; opt
+sat -verify -seq 1 -set-at 1 rst 1 -tempinduct -prove-asserts -show-all
+
diff --git a/tests/svtypes/typedef_package.sv b/tests/svtypes/typedef_package.sv
index a1e16d4b1..b766f10cf 100644
--- a/tests/svtypes/typedef_package.sv
+++ b/tests/svtypes/typedef_package.sv
@@ -1,11 +1,14 @@
package pkg;
typedef logic [7:0] uint8_t;
+ typedef enum logic [7:0] {bb=8'hBB} enum8_t;
endpackage
module top;
(* keep *) (pkg::uint8_t) a = 8'hAA;
+ (* keep *) (pkg::enum8_t) b_enum = pkg::bb;
always @* assert(a == 8'hAA);
+ always @* assert(b_enum == 8'hBB);
endmodule
diff --git a/tests/svtypes/typedef_scopes.sv b/tests/svtypes/typedef_scopes.sv
index faa385bd6..1c45c7057 100644
--- a/tests/svtypes/typedef_scopes.sv
+++ b/tests/svtypes/typedef_scopes.sv
@@ -1,23 +1,35 @@
typedef logic [3:0] outer_uint4_t;
+typedef enum logic {s0, s1} outer_enum_t;
module top;
(outer_uint4_t) u4_i = 8'hA5;
+ (outer_enum_t) enum4_i = s0;
always @(*) assert(u4_i == 4'h5);
+ always @(*) assert(enum4_i == 1'b0);
typedef logic [3:0] inner_type;
+ typedef enum logic [2:0] {s2=2, s3, s4} inner_enum_t;
(inner_type) inner_i1 = 8'h5A;
+ (inner_enum_t) inner_enum1 = s3;
always @(*) assert(inner_i1 == 4'hA);
+ always @(*) assert(inner_enum1 == 3'h3);
if (1) begin: genblock
typedef logic [7:0] inner_type;
- (inner_type) inner_gb_i = 8'hA5;
+ parameter (inner_type) inner_const = 8'hA5;
+ typedef enum logic [2:0] {s5=5, s6, s7} inner_enum_t;
+ (inner_type) inner_gb_i = inner_const; //8'hA5;
+ (inner_enum_t) inner_gb_enum1 = s7;
always @(*) assert(inner_gb_i == 8'hA5);
+ always @(*) assert(inner_gb_enum1 == 3'h7);
end
(inner_type) inner_i2 = 8'h42;
+ (inner_enum_t) inner_enum2 = s4;
always @(*) assert(inner_i2 == 4'h2);
+ always @(*) assert(inner_enum2 == 3'h4);
endmodule
diff --git a/tests/techmap/iopadmap.ys b/tests/techmap/iopadmap.ys
index c058d1607..0bcc71cce 100644
--- a/tests/techmap/iopadmap.ys
+++ b/tests/techmap/iopadmap.ys
@@ -120,3 +120,40 @@ select -assert-count 1 g/t:iobuf
select -assert-count 1 h/t:ibuf
select -assert-count 1 h/t:iobuf
select -assert-count 1 h/t:obuf
+
+
+# Check that \init attributes get moved from output buffer
+# to buffer input
+design -reset
+read_verilog << EOT
+module obuf (input i, (* iopad_external_pin *) output o); endmodule
+module obuft (input i, input oe, (* iopad_external_pin *) output o); endmodule
+module iobuf (input i, input oe, output o, (* iopad_external_pin *) inout io); endmodule
+module sub(input i, output o); endmodule
+
+module a(input i, (* init=1'b1 *) output o);
+sub s(.i(i), .o(o));
+endmodule
+
+module b(input [1:0] i, oe, (* init=2'b1x *) output [1:0] o);
+wire [1:0] w;
+sub s1(.i(i[0]), .o(w[0]));
+sub s2(.i(i[1]), .o(w[1]));
+assign o = oe ? w : 2'bz;
+endmodule
+
+module c(input i, oe, (* init=2'b00 *) inout io, output o1, o2);
+assign io = oe ? i : 1'bz;
+assign {o1,o2} = {io,io};
+endmodule
+EOT
+opt_clean
+tribuf
+simplemap
+iopadmap -bits -outpad obuf i:o -toutpad obuft oe:i:o -tinoutpad iobuf oe:o:i:io
+select -assert-count 1 a/c:s %co a/a:init=1'b1 %i
+select -assert-count 1 a/a:init
+select -assert-count 1 b/c:s* %co %a b/a:init=2'b1x %i
+select -assert-count 1 b/a:init
+select -assert-count 1 c/t:iobuf %co c/a:init=2'b00 %i
+select -assert-count 1 c/a:init
diff --git a/tests/various/bug1614.ys b/tests/various/bug1614.ys
new file mode 100644
index 000000000..6fbe84a4c
--- /dev/null
+++ b/tests/various/bug1614.ys
@@ -0,0 +1,5 @@
+read_verilog <<EOT
+module testcase;
+ wire [3:0] #1 a = 4'b0000;
+endmodule
+EOT
diff --git a/tests/various/specify.v b/tests/various/specify.v
index 5d44d78f7..c160d2ec4 100644
--- a/tests/various/specify.v
+++ b/tests/various/specify.v
@@ -7,11 +7,9 @@ module test (
if (EN) Q <= D;
specify
-`ifndef SKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS
if (EN) (posedge CLK *> (Q : D)) = (1, 2:3:4);
$setup(D, posedge CLK &&& EN, 5);
$hold(posedge CLK, D &&& EN, 6);
-`endif
endspecify
endmodule
@@ -37,3 +35,30 @@ specify
(posedge clk *> (q +: d)) = (3,1);
endspecify
endmodule
+
+module test3(input clk, input [1:0] d, output [1:0] q);
+specify
+ (posedge clk => (q +: d)) = (3,1);
+ (posedge clk *> (q +: d)) = (3,1);
+endspecify
+endmodule
+
+module test4(input clk, d, output q);
+specify
+ $setup(d, posedge clk, 1:2:3);
+ $setuphold(d, posedge clk, 1:2:3, 4:5:6);
+endspecify
+endmodule
+
+module test5(input clk, d, e, output q);
+specify
+ $setup(d, posedge clk &&& e, 1:2:3);
+endspecify
+endmodule
+
+module test6(input clk, d, e, output q);
+specify
+ (d[0] *> q[0]) = (3,1);
+ (posedge clk[0] => (q[0] +: d[0])) = (3,1);
+endspecify
+endmodule
diff --git a/tests/various/specify.ys b/tests/various/specify.ys
index 00597e1e2..9d55b8eb5 100644
--- a/tests/various/specify.ys
+++ b/tests/various/specify.ys
@@ -55,4 +55,23 @@ equiv_induct -seq 5
equiv_status -assert
design -reset
-read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v
+read_verilog -specify <<EOT
+(* blackbox *)
+module test7_sub(input i, output o);
+specify
+ (i => o) = 1;
+endspecify
+assign o = ~i;
+endmodule
+
+module test7(input i, output o);
+ wire w;
+ test7_sub unused(i, w);
+ test7_sub used(i, o);
+endmodule
+EOT
+hierarchy
+cd test7
+clean
+select -assert-count 1 c:used
+select -assert-none c:* c:used %d