diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 32410a651..0917ecba6 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -23,7 +23,11 @@ #include "kernel/celltypes.h" #include "kernel/cellaigs.h" #include "kernel/log.h" +#include #include +#include +#include +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0; static const FDirection FD_IN = 0x1; static const FDirection FD_OUT = 0x2; static const FDirection FD_INOUT = 0x3; +static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width // Get a port direction with respect to a specific module. FDirection getPortFDirection(IdString id, Module *module) @@ -173,6 +178,26 @@ struct FirrtlWorker void process_instance(RTLIL::Cell *cell, vector &wire_exprs) { std::string cell_type = fid(cell->type); + std::string instanceOf; + // If this is a parameterized module, its parent module is encoded in the cell type + if (cell->type.substr(0, 8) == "$paramod") + { + std::string::iterator it; + for (it = cell_type.begin(); it < cell_type.end(); it++) + { + switch (*it) { + case '\\': /* FALL_THROUGH */ + case '=': /* FALL_THROUGH */ + case '\'': /* FALL_THROUGH */ + case '$': instanceOf.append("_"); break; + default: instanceOf.append(1, *it); break; + } + } + } + else + { + instanceOf = cell_type; + } std::string cell_name = cellname(cell); std::string cell_name_comment; @@ -182,7 +207,13 @@ struct FirrtlWorker cell_name_comment = ""; // Find the module corresponding to this instance. auto instModule = design->module(cell->type); - wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str())); + // If there is no instance for this, just return. + if (instModule == NULL) + { + log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str()); + return; + } + wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str())); for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { if (it->second.size() > 0) { @@ -194,20 +225,20 @@ struct FirrtlWorker std::string source, sink; switch (dir) { case FD_INOUT: - log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second)); + log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); case FD_OUT: source = firstName; sink = secondName; break; case FD_NODIRECTION: - log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second)); + log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); /* FALL_THROUGH */ case FD_IN: source = secondName; sink = firstName; break; default: - log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir); + log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); break; } wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str())); @@ -217,6 +248,20 @@ struct FirrtlWorker } + // Given an expression for a shift amount, and a maximum width, + // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics. + std::string gen_dshl(const string b_expr, const int b_padded_width) + { + string result = b_expr; + if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { + int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; + string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<name)); @@ -225,6 +270,12 @@ struct FirrtlWorker for (auto wire : module->wires()) { const auto wireName = make_id(wire->name); + // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. + if (wire->attributes.count("\\init")) { + log_warning("Initial value (%s) for (%s.%s) not supported\n", + wire->attributes.at("\\init").as_string().c_str(), + log_id(module), log_id(wire)); + } if (wire->port_id) { if (wire->port_input && wire->port_output) @@ -240,7 +291,8 @@ struct FirrtlWorker for (auto cell : module->cells()) { - // Is this cell is a module instance? + bool extract_y_bits = false; // Assume no extraction of final bits will be required. + // Is this cell is a module instance? if (cell->type[0] != '$') { process_instance(cell, wire_exprs); @@ -264,21 +316,21 @@ struct FirrtlWorker } string primop; - bool always_uint = false; + bool always_uint = false; if (cell->type == "$not") primop = "not"; - if (cell->type == "$neg") primop = "neg"; - if (cell->type == "$logic_not") { + else if (cell->type == "$neg") primop = "neg"; + else if (cell->type == "$logic_not") { primop = "eq"; a_expr = stringf("%s, UInt(0)", a_expr.c_str()); } - if (cell->type == "$reduce_and") primop = "andr"; - if (cell->type == "$reduce_or") primop = "orr"; - if (cell->type == "$reduce_xor") primop = "xorr"; - if (cell->type == "$reduce_xnor") { + else if (cell->type == "$reduce_and") primop = "andr"; + else if (cell->type == "$reduce_or") primop = "orr"; + else if (cell->type == "$reduce_xor") primop = "xorr"; + else if (cell->type == "$reduce_xnor") { primop = "not"; a_expr = stringf("xorr(%s)", a_expr.c_str()); } - if (cell->type == "$reduce_bool") { + else if (cell->type == "$reduce_bool") { primop = "neq"; // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); @@ -297,14 +349,15 @@ struct FirrtlWorker continue; } if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", - "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", - "$logic_and", "$logic_or")) + "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", + "$logic_and", "$logic_or")) { string y_id = make_id(cell->name); bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); + int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); if (cell->parameters.at("\\A_SIGNED").as_bool()) { @@ -315,67 +368,93 @@ struct FirrtlWorker if (cell->parameters.at("\\B_SIGNED").as_bool()) { b_expr = "asSInt(" + b_expr + ")"; } - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + if (b_padded_width < y_width) { + auto b_sig = cell->getPort("\\B"); + b_padded_width = y_width; + } } - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + auto a_sig = cell->getPort("\\A"); if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { a_expr = "asUInt(" + a_expr + ")"; } string primop; - bool always_uint = false; + bool always_uint = false; if (cell->type == "$add") primop = "add"; - if (cell->type == "$sub") primop = "sub"; - if (cell->type == "$mul") primop = "mul"; - if (cell->type == "$div") primop = "div"; - if (cell->type == "$mod") primop = "rem"; - if (cell->type == "$and") { + else if (cell->type == "$sub") primop = "sub"; + else if (cell->type == "$mul") primop = "mul"; + else if (cell->type == "$div") primop = "div"; + else if (cell->type == "$mod") primop = "rem"; + else if (cell->type == "$and") { primop = "and"; always_uint = true; } - if (cell->type == "$or" ) { + else if (cell->type == "$or" ) { primop = "or"; always_uint = true; } - if (cell->type == "$xor") { + else if (cell->type == "$xor") { primop = "xor"; always_uint = true; } - if ((cell->type == "$eq") | (cell->type == "$eqx")) { + else if ((cell->type == "$eq") | (cell->type == "$eqx")) { primop = "eq"; always_uint = true; } - if ((cell->type == "$ne") | (cell->type == "$nex")) { + else if ((cell->type == "$ne") | (cell->type == "$nex")) { primop = "neq"; always_uint = true; } - if (cell->type == "$gt") { + else if (cell->type == "$gt") { primop = "gt"; always_uint = true; } - if (cell->type == "$ge") { + else if (cell->type == "$ge") { primop = "geq"; always_uint = true; } - if (cell->type == "$lt") { + else if (cell->type == "$lt") { primop = "lt"; always_uint = true; } - if (cell->type == "$le") { + else if (cell->type == "$le") { primop = "leq"; always_uint = true; } - if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl"; - if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr"; - if ((cell->type == "$logic_and")) { + else if ((cell->type == "$shl") | (cell->type == "$sshl")) { + // FIRRTL will widen the result (y) by the amount of the shift. + // We'll need to offset this by extracting the un-widened portion as Verilog would do. + extract_y_bits = true; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shl"; + } else { + primop = "dshl"; + // Convert from FIRRTL left shift semantics. + b_expr = gen_dshl(b_expr, b_padded_width); + } + } + else if ((cell->type == "$shr") | (cell->type == "$sshr")) { + // We don't need to extract a specific range of bits. + extract_y_bits = false; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shr"; + } else { + primop = "dshr"; + } + } + else if ((cell->type == "$logic_and")) { primop = "and"; a_expr = "neq(" + a_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))"; always_uint = true; } - if ((cell->type == "$logic_or")) { + else if ((cell->type == "$logic_or")) { primop = "or"; a_expr = "neq(" + a_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))"; @@ -388,6 +467,11 @@ struct FirrtlWorker string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + // Deal with FIRRTL's "shift widens" semantics + if (extract_y_bits) { + expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + } + if ((is_signed && !always_uint) || cell->type.in("$sub")) expr = stringf("asUInt(%s)", expr.c_str()); @@ -513,7 +597,65 @@ struct FirrtlWorker continue; } - log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); + // This may be a parameterized module - paramod. + if (cell->type.substr(0, 8) == "$paramod") + { + process_instance(cell, wire_exprs); + continue; + } + if (cell->type == "$shiftx") { + // assign y = a[b +: y_width]; + // We'll extract the correct bits as part of the primop. + + string y_id = make_id(cell->name); + int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); + string a_expr = make_expr(cell->getPort("\\A")); + // Get the initial bit selector + string b_expr = make_expr(cell->getPort("\\B")); + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // Use validif to constrain the selection (test the sign bit) + auto b_string = b_expr.c_str(); + int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1; + b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); + } + string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); + + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + if (cell->type == "$shift") { + // assign y = a >> b; + // where b may be negative + + string y_id = make_id(cell->name); + int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); + string a_expr = make_expr(cell->getPort("\\A")); + string b_expr = make_expr(cell->getPort("\\B")); + auto b_string = b_expr.c_str(); + int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); + string expr; + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // We generate a left or right shift based on the sign of b. + std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width); + std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + expr = stringf("mux(%s < 0, %s, %s)", + b_string, + dshl.c_str(), + dshr.c_str() + ); + } else { + expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + } + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } for (auto conn : module->connections()) @@ -629,38 +771,53 @@ struct FirrtlBackend : public Backend { log(" write_firrtl [options] [filename]\n"); log("\n"); log("Write a FIRRTL netlist of the current design.\n"); + log("The following commands are executed by this command:\n"); + log(" pmuxtree\n"); log("\n"); } void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-aig") { - // aig_mode = true; - // continue; - // } - break; + size_t argidx = args.size(); // We aren't expecting any arguments. + + // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag). + if (filename == "") { + if (argidx > 0 && args[argidx - 1][0] != '-') { + // extra_args and friends need to see this argument. + argidx -= 1; + filename = args[argidx]; + } } extra_args(f, filename, args, argidx); + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + log_header(design, "Executing FIRRTL backend.\n"); + log_push(); - Module *top = design->top_module(); - - if (top == nullptr) - log_error("No top module found!\n"); + Pass::call(design, stringf("pmuxtree")); namecache.clear(); autoid_counter = 0; + // Get the top module, or a reasonable facsimile - we need something for the circuit name. + Module *top = design->top_module(); + Module *last = nullptr; + // Generate module and wire names. for (auto module : design->modules()) { make_id(module->name); + last = module; + if (top == nullptr && module->get_bool_attribute("\\top")) { + top = module; + } for (auto wire : module->wires()) if (wire->port_id) make_id(wire->name); } + if (top == nullptr) + top = last; + *f << stringf("circuit %s:\n", make_id(top->name)); for (auto module : design->modules()) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 4b5a13941..d351a6266 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -293,7 +293,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o } } -void dump_reg_init(std::ostream &f, SigSpec sig, bool write_equals = true) +void dump_reg_init(std::ostream &f, SigSpec sig) { Const initval; bool gotinit = false; @@ -308,7 +308,7 @@ void dump_reg_init(std::ostream &f, SigSpec sig, bool write_equals = true) } if (gotinit) { - if (write_equals) f << " = "; + f << " = "; dump_const(f, initval); } } @@ -1250,14 +1250,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_attributes(f, indent, cell->attributes); f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str()); - std::string init; - if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { - std::stringstream ss; - dump_reg_init(ss, cell->getPort("\\Q"), false /* write_equals */); - init = ss.str(); - } - - if (!defparam && (cell->parameters.size() > 0 || !init.empty())) { + if (!defparam && cell->parameters.size() > 0) { f << stringf(" #("); for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { if (it != cell->parameters.begin()) @@ -1267,11 +1260,6 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(")"); } - if (!init.empty()) { - if (!cell->parameters.empty()) - f << stringf(","); - f << stringf("\n%s .INIT(%s)", indent.c_str(), init.c_str()); - } f << stringf("\n%s" ")", indent.c_str()); } @@ -1313,17 +1301,24 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } f << stringf("\n%s" ");\n", indent.c_str()); - if (defparam && (cell->parameters.size() > 0 || !init.empty())) { + if (defparam && cell->parameters.size() > 0) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second, -1, 0, false, is_signed); f << stringf(";\n"); } - if (!init.empty()) - f << stringf("%sdefparam %s.INIT = %s;\n", indent.c_str(), cell_name.c_str(), init.c_str()); } + if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + std::stringstream ss; + dump_reg_init(ss, cell->getPort("\\Q")); + if (!ss.str().empty()) { + f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str()); + f << ss.str(); + f << ";\n"; + } + } } void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index b9957bd5e..289673e82 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -451,9 +451,8 @@ endmodule //- 1 1 | y //- module \$_SR_NN_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -476,9 +475,8 @@ endmodule //- 1 0 | y //- module \$_SR_NP_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -501,9 +499,8 @@ endmodule //- 0 1 | y //- module \$_SR_PN_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -526,9 +523,8 @@ endmodule //- 0 0 | y //- module \$_SR_PP_ (S, R, Q); -parameter INIT = 1'bx; input S, R; -output reg Q = INIT; +output reg Q; always @(posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -546,9 +542,8 @@ endmodule //- type is usually only used in netlists for formal verification.) //- module \$_FF_ (D, Q); -parameter INIT = 1'bx; input D; -output reg Q = INIT; +output reg Q; always @($global_clock) begin Q <= D; end @@ -567,9 +562,8 @@ endmodule //- - - | q //- module \$_DFF_N_ (D, C, Q); -parameter INIT = 1'bx; input D, C; -output reg Q = INIT; +output reg Q; always @(negedge C) begin Q <= D; end @@ -587,9 +581,8 @@ endmodule //- - - | q //- module \$_DFF_P_ (D, C, Q); -parameter INIT = 1'bx; input D, C; -output reg Q = INIT; +output reg Q; always @(posedge C) begin Q <= D; end @@ -607,9 +600,8 @@ endmodule //- - - - | q //- module \$_DFFE_NN_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(negedge C) begin if (!E) Q <= D; end @@ -627,9 +619,8 @@ endmodule //- - - - | q //- module \$_DFFE_NP_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(negedge C) begin if (E) Q <= D; end @@ -647,9 +638,8 @@ endmodule //- - - - | q //- module \$_DFFE_PN_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(posedge C) begin if (!E) Q <= D; end @@ -667,9 +657,8 @@ endmodule //- - - - | q //- module \$_DFFE_PP_ (D, C, E, Q); -parameter INIT = 1'bx; input D, C, E; -output reg Q = INIT; +output reg Q; always @(posedge C) begin if (E) Q <= D; end @@ -688,9 +677,8 @@ endmodule //- - - - | q //- module \$_DFF_NN0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or negedge R) begin if (R == 0) Q <= 0; @@ -712,9 +700,8 @@ endmodule //- - - - | q //- module \$_DFF_NN1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or negedge R) begin if (R == 0) Q <= 1; @@ -736,9 +723,8 @@ endmodule //- - - - | q //- module \$_DFF_NP0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or posedge R) begin if (R == 1) Q <= 0; @@ -760,9 +746,8 @@ endmodule //- - - - | q //- module \$_DFF_NP1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(negedge C or posedge R) begin if (R == 1) Q <= 1; @@ -784,9 +769,8 @@ endmodule //- - - - | q //- module \$_DFF_PN0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or negedge R) begin if (R == 0) Q <= 0; @@ -808,9 +792,8 @@ endmodule //- - - - | q //- module \$_DFF_PN1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or negedge R) begin if (R == 0) Q <= 1; @@ -832,9 +815,8 @@ endmodule //- - - - | q //- module \$_DFF_PP0_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or posedge R) begin if (R == 1) Q <= 0; @@ -856,9 +838,8 @@ endmodule //- - - - | q //- module \$_DFF_PP1_ (D, C, R, Q); -parameter INIT = 1'bx; input D, C, R; -output reg Q = INIT; +output reg Q; always @(posedge C or posedge R) begin if (R == 1) Q <= 1; @@ -881,9 +862,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -909,9 +889,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NNP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -937,9 +916,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -964,9 +942,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_NPP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(negedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -991,9 +968,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, negedge S, negedge R) begin if (R == 0) Q <= 0; @@ -1019,9 +995,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PNP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, negedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1047,9 +1022,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPN_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, posedge S, negedge R) begin if (R == 0) Q <= 0; @@ -1074,9 +1048,8 @@ endmodule //- - - - - | q //- module \$_DFFSR_PPP_ (C, S, R, D, Q); -parameter INIT = 1'bx; input C, S, R, D; -output reg Q = INIT; +output reg Q; always @(posedge C, posedge S, posedge R) begin if (R == 1) Q <= 0; @@ -1099,9 +1072,8 @@ endmodule //- - - | q //- module \$_DLATCH_N_ (E, D, Q); -parameter INIT = 1'bx; input E, D; -output reg Q = INIT; +output reg Q; always @* begin if (E == 0) Q <= D; @@ -1120,9 +1092,8 @@ endmodule //- - - | q //- module \$_DLATCH_P_ (E, D, Q); -parameter INIT = 1'bx; input E, D; -output reg Q = INIT; +output reg Q; always @* begin if (E == 1) Q <= D; @@ -1143,9 +1114,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1171,9 +1141,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NNP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1199,9 +1168,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1226,9 +1194,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_NPP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1253,9 +1220,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1281,9 +1247,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PNP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; @@ -1309,9 +1274,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPN_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 0) Q <= 0; @@ -1336,9 +1300,8 @@ endmodule //- - - - - | q //- module \$_DLATCHSR_PPP_ (E, S, R, D, Q); -parameter INIT = 1'bx; input E, S, R, D; -output reg Q = INIT; +output reg Q; always @* begin if (R == 1) Q <= 0; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index a1e0c1575..8e43fe058 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1464,11 +1464,10 @@ module \$dff (CLK, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1484,11 +1483,10 @@ module \$dffe (CLK, EN, D, Q); parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; always @(posedge pos_clk) begin @@ -1506,11 +1504,10 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; @@ -1540,11 +1537,10 @@ parameter WIDTH = 0; parameter CLK_POLARITY = 1'b1; parameter ARST_POLARITY = 1'b1; parameter ARST_VALUE = 0; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input CLK, ARST; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_clk = CLK == CLK_POLARITY; wire pos_arst = ARST == ARST_POLARITY; @@ -1563,11 +1559,10 @@ module \$dlatch (EN, D, Q); parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; always @* begin if (EN == EN_POLARITY) @@ -1585,11 +1580,10 @@ parameter WIDTH = 0; parameter EN_POLARITY = 1'b1; parameter SET_POLARITY = 1'b1; parameter CLR_POLARITY = 1'b1; -parameter INIT = {WIDTH > 0 ? WIDTH : 1{1'bx}}; input EN; input [WIDTH-1:0] SET, CLR, D; -output reg [WIDTH-1:0] Q = INIT; +output reg [WIDTH-1:0] Q; wire pos_en = EN == EN_POLARITY; wire [WIDTH-1:0] pos_set = SET_POLARITY ? SET : ~SET; diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh index d5708c456..c22ab6928 100755 --- a/tests/asicworld/run-test.sh +++ b/tests/asicworld/run-test.sh @@ -11,4 +11,4 @@ do done shift "$((OPTIND-1))" -exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS="-e" *.v +exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS+="-e" *.v diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl new file mode 100644 index 000000000..c782a2bd6 --- /dev/null +++ b/tests/asicworld/xfirrtl @@ -0,0 +1,24 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +code_hdl_models_arbiter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_hdl_models_clk_div_45.v yosys issue: 2nd PMUXTREE pass yields: ERROR: Negative edge clock on FF clk_div_45.$procdff$49. +code_hdl_models_d_ff_gates.v combinational loop +code_hdl_models_d_latch_gates.v combinational loop +code_hdl_models_dff_async_reset.v $adff +code_hdl_models_tff_async_reset.v $adff +code_hdl_models_uart.v $adff +code_specman_switch_fabric.v subfield assignment (bits() <= ...) +code_tidbits_asyn_reset.v $adff +code_tidbits_reg_seq_example.v $adff +code_verilog_tutorial_always_example.v empty module +code_verilog_tutorial_escape_id.v make_id issues (name begins with a digit) +code_verilog_tutorial_explicit.v firrtl backend bug (empty module) +code_verilog_tutorial_first_counter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_fsm_full.v error: reg reset; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_if_else.v empty module (everything is under 'always @ (posedge clk)') +[code_verilog_tutorial_n_out_primitive.v empty module +code_verilog_tutorial_parallel_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_simple_function.v empty module (no hardware) +code_verilog_tutorial_simple_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_task_global.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_v2k_reg.v empty module +code_verilog_tutorial_which_clock.v $adff diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl new file mode 100644 index 000000000..00e89b389 --- /dev/null +++ b/tests/simple/xfirrtl @@ -0,0 +1,26 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +arraycells.v inst id[0] of +dff_different_styles.v +generate.v combinational loop +hierdefparam.v inst id[0] of +i2c_master_tests.v $adff +macros.v drops modules +mem2reg.v drops modules +mem_arst.v $adff +memory.v $adff +multiplier.v inst id[0] of +muxtree.v drops modules +omsp_dbg_uart.v $adff +operators.v $pow +paramods.v subfield assignment (bits() <= ...) +partsel.v drops modules +process.v drops modules +realexpr.v drops modules +scopes.v original verilog issues ( -x where x isn't declared signed) +sincos.v $adff +specify.v no code (empty module generates error +subbytes.v $adff +task_func.v drops modules +values.v combinational loop +vloghammer.v combinational loop +wreduce.v original verilog issues ( -x where x isn't declared signed) diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk index c68678929..e0f2bcdc1 100644 --- a/tests/tools/autotest.mk +++ b/tests/tools/autotest.mk @@ -1,7 +1,7 @@ -EXTRA_FLAGS= -SEED= - +# Don't bother defining default values for SEED and EXTRA_FLAGS. +# Their "natural" default values should be sufficient, +# and they may be overridden in the environment. ifneq ($(strip $(SEED)),) SEEDOPT=-S$(SEED) endif diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 0ffa062e3..65fd4cb1f 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -17,12 +17,18 @@ scriptfiles="" scriptopt="" toolsdir="$(cd $(dirname $0); pwd)" warn_iverilog_git=false +# The following are used in verilog to firrtl regression tests. +# Typically these will be passed as environment variables: +#EXTRA_FLAGS="--firrtl2verilog 'java -cp /.../firrtl/utils/bin/firrtl.jar firrtl.Driver'" +# The tests are skipped if firrtl2verilog is the empty string (the default). +firrtl2verilog="" +xfirrtl="../xfirrtl" if [ ! -f $toolsdir/cmp_tbdata -o $toolsdir/cmp_tbdata.c -nt $toolsdir/cmp_tbdata ]; then ( set -ex; ${CC:-gcc} -Wall -o $toolsdir/cmp_tbdata $toolsdir/cmp_tbdata.c; ) || exit 1 fi -while getopts xmGl:wkjvref:s:p:n:S:I:B: opt; do +while getopts xmGl:wkjvref:s:p:n:S:I:B:-: opt; do case "$opt" in x) use_xsim=true ;; @@ -61,8 +67,24 @@ while getopts xmGl:wkjvref:s:p:n:S:I:B: opt; do minclude_opts="$minclude_opts +incdir+$OPTARG" ;; B) backend_opts="$backend_opts $OPTARG" ;; + -) + case "${OPTARG}" in + xfirrtl) + xfirrtl="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + firrtl2verilog) + firrtl2verilog="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + *) + if [ "$OPTERR" == 1 ] && [ "${optspec:0:1}" != ":" ]; then + echo "Unknown option --${OPTARG}" >&2 + fi + ;; + esac;; *) - echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [-B backend_opt] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2 exit 1 esac done @@ -118,6 +140,7 @@ do "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} frontend="verilog" fi + rm -f ${bn}_ref.fir if [ ! -f ../${bn}_tb.v ]; then "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "test_autotb $autotb_opts" -o ${bn}_tb.v ${bn}_ref.v @@ -157,6 +180,13 @@ do else test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.v test_passes -f "$frontend $include_opts" -p "hierarchy; synth -run coarse; techmap; opt; abc -dff" ${bn}_ref.v + if [ -n "$firrtl2verilog" ]; then + if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then + "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v + $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v -X verilog + test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v + fi + fi fi touch ../${bn}.log } @@ -169,14 +199,18 @@ do ( set -ex; body; ) > ${bn}.err 2>&1 fi + did_firrtl="" + if [ -f ${bn}.out/${bn}_ref.fir ]; then + did_firrtl="+FIRRTL " + fi if [ -f ${bn}.log ]; then mv ${bn}.err ${bn}.log - echo "${status_prefix}-> ok" + echo "${status_prefix}${did_firrtl}-> ok" elif [ -f ${bn}.skip ]; then mv ${bn}.err ${bn}.skip echo "${status_prefix}-> skip" else - echo "${status_prefix}-> ERROR!" + echo "${status_prefix}${did_firrtl}-> ERROR!" if $warn_iverilog_git; then echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." fi