diff --git a/README.md b/README.md index efb74ef4e..73124898d 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ writing the design to the console in Yosys's internal format: yosys> write_ilang -elaborate design hierarchy: +elaborate design hierarchy and convert wand/wor nets to logic: yosys> hierarchy @@ -257,7 +257,7 @@ for them: - Non-synthesizable language features as defined in IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 -- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types +- The ``tri``, ``triand`` and ``trior`` net types - The ``config`` and ``disable`` keywords and library map files diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 29e175c15..83993eea9 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -194,6 +194,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_logic = false; is_signed = false; is_string = false; + is_wand = false; + is_wor = false; is_unsized = false; was_checked = false; range_valid = false; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index f90e683ad..46d482f1a 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -173,7 +173,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector bits; - bool is_input, is_output, is_reg, is_logic, is_signed, is_string, range_valid, range_swapped, was_checked, is_unsized; + bool is_input, is_output, is_reg, is_logic, is_signed, is_string, is_wand, is_wor, range_valid, range_swapped, was_checked, is_unsized; int port_id, range_left, range_right; uint32_t integer; double realvalue; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 382b865a4..d2651c9aa 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -920,6 +920,9 @@ 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()); wire->attributes[attr.first] = attr.second->asAttrConst(); } + + if (is_wand) wire->set_bool_attribute("\\wand"); + if (is_wor) wire->set_bool_attribute("\\wor"); } break; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d89e144a9..9558bbfb9 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -218,6 +218,8 @@ YOSYS_NAMESPACE_END "output" { return TOK_OUTPUT; } "inout" { return TOK_INOUT; } "wire" { return TOK_WIRE; } +"wor" { return TOK_WOR; } +"wand" { return TOK_WAND; } "reg" { return TOK_REG; } "integer" { return TOK_INTEGER; } "signed" { return TOK_SIGNED; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 132468f0c..8244a8f44 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -139,7 +139,7 @@ struct specify_rise_fall { %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR -%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC +%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC @@ -485,6 +485,12 @@ wire_type_token_io: wire_type_token: TOK_WIRE { } | + TOK_WOR { + astbuf3->is_wor = true; + } | + TOK_WAND { + astbuf3->is_wand = true; + } | TOK_REG { astbuf3->is_reg = true; } | diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 72bc2e133..013923816 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -562,7 +562,7 @@ struct HierarchyPass : public Pass { log("In parametric designs, a module might exists in several variations with\n"); log("different parameter values. This pass looks at all modules in the current\n"); log("design an re-runs the language frontends for the parametric modules as\n"); - log("needed.\n"); + log("needed. It also resolves assignments to wired logic data types (wand/wor).\n"); log("\n"); log(" -check\n"); log(" also check the design hierarchy. this generates an error when\n"); @@ -941,6 +941,61 @@ struct HierarchyPass : public Pass { std::set blackbox_derivatives; std::vector design_modules = design->modules(); + std::map wlogic_map; + + for (auto module : design_modules) + for (auto wire : module->wires()) + { + Cell *reduce = nullptr; + if (wire->get_bool_attribute("\\wand")) { + reduce = module->addCell( + stringf("$%s_reduce", wire->name.c_str()), "$reduce_and"); + } + if (wire->get_bool_attribute("\\wor")) { + reduce = module->addCell( + stringf("$%s_reduce", wire->name.c_str()), "$reduce_or"); + } + if (reduce) { + if (wire->width > 1) + log_error("Multi-bit wand/wor unsupported (%s)\n", + log_id(wire)); + + reduce->parameters["\\A_SIGNED"] = Const(0); + reduce->parameters["\\A_WIDTH"] = Const(0); + reduce->setPort("\\A", SigSpec()); + + reduce->parameters["\\Y_WIDTH"] = Const(1); + reduce->setPort("\\Y", wire); + wlogic_map[wire] = reduce; + } + } + + for (auto module : design_modules) { + std::vector new_connections; + for (auto &conn : module->connections()) + { + SigSpec sig = conn.first; + for (int i = 0; i < GetSize(sig); i++) { + Wire *sigwire = sig[i].wire; + if (sigwire == nullptr) + continue; + + if (sigwire->get_bool_attribute("\\wor") || sigwire->get_bool_attribute("\\wand")) { + Cell *reduce = wlogic_map[sigwire]; + SigSpec reduce_in = reduce->getPort("\\A"); + int reduce_width = reduce->getParam("\\A_WIDTH").as_int(); + Wire *new_reduce_input = module->addWire( + stringf("%s_in%d", reduce->name.c_str(), reduce_width)); + reduce_in.append(new_reduce_input); + reduce->setPort("\\A", reduce_in); + reduce->fixup_parameters(); + sig[i] = new_reduce_input; + } + } + new_connections.push_back(SigSig(sig, conn.second)); + } + module->new_connections(new_connections); + } for (auto module : design_modules) for (auto cell : module->cells()) @@ -996,6 +1051,27 @@ struct HierarchyPass : public Pass { cell->setPort(conn.first, sig); } + for (int i = 0; i < GetSize(sig); i++) { + Wire *sigwire = sig[i].wire; + if (sigwire == nullptr) + continue; + + if (sigwire->get_bool_attribute("\\wor") || sigwire->get_bool_attribute("\\wand")) { + if (w->port_output && !w->port_input) { + Cell *reduce = wlogic_map[sigwire]; + SigSpec reduce_in = reduce->getPort("\\A"); + int reduce_width = reduce->getParam("\\A_WIDTH").as_int(); + Wire *new_reduce_input = module->addWire( + stringf("$%s_in%d", reduce->name.c_str(), reduce_width)); + reduce_in.append(new_reduce_input); + reduce->setPort("\\A", reduce_in); + reduce->fixup_parameters(); + sig[i] = new_reduce_input; + } + } + } + cell->setPort(conn.first, sig); + if (w->port_output && !w->port_input && sig.has_const()) log_error("Output port %s.%s.%s (%s) is connected to constants: %s\n", log_id(module), log_id(cell), log_id(conn.first), log_id(cell->type), log_signal(sig)); diff --git a/tests/various/wandwor.v b/tests/various/wandwor.v new file mode 100644 index 000000000..fc072daa3 --- /dev/null +++ b/tests/various/wandwor.v @@ -0,0 +1,33 @@ +module a(Q); + output wire Q = 0; +endmodule + +module b(D); + input wire D; +endmodule + +module c; + // net definitions + wor D; + wand E; + + // assignments to wired logic nets + assign D = 1; + assign D = 0; + assign D = 1; + assign D = 0; + + // assignments of wired logic nets to wires + wire F = E; + + genvar i; + for (i = 0; i < 3; i = i + 1) + begin : genloop + // connection of module outputs + a a_inst (.Q(E)); + + // connection of module inputs + b b_inst (.D(E)); + end +endmodule +