diff options
33 files changed, 674 insertions, 117 deletions
@@ -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 |