Merge branch 'master' of github.com:yosyshq/yosys into q3k/cirrus
diff --git a/README.md b/README.md index 840f2c8..883f2b0 100644 --- a/README.md +++ b/README.md
@@ -117,7 +117,7 @@ yosys> read_verilog tests/simple/fiedler-cooley.v -writing the design to the console in yosys's internal format: +writing the design to the console in Yosys's internal format: yosys> write_ilang @@ -234,7 +234,7 @@ ================================= The following Verilog-2005 features are not supported by -yosys and there are currently no plans to add support +Yosys and there are currently no plans to add support for them: - Non-synthesizable language features as defined in @@ -285,9 +285,9 @@ storage element. The register itself will always have all bits set to 'x' (undefined). The variable may only be used as blocking assigned temporary variable within an always block. This is mostly used internally - by yosys to synthesize Verilog functions and access arrays. + by Yosys to synthesize Verilog functions and access arrays. -- The ``onehot`` attribute on wires mark them as onehot state register. This +- The ``onehot`` attribute on wires mark them as one-hot state register. This is used for example for memory port sharing and set by the fsm_map pass. - The ``blackbox`` attribute on modules is used to mark empty stub modules @@ -319,13 +319,13 @@ through the synthesis. When entities are combined, a new |-separated string is created that contains all the string from the original entities. -- In addition to the ``(* ... *)`` attribute syntax, yosys supports +- In addition to the ``(* ... *)`` attribute syntax, Yosys supports the non-standard ``{* ... *}`` attribute syntax to set default attributes for everything that comes after the ``{* ... *}`` statement. (Reset by adding an empty ``{* *}`` statement.) - In module parameter and port declarations, and cell port and parameter - lists, a trailing comma is ignored. This simplifies writing verilog code + lists, a trailing comma is ignored. This simplifies writing Verilog code generators a bit in some cases. - Modules can be declared with ``module mod_name(...);`` (with three dots @@ -410,11 +410,11 @@ - The system functions ``$allconst`` and ``$allseq`` can be used to construct formal exist-forall problems. Assumptions only hold if the trace satisfies - the assumtion for all ``$allconst/$allseq`` values. For assertions and cover + the assumption for all ``$allconst/$allseq`` values. For assertions and cover statements it is sufficient if just one ``$allconst/$allseq`` value triggers the property (similar to ``$anyconst/$anyseq``). -- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute +- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven by a ``$anyconst/$anyseq/$allconst/$allseq`` function. @@ -485,6 +485,6 @@ Notes: -- To run `make manual` you need to have installed yosys with `make install`, +- To run `make manual` you need to have installed Yosys with `make install`, otherwise it will fail on finding `kernel/yosys.h` while building `PRESENTATION_Prog`.
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index ab27028..53359bd 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc
@@ -133,12 +133,13 @@ cell_recursion_guard.insert(cell); btorf_push(log_id(cell)); - if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx", - "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) + if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx", + "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) { string btor_op; if (cell->type == "$add") btor_op = "add"; if (cell->type == "$sub") btor_op = "sub"; + if (cell->type == "$mul") btor_op = "mul"; if (cell->type.in("$shl", "$sshl")) btor_op = "sll"; if (cell->type == "$shr") btor_op = "srl"; if (cell->type == "$sshr") btor_op = "sra"; @@ -146,6 +147,7 @@ if (cell->type.in("$and", "$_AND_")) btor_op = "and"; if (cell->type.in("$or", "$_OR_")) btor_op = "or"; if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor"; + if (cell->type == "$concat") btor_op = "concat"; if (cell->type == "$_NAND_") btor_op = "nand"; if (cell->type == "$_NOR_") btor_op = "nor"; if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor"; @@ -214,6 +216,40 @@ goto okay; } + if (cell->type.in("$div", "$mod")) + { + string btor_op; + if (cell->type == "$div") btor_op = "div"; + if (cell->type == "$mod") btor_op = "rem"; + log_assert(!btor_op.empty()); + + int width = GetSize(cell->getPort("\\Y")); + width = std::max(width, GetSize(cell->getPort("\\A"))); + width = std::max(width, GetSize(cell->getPort("\\B"))); + + bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; + bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false; + + int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); + int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); + + int sid = get_bv_sid(width); + int nid = next_nid++; + btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b); + + SigSpec sig = sigmap(cell->getPort("\\Y")); + + if (GetSize(sig) < width) { + int sid = get_bv_sid(GetSize(sig)); + int nid2 = next_nid++; + btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1); + nid = nid2; + } + + add_nid_sig(nid, sig); + goto okay; + } + if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) { int sid = get_bv_sid(1);
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index 349bc5a..6f2ccbe 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc
@@ -748,7 +748,7 @@ log("\n"); log(" write_simplec [options] [filename]\n"); log("\n"); - log("Write simple C code for simulating the design. The C code writen can be used to\n"); + log("Write simple C code for simulating the design. The C code written can be used to\n"); log("simulate the design in a C environment, but the purpose of this command is to\n"); log("generate code that works well with C-based formal verification.\n"); log("\n");
diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v index 744dbe9..92329a6 100644 --- a/backends/simplec/test00_uut.v +++ b/backends/simplec/test00_uut.v
@@ -3,12 +3,12 @@ unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y)); assign z = a ^ b ^ c, w = z; endmodule - + module unit_x(input [31:0] a, b, c, output [31:0] x); assign x = (a & b) | c; endmodule - + module unit_y(input [31:0] a, b, c, output [31:0] y); assign y = a & (b | c); endmodule - +
diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 721a395..94a5e2d 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py
@@ -87,7 +87,7 @@ --aig <aim_filename>:<aiw_filename> like above, but for map files and witness files that do not - share a filename prefix (or use differen file extensions). + share a filename prefix (or use different file extensions). --aig-noheader the AIGER witness file does not include the status and @@ -103,8 +103,8 @@ --presat check if the design with assumptions but without assertions is SAT before checking if assertions are UNSAT. This will - detect if there are contradicting assumtions. In some cases - this will also help to "warmup" the solver, potentially + detect if there are contradicting assumptions. In some cases + this will also help to "warm up" the solver, potentially yielding a speedup. --final-only @@ -149,7 +149,7 @@ --append <num_steps> add <num_steps> time steps at the end of the trace when creating a counter example (this additional time - steps will still be constrained by assumtions) + steps will still be constrained by assumptions) """ + so.helpmsg()) sys.exit(1)
diff --git a/backends/table/table.cc b/backends/table/table.cc index 979273d..b75169e 100644 --- a/backends/table/table.cc +++ b/backends/table/table.cc
@@ -109,7 +109,7 @@ else if (cell->output(conn.first)) *f << "out" << "\t"; else - *f << "unkown" << "\t"; + *f << "unknown" << "\t"; *f << log_signal(sigmap(conn.second)) << "\n"; }
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 71db25f..2537e18 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc
@@ -1447,7 +1447,7 @@ } if (!module->processes.empty()) - log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n" + log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n" "can't always be mapped directly to Verilog always blocks. Unintended\n" "changes in simulation behavior are possible! Use \"proc\" to convert\n" "processes to logic networks and registers.\n", log_id(module));
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 2c15615..5a1bae7 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc
@@ -36,14 +36,14 @@ using namespace AST; using namespace AST_INTERNAL; -// instanciate global variables (public API) +// instantiate global variables (public API) namespace AST { std::string current_filename; void (*set_line_num)(int) = NULL; int (*get_line_num)() = NULL; } -// instanciate global variables (private API) +// instantiate global variables (private API) namespace AST_INTERNAL { bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit; bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 55abe16..83714f8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc
@@ -1810,6 +1810,11 @@ log_assert(block != nullptr); + if (num_steps == 0) { + newNode = children[0]->clone(); + goto apply_newNode; + } + int myidx = autoidx++; AstNode *outreg = nullptr;
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index 034b3e7..9116b25 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc
@@ -276,7 +276,7 @@ if(lastcell == nullptr || module == nullptr) { - err_reason = stringf("No primative object to attach .cname %s.", p); + err_reason = stringf("No primitive object to attach .cname %s.", p); goto error_with_reason; }
diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index d8783ac..6b302a7 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc
@@ -44,11 +44,39 @@ log("Load modules from an ilang file to the current design. (ilang is a text\n"); log("representation of a design in yosys's internal format.)\n"); log("\n"); + log(" -nooverwrite\n"); + log(" ignore re-definitions of modules. (the default behavior is to\n"); + log(" create an error message if the existing module is not a blackbox\n"); + log(" module, and overwrite the existing module if it is a blackbox module.)\n"); + log("\n"); + log(" -overwrite\n"); + log(" overwrite existing modules with the same name\n"); + log("\n"); } void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + ILANG_FRONTEND::flag_nooverwrite = false; + ILANG_FRONTEND::flag_overwrite = false; + log_header(design, "Executing ILANG frontend.\n"); - extra_args(f, filename, args, 1); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-nooverwrite") { + ILANG_FRONTEND::flag_nooverwrite = true; + ILANG_FRONTEND::flag_overwrite = false; + continue; + } + if (arg == "-overwrite") { + ILANG_FRONTEND::flag_nooverwrite = false; + ILANG_FRONTEND::flag_overwrite = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + log("Input filename: %s\n", filename.c_str()); ILANG_FRONTEND::lexin = f;
diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h index ad3ffec..052dd4c 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/ilang/ilang_frontend.h
@@ -32,6 +32,8 @@ namespace ILANG_FRONTEND { extern std::istream *lexin; extern RTLIL::Design *current_design; + extern bool flag_nooverwrite; + extern bool flag_overwrite; } YOSYS_NAMESPACE_END
diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index b957ecd..5bcc01f 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y
@@ -37,6 +37,8 @@ std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack; std::vector<RTLIL::CaseRule*> case_stack; dict<RTLIL::IdString, RTLIL::Const> attrbuf; + bool flag_nooverwrite, flag_overwrite; + bool delete_current_module; } using namespace ILANG_FRONTEND; YOSYS_NAMESPACE_END @@ -93,18 +95,36 @@ module: TOK_MODULE TOK_ID EOL { - if (current_design->has($2)) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); + delete_current_module = false; + if (current_design->has($2)) { + RTLIL::Module *existing_mod = current_design->module($2); + if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) { + log("Ignoring blackbox re-definition of module %s.\n", $2); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", $2); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2); + current_design->remove(existing_mod); + } + } current_module = new RTLIL::Module; current_module->name = $2; current_module->attributes = attrbuf; - current_design->add(current_module); + if (!delete_current_module) + current_design->add(current_module); attrbuf.clear(); free($2); } module_body TOK_END { if (attrbuf.size() != 0) rtlil_frontend_ilang_yyerror("dangling attribute"); current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + current_module = nullptr; } EOL; module_body:
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index 4acfbf1..6e3cffa 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc
@@ -616,7 +616,7 @@ LibertyAst *bus_type_node = node->find("bus_type"); if (!bus_type_node || !type_map.count(bus_type_node->value)) - log_error("Unkown or unsupported type for bus interface %s on cell %s.\n", + log_error("Unknown or unsupported type for bus interface %s on cell %s.\n", node->args.at(0).c_str(), log_id(cell_name)); int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index bc035c3..94138cd 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc
@@ -130,6 +130,15 @@ return false; } +RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) +{ + std::string s = stringf("$verific$%s", obj->Name()); + if (obj->Linefile()) + s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile())); + s += stringf("$%d", autoidx++); + return s; +} + void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj) { MapIter mi; @@ -215,7 +224,7 @@ dummy_wire = NULL; } else { if (dummy_wire == NULL) - dummy_wire = module->addWire(NEW_ID); + dummy_wire = module->addWire(new_verific_id(inst)); else dummy_wire->width++; sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1)); @@ -231,8 +240,8 @@ } if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addAndGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + module->addAndGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); return true; } @@ -243,8 +252,8 @@ } if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addOrGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + module->addOrGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); return true; } @@ -284,16 +293,16 @@ if (inst->Type() == PRIM_FADD) { RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin()); - RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(NEW_ID); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID); - RTLIL::SigSpec tmp1 = module->addWire(NEW_ID); - RTLIL::SigSpec tmp2 = module->addWire(NEW_ID); - RTLIL::SigSpec tmp3 = module->addWire(NEW_ID); - module->addXorGate(NEW_ID, a, b, tmp1); + RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(new_verific_id(inst)); + RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp1 = module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp2 = module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp3 = module->addWire(new_verific_id(inst)); + module->addXorGate(new_verific_id(inst), a, b, tmp1); module->addXorGate(inst_name, tmp1, c, y); - module->addAndGate(NEW_ID, tmp1, c, tmp2); - module->addAndGate(NEW_ID, a, b, tmp3); - module->addOrGate(NEW_ID, tmp2, tmp3, x); + module->addAndGate(new_verific_id(inst), tmp1, c, tmp2); + module->addAndGate(new_verific_id(inst), a, b, tmp3); + module->addOrGate(new_verific_id(inst), tmp2, tmp3, x); return true; } @@ -320,63 +329,78 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name) { + RTLIL::Cell *cell = nullptr; + if (inst->Type() == PRIM_AND) { - module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addAnd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + cell = module->addAnd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + import_attributes(cell->attributes, inst); + cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_OR) { - module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addOr(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + cell = module->addOr(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + import_attributes(cell->attributes, inst); + cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_XOR) { - module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_XNOR) { - module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_INV) { - module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_MUX) { - module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + cell = module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_TRI) { - module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_FADD) { - RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID); + RTLIL::SigSpec a_plus_b = module->addWire(new_verific_id(inst), 2); + RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); if (inst->GetCout()) y.append(net_map_at(inst->GetCout())); - module->addAdd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b); - module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y); + cell = module->addAdd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b); + import_attributes(cell->attributes, inst); + cell = module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y); + import_attributes(cell->attributes, inst); return true; } @@ -387,24 +411,26 @@ log_assert(clocking.body_net == nullptr); if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); else if (inst->GetSet()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0); + cell = clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0); else if (inst->GetReset()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1); + cell = clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1); else - clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), + cell = clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_DLATCHRS) { if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); else - module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), + cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } @@ -420,37 +446,45 @@ if (inst->GetCout() != NULL) out.append(net_map_at(inst->GetCout())); if (inst->GetCin()->IsGnd()) { - module->addAdd(inst_name, IN1, IN2, out, SIGNED); + cell = module->addAdd(inst_name, IN1, IN2, out, SIGNED); + import_attributes(cell->attributes, inst); } else { - RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out)); - module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED); - module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst), GetSize(out)); + cell = module->addAdd(new_verific_id(inst), IN1, IN2, tmp, SIGNED); + import_attributes(cell->attributes, inst); + cell = module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false); + import_attributes(cell->attributes, inst); } return true; } if (inst->Type() == OPER_MULTIPLIER) { - module->addMul(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMul(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_DIVIDER) { - module->addDiv(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addDiv(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_MODULO) { - module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REMAINDER) { - module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_SHIFT_LEFT) { - module->addShl(inst_name, IN1, IN2, OUT, false); + cell = module->addShl(inst_name, IN1, IN2, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -460,7 +494,8 @@ for (unsigned i = 1; i < inst->OutputSize(); i++) { vec.append(RTLIL::State::S0); } - module->addShl(inst_name, vec, IN, OUT, false); + cell = module->addShl(inst_name, vec, IN, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -470,7 +505,8 @@ for (unsigned i = 1; i < inst->OutputSize(); i++) { vec.append(RTLIL::State::S0); } - module->addShl(inst_name, vec, IN, OUT, false); + cell = module->addShl(inst_name, vec, IN, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -478,108 +514,127 @@ Net *net_cin = inst->GetCin(); Net *net_a_msb = inst->GetInput1Bit(0); if (net_cin->IsGnd()) - module->addShr(inst_name, IN1, IN2, OUT, false); + cell = module->addShr(inst_name, IN1, IN2, OUT, false); else if (net_cin == net_a_msb) - module->addSshr(inst_name, IN1, IN2, OUT, true); + cell = module->addSshr(inst_name, IN1, IN2, OUT, true); else log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name()); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_AND) { - module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_OR) { - module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_XOR) { - module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_XNOR) { - module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_NOR) { - SigSpec t = module->ReduceOr(NEW_ID, IN, SIGNED); - module->addNot(inst_name, t, net_map_at(inst->GetOutput())); + SigSpec t = module->ReduceOr(new_verific_id(inst), IN, SIGNED); + cell = module->addNot(inst_name, t, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_LESSTHAN) { Net *net_cin = inst->GetCin(); if (net_cin->IsGnd()) - module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); else if (net_cin->IsPwr()) - module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); else log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name()); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_AND) { - module->addAnd(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addAnd(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_OR) { - module->addOr(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addOr(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_XOR) { - module->addXor(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addXor(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_XNOR) { - module->addXnor(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addXnor(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_BUF) { - module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); + cell = module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_INV) { - module->addNot(inst_name, IN, OUT, SIGNED); + cell = module->addNot(inst_name, IN, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_MINUS) { - module->addSub(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addSub(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_UMINUS) { - module->addNeg(inst_name, IN, OUT, SIGNED); + cell = module->addNeg(inst_name, IN, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_EQUAL) { - module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_NEQUAL) { - module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_MUX) { - module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT); + cell = module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_NTO1MUX) { - module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); + cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } @@ -599,25 +654,29 @@ padded_data.append(d); } - module->addShr(inst_name, padded_data, sel, out); + cell = module->addShr(inst_name, padded_data, sel, out); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_SELECTOR) { - module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput())); + cell = module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_SELECTOR) { SigSpec out = OUT; - module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out); + cell = module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_TRI) { - module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT); + cell = module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT); + import_attributes(cell->attributes, inst); return true; } @@ -631,9 +690,10 @@ RTLIL::SigSpec sig_reset = operatorInport(inst, "reset"); if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool()) - clocking.addDff(inst_name, IN, OUT); + cell = clocking.addDff(inst_name, IN, OUT); else - clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT); + cell = clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT); + import_attributes(cell->attributes, inst); return true; } @@ -862,7 +922,7 @@ ascii_initdata++; } if (initval_valid) { - RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit"); + RTLIL::Cell *cell = module->addCell(new_verific_id(net), "$meminit"); cell->parameters["\\WORDS"] = 1; if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) cell->setPort("\\ADDR", word_idx); @@ -925,7 +985,7 @@ if (net->Bus()) continue; - RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : NEW_ID); + RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net)); if (verific_verbose) log(" importing net %s as %s.\n", net->Name(), log_id(wire_name)); @@ -949,7 +1009,7 @@ if (found_new_net) { - RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : NEW_ID); + RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus)); if (verific_verbose) log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name)); @@ -1025,16 +1085,16 @@ } if (GetSize(anyconst_sig)) - module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig))); + module->connect(anyconst_sig, module->Anyconst(new_verific_id(netbus), GetSize(anyconst_sig))); if (GetSize(anyseq_sig)) - module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig))); + module->connect(anyseq_sig, module->Anyseq(new_verific_id(netbus), GetSize(anyseq_sig))); if (GetSize(allconst_sig)) - module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig))); + module->connect(allconst_sig, module->Allconst(new_verific_id(netbus), GetSize(allconst_sig))); if (GetSize(allseq_sig)) - module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig))); + module->connect(allseq_sig, module->Allseq(new_verific_id(netbus), GetSize(allseq_sig))); } for (auto it : init_nets) @@ -1058,10 +1118,10 @@ } for (auto net : anyconst_nets) - module->connect(net_map_at(net), module->Anyconst(NEW_ID)); + module->connect(net_map_at(net), module->Anyconst(new_verific_id(net))); for (auto net : anyseq_nets) - module->connect(net_map_at(net), module->Anyseq(NEW_ID)); + module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); pool<Instance*, hash_ptr_ops> sva_asserts; pool<Instance*, hash_ptr_ops> sva_assumes; @@ -1072,7 +1132,7 @@ FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) { - RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : NEW_ID); + RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst)); if (verific_verbose) log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name)); @@ -1140,27 +1200,34 @@ if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT) { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name())); - if (memory->width != int(inst->Input2Size())) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); + int numchunks = int(inst->Input2Size()) / memory->width; + int chunksbits = ceil_log2(numchunks); - RTLIL::SigSpec addr = operatorInput1(inst); - RTLIL::SigSpec data = operatorInput2(inst); + if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) + log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); - RTLIL::Cell *cell = module->addCell(inst_name, "$memwr"); - cell->parameters["\\MEMID"] = memory->name.str(); - cell->parameters["\\CLK_ENABLE"] = false; - cell->parameters["\\CLK_POLARITY"] = true; - cell->parameters["\\PRIORITY"] = 0; - cell->parameters["\\ABITS"] = GetSize(addr); - cell->parameters["\\WIDTH"] = GetSize(data); - cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data))); - cell->setPort("\\CLK", RTLIL::State::S0); - cell->setPort("\\ADDR", addr); - cell->setPort("\\DATA", data); + for (int i = 0; i < numchunks; i++) + { + RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; + RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); - if (inst->Type() == OPER_CLOCKED_WRITE_PORT) { - cell->parameters["\\CLK_ENABLE"] = true; - cell->setPort("\\CLK", net_map_at(inst->GetClock())); + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : + RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memwr"); + cell->parameters["\\MEMID"] = memory->name.str(); + cell->parameters["\\CLK_ENABLE"] = false; + cell->parameters["\\CLK_POLARITY"] = true; + cell->parameters["\\PRIORITY"] = 0; + cell->parameters["\\ABITS"] = GetSize(addr); + cell->parameters["\\WIDTH"] = GetSize(data); + cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data))); + cell->setPort("\\CLK", RTLIL::State::S0); + cell->setPort("\\ADDR", addr); + cell->setPort("\\DATA", data); + + if (inst->Type() == OPER_CLOCKED_WRITE_PORT) { + cell->parameters["\\CLK_ENABLE"] = true; + cell->setPort("\\CLK", net_map_at(inst->GetClock())); + } } continue; } @@ -1196,7 +1263,7 @@ log_assert(inst->Input1Size() == inst->OutputSize()); SigSpec sig_d, sig_q, sig_o; - sig_q = module->addWire(NEW_ID, inst->Input1Size()); + sig_q = module->addWire(new_verific_id(inst), inst->Input1Size()); for (int i = int(inst->Input1Size())-1; i >= 0; i--){ sig_d.append(net_map_at(inst->GetInput1Bit(i))); @@ -1210,8 +1277,8 @@ log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); } - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addXnor(NEW_ID, sig_d, sig_q, sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); if (!mode_keep) continue; @@ -1225,7 +1292,7 @@ SigSpec sig_d = net_map_at(inst->GetInput1()); SigSpec sig_o = net_map_at(inst->GetOutput()); - SigSpec sig_q = module->addWire(NEW_ID); + SigSpec sig_q = module->addWire(new_verific_id(inst)); if (verific_verbose) { log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", @@ -1234,8 +1301,8 @@ log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); } - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addXnor(NEW_ID, sig_d, sig_q, sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); if (!mode_keep) continue; @@ -1254,7 +1321,7 @@ log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - past_ffs.insert(clocking.addDff(NEW_ID, sig_d, sig_q)); + past_ffs.insert(clocking.addDff(new_verific_id(inst), sig_d, sig_q)); if (!mode_keep) continue; @@ -1268,14 +1335,14 @@ SigBit sig_d = net_map_at(inst->GetInput1()); SigBit sig_o = net_map_at(inst->GetOutput()); - SigBit sig_q = module->addWire(NEW_ID); + SigBit sig_q = module->addWire(new_verific_id(inst)); if (verific_verbose) log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addEq(NEW_ID, {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o); if (!mode_keep) continue; @@ -1298,9 +1365,9 @@ Cell *cell = nullptr; if (assume_attr != nullptr && !strcmp(assume_attr, "1")) - cell = module->addAssume(NEW_ID, cond, State::S1); + cell = module->addAssume(new_verific_id(inst), cond, State::S1); else - cell = module->addAssert(NEW_ID, cond, State::S1); + cell = module->addAssert(new_verific_id(inst), cond, State::S1); import_attributes(cell->attributes, inst); continue; @@ -1342,7 +1409,7 @@ IdString port_name_id = RTLIL::escape_id(port_name); auto &sigvec = cell_port_conns[port_name_id]; if (GetSize(sigvec) <= port_offset) { - SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec)); + SigSpec zwires = module->addWire(new_verific_id(inst), port_offset+1-GetSize(sigvec)); for (auto bit : zwires) sigvec.push_back(bit); } @@ -1833,13 +1900,19 @@ { Message::SetConsoleOutput(0); Message::RegisterCallBackMsg(msg_func); + RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); - RuntimeFlags::SetVar("db_infer_wide_operators", 1); + + RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); + RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); + + RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); + RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); // Workaround for VIPER #13851 RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1);
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 334a436..b331dd4 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h
@@ -78,6 +78,7 @@ RTLIL::SigBit net_map_at(Verific::Net *net); + RTLIL::IdString new_verific_id(Verific::DesignObj *obj); void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj); RTLIL::SigSpec operatorInput(Verific::Instance *inst);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index cdc9ece..6681115 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc
@@ -827,9 +827,9 @@ for (auto &it : nodes[i].edges) { if (it.second != State::S1) - log(" egde %s -> %d\n", log_signal(it.second), it.first); + log(" edge %s -> %d\n", log_signal(it.second), it.first); else - log(" egde -> %d\n", it.first); + log(" edge -> %d\n", it.first); } for (auto &it : nodes[i].links) { @@ -856,9 +856,9 @@ for (auto &it : unodes[i].edges) { if (!it.second.empty()) - log(" egde %s -> %d\n", log_signal(it.second), it.first); + log(" edge %s -> %d\n", log_signal(it.second), it.first); else - log(" egde -> %d\n", it.first); + log(" edge -> %d\n", it.first); } for (auto &ctrl : unodes[i].accept) {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 51e112e..a6718b0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y
@@ -794,7 +794,7 @@ list_of_path_outputs : specify_output_terminal_descriptor | list_of_path_outputs ',' specify_output_terminal_descriptor ; - + opt_polarity_operator : '+' | '-' @@ -819,7 +819,7 @@ system_timing_args : system_timing_arg | system_timing_args ',' system_timing_arg ; - + /* t_path_delay_expression : path_delay_expression; @@ -881,7 +881,7 @@ // 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' -// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness +// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness constant_expression: expr ;
diff --git a/kernel/log.h b/kernel/log.h index 0b4905c..e1f54a1 100644 --- a/kernel/log.h +++ b/kernel/log.h
@@ -195,7 +195,7 @@ t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; # else -# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)." # endif }
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 14259f8..8404db5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc
@@ -3793,6 +3793,11 @@ delete *it; } +bool RTLIL::CaseRule::empty() const +{ + return actions.empty() && switches.empty(); +} + RTLIL::CaseRule *RTLIL::CaseRule::clone() const { RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule; @@ -3809,6 +3814,11 @@ delete *it; } +bool RTLIL::SwitchRule::empty() const +{ + return cases.empty(); +} + RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const { RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule;
diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 276540a..f877622 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h
@@ -1227,6 +1227,8 @@ ~CaseRule(); void optimize(); + bool empty() const; + template<typename T> void rewrite_sigspecs(T &functor); RTLIL::CaseRule *clone() const; }; @@ -1238,6 +1240,8 @@ ~SwitchRule(); + bool empty() const; + template<typename T> void rewrite_sigspecs(T &functor); RTLIL::SwitchRule *clone() const; };
diff --git a/kernel/yosys.cc b/kernel/yosys.cc index f002955..2ed0f4d 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc
@@ -166,7 +166,7 @@ std::string string; char *str = NULL; -#if defined(_WIN32 )|| defined(__CYGWIN__) +#if defined(_WIN32 )|| defined(__CYGWIN__) int sz = 64, rc; while (1) { va_list apc; @@ -637,8 +637,9 @@ struct TclPass : public Pass { TclPass() : Pass("tcl", "execute a TCL script file") { } void help() YS_OVERRIDE { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" tcl <filename>\n"); + log(" tcl <filename> [args]\n"); log("\n"); log("This command executes the tcl commands in the specified file.\n"); log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); @@ -648,14 +649,24 @@ log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n"); log("in order to avoid a name collision with the built in commands.\n"); log("\n"); + log("If any arguments are specified, these arguments are provided to the script via\n"); + log("the standard $argc and $argv variables.\n"); + log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + void execute(std::vector<std::string> args, RTLIL::Design *) YS_OVERRIDE { if (args.size() < 2) log_cmd_error("Missing script file.\n"); - if (args.size() > 2) - extra_args(args, 1, design, false); - if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK) - log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); + + std::vector<Tcl_Obj*> script_args; + for (auto it = args.begin() + 2; it != args.end(); ++it) + script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size())); + + Tcl_Interp *interp = yosys_get_tcl_interp(); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0); + if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) + log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); } } TclPass; #endif @@ -733,7 +744,7 @@ return "/"; } #else - #error Dont know how to determine process executable base path! + #error "Don't know how to determine process executable base path!" #endif #ifdef EMSCRIPTEN
diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h index 983e6fd..3a34c13 100644 --- a/libs/ezsat/ezminisat.h +++ b/libs/ezsat/ezminisat.h
@@ -28,7 +28,7 @@ #include <time.h> // minisat is using limit macros and format macros in their headers that -// can be the source of some troubles when used from c++11. thefore we +// can be the source of some troubles when used from c++11. therefore we // don't force ezSAT users to use minisat headers.. namespace Minisat { class Solver;
diff --git a/libs/subcircuit/README b/libs/subcircuit/README index b133568..ecaa987 100644 --- a/libs/subcircuit/README +++ b/libs/subcircuit/README
@@ -109,7 +109,7 @@ Setting up graphs ----------------- -Instanciate the SubCircuit::Graph class and use the methods of this class to +Instantiate the SubCircuit::Graph class and use the methods of this class to set up the circuit. SubCircuit::Graph myGraph; @@ -152,7 +152,7 @@ The method createConstant() can be used to add a constant driver to a signal. The signal value is encoded as one char by bit, allowing for multi-valued -logic matching. The follwoing command sets the lowest bit of cell6.A to a +logic matching. The following command sets the lowest bit of cell6.A to a logic 1: myGraph.createConnection("cell6", "A", 0, '1'); @@ -314,7 +314,7 @@ Perform additional checks on a pair of a pair of adjacent nodes (one adjacent pair from the needle and one adjacent pair from the haystack) - to determine wheter this edge from the needle is compatible with + to determine whether this edge from the needle is compatible with that edge from the haystack. The default implementation always returns true.
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 277e893..d40a600 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex
@@ -211,14 +211,15 @@ \subsection{Memories} \label{sec:memcells} -Memories are either represented using RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells -or simply by using {\tt \$mem} cells. +Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} +cells, or by {\tt \$mem} cells alone. In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width, size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port) cell is created. Having individual cells for read and write ports has the advantage that they can be consolidated using resource sharing passes. In some cases this drastically reduces the number of required -ports on the memory cell. +ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells, +which allow delaying constant folding for initialization addresses and data until after the frontend finishes. The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR}, and a data output \B{DATA}. They also have the @@ -253,7 +254,7 @@ \begin{itemize} \item \B{MEMID} \\ -The name of the RTLIL::Memory object that is associated with this read port. +The name of the RTLIL::Memory object that is associated with this write port. \item \B{ABITS} \\ The number of address bits (width of the \B{ADDR} input port). @@ -262,7 +263,7 @@ The number of data bits (width of the \B{DATA} output port). \item \B{CLK\_ENABLE} \\ -When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and +When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and the \B{CLK} input is not used. \item \B{CLK\_POLARITY} \\ @@ -273,6 +274,27 @@ The cell with the higher integer value in this parameter wins a write conflict. \end{itemize} +The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width +of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs +must resolve to a constant for synthesis to succeed. + +\begin{itemize} +\item \B{MEMID} \\ +The name of the RTLIL::Memory object that is associated with this initialization cell. + +\item \B{ABITS} \\ +The number of address bits (width of the \B{ADDR} input port). + +\item \B{WIDTH} \\ +The number of data bits per memory location. + +\item \B{WORDS} \\ +The number of consecutive memory locations initialized by this cell. + +\item \B{PRIORITY} \\ +The cell with the higher integer value in this parameter wins an initialization conflict. +\end{itemize} + The HDL frontend models a memory using RTLIL::Memory objects and asynchronous {\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates {\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then @@ -295,6 +317,9 @@ \item \B{WIDTH} \\ The number of data bits per word. +\item \B{INIT} \\ +The initial memory contents. + \item \B{RD\_PORTS} \\ The number of read ports on this memory cell. @@ -345,9 +370,11 @@ This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports. \end{itemize} -The {\tt techmap} pass can be used to manually map {\tt \$mem} cells to -specialized memory cells on the target architecture, such as block ram resources -on an FPGA. +The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells +belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation. +The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports. +The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA. +The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders. \subsection{Finite State Machines}
diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex index 964875d..2feb0f1 100644 --- a/manual/CHAPTER_Overview.tex +++ b/manual/CHAPTER_Overview.tex
@@ -428,8 +428,8 @@ All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to {\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports -to the memory. The \B{MEMID} parameter on these cells is used to link them together and to the -RTLIL::Memory object they belong to. +to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend. +The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to. The rationale behind using separate cells for the individual ports versus creating a large multiport memory cell right in the language frontend is that
diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc index 522758e..7e32da6 100644 --- a/passes/cmds/chformal.cc +++ b/passes/cmds/chformal.cc
@@ -32,7 +32,7 @@ log(" chformal [types] [mode] [options] [selection]\n"); log("\n"); log("Make changes to the formal constraints of the design. The [types] options\n"); - log("the type of constraint to operate on. If none of the folling options is given,\n"); + log("the type of constraint to operate on. If none of the following options are given,\n"); log("the command will operate on all constraint types:\n"); log("\n"); log(" -assert $assert cells, representing assert(...) constraints\n"); @@ -59,7 +59,7 @@ log(" -assume2assert\n"); log(" -live2fair\n"); log(" -fair2live\n"); - log(" change the roles of cells as indicated. this options can be combined\n"); + log(" change the roles of cells as indicated. these options can be combined\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc index d480b79..f93bada 100644 --- a/passes/cmds/connect.cc +++ b/passes/cmds/connect.cc
@@ -137,7 +137,7 @@ if (!set_lhs.empty()) { if (!unset_expr.empty() || !port_cell.empty()) - log_cmd_error("Cant use -set together with -unset and/or -port.\n"); + log_cmd_error("Can't use -set together with -unset and/or -port.\n"); RTLIL::SigSpec sig_lhs, sig_rhs; if (!RTLIL::SigSpec::parse_sel(sig_lhs, design, module, set_lhs)) @@ -157,7 +157,7 @@ if (!unset_expr.empty()) { if (!port_cell.empty() || flag_nounset) - log_cmd_error("Cant use -unset together with -port and/or -nounset.\n"); + log_cmd_error("Can't use -unset together with -port and/or -nounset.\n"); RTLIL::SigSpec sig; if (!RTLIL::SigSpec::parse_sel(sig, design, module, unset_expr)) @@ -170,7 +170,7 @@ if (!port_cell.empty()) { if (flag_nounset) - log_cmd_error("Cant use -port together with -nounset.\n"); + log_cmd_error("Can't use -port together with -nounset.\n"); if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0) log_cmd_error("Can't find cell %s.\n", port_cell.c_str());
diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index ba407ea..b5e8ef1 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc
@@ -987,7 +987,7 @@ log("list of selected objects.\n"); log("\n"); log("Note that many commands support an optional [selection] argument that can be\n"); - log("used to YS_OVERRIDE the global selection for the command. The syntax of this\n"); + log("used to override the global selection for the command. The syntax of this\n"); log("optional argument is identical to the syntax of the <selection> argument\n"); log("described here.\n"); log("\n");
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index a1dfa9b..56ef2d1 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc
@@ -137,7 +137,7 @@ log(" replace with $anyconst drivers (for formal)\n"); log("\n"); log(" -random <seed>\n"); - log(" replace with random bits using the specified integer als seed\n"); + log(" replace with random bits using the specified integer as seed\n"); log(" value for the random number generator.\n"); log("\n"); log(" -init\n");
diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index a488732..58acd30 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc
@@ -623,7 +623,7 @@ log(" assigned to each unique value of this attribute.\n"); log("\n"); log(" -width\n"); - log(" annotate busses with a label indicating the width of the bus.\n"); + log(" annotate buses with a label indicating the width of the bus.\n"); log("\n"); log(" -signed\n"); log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index ff80f38..ee96ace 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc
@@ -37,7 +37,7 @@ log("specified logfile(s).\n"); log("\n"); log(" -q\n"); - log(" Do not print output to the normal destination (console and/or log file)\n"); + log(" Do not print output to the normal destination (console and/or log file).\n"); log("\n"); log(" -o logfile\n"); log(" Write output to this file, truncate if exists.\n"); @@ -46,7 +46,7 @@ log(" Write output to this file, append if exists.\n"); log("\n"); log(" +INT, -INT\n"); - log(" Add/subract INT from the -v setting for this command.\n"); + log(" Add/subtract INT from the -v setting for this command.\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index fc504e9..5ae991b 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc
@@ -196,13 +196,13 @@ vector<string> warnings; if (is_module_port) - warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n"); + warnings.push_back("Forcing FSM recoding on module port might result in larger circuit.\n"); if (!looks_like_good_state_reg) - warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n"); + warnings.push_back("Users of state reg look like FSM recoding might result in larger circuit.\n"); if (has_init_attr) - warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!"); + warnings.push_back("Initialization value on FSM state register is ignored. Possible simulation-synthesis mismatch!\n"); if (!looks_like_state_reg) warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n"); @@ -236,7 +236,7 @@ log(" Users of register don't seem to benefit from recoding.\n"); if (has_init_attr) - log(" Register has an initialization value."); + log(" Register has an initialization value.\n"); if (is_self_resetting) log(" Circuit seems to be self-resetting.\n");
diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index 67551f6..6095eaf 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc
@@ -178,7 +178,7 @@ log_state_in = fsm_data.state_table.at(state_in); if (states.count(ce.values_map(ce.assign_map(dff_in)).as_const()) == 0) { - log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transistion!>%s\n", + log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transition!>%s\n", log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(ce.values_map(ce.assign_map(dff_in))), log_signal(tr.ctrl_out), undef_bit_in_next_state_mode ? " SHORTENED" : ""); @@ -194,7 +194,7 @@ log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out)); } else { - log(" transition: %10s %s -> %10s %s <ignored undef transistion!>\n", + log(" transition: %10s %s -> %10s %s <ignored undef transition!>\n", log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out)); }
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 0c782b8..0e28dbc 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc
@@ -543,7 +543,7 @@ log(" an unknown module is used as cell type.\n"); log("\n"); log(" -simcheck\n"); - log(" like -check, but also thow an error if blackbox modules are\n"); + log(" like -check, but also throw an error if blackbox modules are\n"); log(" instantiated, and throw an error if the design has no top module\n"); log("\n"); log(" -purge_lib\n");
diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index 70d9871..369fcc8 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc
@@ -184,9 +184,6 @@ mem->parameters["\\OFFSET"] = Const(memory->start_offset); mem->parameters["\\SIZE"] = Const(memory->size); mem->parameters["\\ABITS"] = Const(addr_bits); - - while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx) - init_data.bits.pop_back(); mem->parameters["\\INIT"] = init_data; log_assert(sig_wr_clk.size() == wr_ports);
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 32df191..220d292 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc
@@ -41,7 +41,7 @@ if (wire->attributes.count("\\init") == 0) continue; SigSpec sig = sigmap(wire); - Const initval = wire->attributes.count("\\init"); + Const initval = wire->attributes.at("\\init"); for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++) if (initval[i] == State::S0 || initval[i] == State::S1) init_bits.insert(sig[i]);
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 610edc5..998c650 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc
@@ -1477,7 +1477,7 @@ log(" opt_expr [options] [selection]\n"); log("\n"); log("This pass performs const folding on internal cell types with constant inputs.\n"); - log("It also performs some simple expression rewritring.\n"); + log("It also performs some simple expression rewriting.\n"); log("\n"); log(" -mux_undef\n"); log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n");
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index be050c7..26855fd 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc
@@ -36,7 +36,7 @@ dict<RTLIL::Cell*, pool<RTLIL::Cell*>> luts_dlogics; dict<RTLIL::Cell*, pool<int>> luts_dlogic_inputs; - int combined_count = 0; + int eliminated_count = 0, combined_count = 0; bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs) { @@ -133,7 +133,7 @@ // Second, make sure that the connection to dedicated logic is legal. If it is not legal, // it means one of the two things: // * The connection is spurious. I.e. this is dedicated logic that will be packed - // with some other LUT, and it just happens to be conected to this LUT as well. + // with some other LUT, and it just happens to be connected to this LUT as well. // * The connection is illegal. // In either of these cases, we don't need to concern ourselves with preserving the connection // between this LUT and this dedicated logic cell. @@ -188,7 +188,7 @@ show_stats_by_arity(); log("\n"); - log("Combining LUTs.\n"); + log("Eliminating LUTs.\n"); pool<RTLIL::Cell*> worklist = luts; while (worklist.size()) { @@ -198,6 +198,106 @@ break; } + auto lut = worklist.pop(); + SigSpec lut_input = sigmap(lut->getPort("\\A")); + pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut]; + + vector<SigBit> lut_inputs; + for (auto &bit : lut_input) + { + if (bit.wire) + lut_inputs.push_back(sigmap(bit)); + } + + bool const0_match = true; + bool const1_match = true; + vector<bool> input_matches; + for (size_t i = 0; i < lut_inputs.size(); i++) + input_matches.push_back(true); + + for (int eval = 0; eval < 1 << lut_inputs.size(); eval++) + { + dict<SigBit, bool> eval_inputs; + for (size_t i = 0; i < lut_inputs.size(); i++) + eval_inputs[lut_inputs[i]] = (eval >> i) & 1; + bool value = evaluate_lut(lut, eval_inputs); + if (value != 0) + const0_match = false; + if (value != 1) + const1_match = false; + for (size_t i = 0; i < lut_inputs.size(); i++) + { + if (value != eval_inputs[lut_inputs[i]]) + input_matches[i] = false; + } + } + + int input_match = -1; + for (size_t i = 0; i < lut_inputs.size(); i++) + if (input_matches[i]) + input_match = i; + + if (const0_match || const1_match || input_match != -1) + { + log("Found redundant cell %s.%s.\n", log_id(module), log_id(lut)); + + SigBit value; + if (const0_match) + { + log(" Cell evaluates constant 0.\n"); + value = State::S0; + } + if (const1_match) + { + log(" Cell evaluates constant 1.\n"); + value = State::S1; + } + if (input_match != -1) { + log(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match])); + value = lut_inputs[input_match]; + } + + if (lut_dlogic_inputs.size()) + { + log(" Not eliminating cell (connected to dedicated logic).\n"); + } + else + { + SigSpec lut_output = lut->getPort("\\Y"); + for (auto &port : index.query_ports(lut_output)) + { + if (port.cell != lut && luts.count(port.cell)) + worklist.insert(port.cell); + } + + module->connect(lut_output, value); + sigmap.add(lut_output, value); + + module->remove(lut); + luts.erase(lut); + luts_arity.erase(lut); + luts_dlogics.erase(lut); + luts_dlogic_inputs.erase(lut); + + eliminated_count++; + if (limit > 0) + limit--; + } + } + } + show_stats_by_arity(); + + log("\n"); + log("Combining LUTs.\n"); + worklist = luts; + while (worklist.size()) + { + if (limit == 0) + { + log("Limit reached.\n"); + break; + } + auto lutA = worklist.pop(); SigSpec lutA_input = sigmap(lutA->getPort("\\A")); SigSpec lutA_output = sigmap(lutA->getPort("\\Y")[0]); @@ -487,16 +587,20 @@ } extra_args(args, argidx, design); - int total_count = 0; + int eliminated_count = 0, combined_count = 0; for (auto module : design->selected_modules()) { - OptLutWorker worker(dlogic, module, limit - total_count); - total_count += worker.combined_count; + OptLutWorker worker(dlogic, module, limit - eliminated_count - combined_count); + eliminated_count += worker.eliminated_count; + combined_count += worker.combined_count; } - if (total_count) + if (eliminated_count) + design->scratchpad_set_bool("opt.did_something", true); + if (combined_count) design->scratchpad_set_bool("opt.did_something", true); log("\n"); - log("Combined %d LUTs.\n", total_count); + log("Eliminated %d LUTs.\n", eliminated_count); + log("Combined %d LUTs.\n", combined_count); } } OptLutPass;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 0164f58..8063b86 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc
@@ -235,8 +235,11 @@ } else { while (GetSize(sig) > 0) { - auto info = mi.query(sig[GetSize(sig)-1]); + auto bit = sig[GetSize(sig)-1]; + if (keep_bits.count(bit)) + break; + auto info = mi.query(bit); if (info->is_output || GetSize(info->ports) > 1) break;
diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index b9e43d1..3919e4b 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc
@@ -77,18 +77,36 @@ } else { - bool all_cases_are_empty = true; - for (auto cs : sw->cases) { - if (cs->actions.size() != 0 || cs->switches.size() != 0) - all_cases_are_empty = false; + bool all_fully_def = true; + for (auto cs : sw->cases) + { if (max_depth != 0) proc_clean_case(cs, did_something, count, max_depth-1); + for (auto cmp : cs->compare) + if (!cmp.is_fully_def()) + all_fully_def = false; } - if (all_cases_are_empty) { - did_something = true; - for (auto cs : sw->cases) - delete cs; - sw->cases.clear(); + if (all_fully_def) + { + for (auto cs = sw->cases.begin(); cs != sw->cases.end();) + { + if ((*cs)->empty()) + { + did_something = true; + delete *cs; + cs = sw->cases.erase(cs); + } + else ++cs; + } + } + else + { + while (!sw->cases.empty() && sw->cases.back()->empty()) + { + did_something = true; + delete sw->cases.back(); + sw->cases.pop_back(); + } } } } @@ -106,7 +124,7 @@ } for (size_t i = 0; i < cs->switches.size(); i++) { RTLIL::SwitchRule *sw = cs->switches[i]; - if (sw->cases.size() == 0) { + if (sw->empty()) { cs->switches.erase(cs->switches.begin() + (i--)); did_something = true; delete sw;
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index a8eecc9..4839048 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc
@@ -43,18 +43,37 @@ log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); log(" mode.)\n"); log("\n"); + log(" -strinit <string for high> <string for low> \n"); + log(" use string values in the command line to represent a single-bit\n"); + log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); + log(" mode.)\n"); + log("\n"); + log(" -noreinit\n"); + log(" fail if the FF cell has already a defined initial value set in other\n"); + log(" passes and the initial value of the net it drives is not equal to\n"); + log(" the already defined initial value.\n"); + log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n"); dict<IdString, dict<IdString, IdString>> ff_types; - bool highlow_mode = false; + bool highlow_mode = false, noreinit = false; + std::string high_string, low_string; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-highlow") { highlow_mode = true; + high_string = "high"; + low_string = "low"; + continue; + } + if (args[argidx] == "-strinit" && argidx+2 < args.size()) { + highlow_mode = true; + high_string = args[++argidx]; + low_string = args[++argidx]; continue; } if (args[argidx] == "-ff" && argidx+3 < args.size()) { @@ -64,6 +83,10 @@ ff_types[cell_name][output_port] = init_param; continue; } + if (args[argidx] == "-noreinit") { + noreinit = true; + continue; + } break; } extra_args(args, argidx, design); @@ -112,6 +135,10 @@ continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) + log_error("Trying to assign a different init value for %s.%s.%s which technically " + "have a conflicted init value.\n", + log_id(module), log_id(cell), log_id(it.second)); value.bits[i] = init_bits.at(sig[i]); cleanup_bits.insert(sig[i]); } @@ -121,9 +148,9 @@ log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n", log_id(module), log_id(cell), log_id(it.second)); if (value[0] == State::S1) - value = Const("high"); + value = Const(high_string); else - value = Const("low"); + value = Const(low_string); } log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second),
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v index 95f5d59..9f647cb 100755 --- a/techlibs/achronix/speedster22i/cells_map.v +++ b/techlibs/achronix/speedster22i/cells_map.v
@@ -32,7 +32,7 @@ // > end buffers < // > Look-Up table < -// > VT: I still think Achronix folks would have choosen a better \ +// > VT: I still think Achronix folks would have chosen a better \ // > logic architecture. // LUT Map module \$lut (A, Y); @@ -43,30 +43,30 @@ generate if (WIDTH == 1) begin // VT: This is not consistent and ACE will complain: assign Y = ~A[0]; - LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(1'b0), .din2(1'b0), .din3(1'b0)); end else if (WIDTH == 2) begin - LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0), .din3(1'b0)); end else if(WIDTH == 3) begin - LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(1'b0)); end else if(WIDTH == 4) begin - LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_ + LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3])); end else wire _TECHMAP_FAIL_ = 1; endgenerate -endmodule +endmodule // > end LUT < // > Flops < // DFF flop module \$_DFF_P_ (input D, C, output Q); - DFF _TECHMAP_REPLACE_ + DFF _TECHMAP_REPLACE_ (.q(Q), .d(D), .ck(C)); -endmodule +endmodule
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 92b1078..3642e3b 100755 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc
@@ -108,7 +108,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_ACHRONIX pass.\n"); log_push();
diff --git a/techlibs/anlogic/Makefile.inc b/techlibs/anlogic/Makefile.inc index 59be83f..f37b5e7 100644 --- a/techlibs/anlogic/Makefile.inc +++ b/techlibs/anlogic/Makefile.inc
@@ -5,5 +5,6 @@ $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v))
diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 36b920e..cfc743a 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v
@@ -1,19 +1,31 @@ -module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule -module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule + +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule `ifndef NO_LUT module \$lut (A, Y);
diff --git a/techlibs/anlogic/drams.txt b/techlibs/anlogic/drams.txt index 2bff14a..eb94775 100644 --- a/techlibs/anlogic/drams.txt +++ b/techlibs/anlogic/drams.txt
@@ -1,7 +1,7 @@ bram $__ANLOGIC_DRAM16X4 init 0 abits 4 - dbits 2 + dbits 4 groups 2 ports 1 1 wrmode 0 1
diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index a4eafed..fab199f 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc
@@ -119,7 +119,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_ANLOGIC pass.\n"); log_push(); @@ -170,13 +170,14 @@ { run("dffsr2dff"); run("techmap -D NO_LUT -map +/anlogic/cells_map.v"); + run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); run("simplemap"); } if (check_label("map_luts")) { - run("abc -lut 6"); + run("abc -lut 4:6"); run("clean"); }
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 70074f6..0e05620 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc
@@ -26,5 +26,5 @@ $(eval $(call add_share_file,share,techlibs/common/adff2dff.v)) $(eval $(call add_share_file,share,techlibs/common/dff2ff.v)) $(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) +$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) -
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v new file mode 100644 index 0000000..8aa1eb9 --- /dev/null +++ b/techlibs/common/cmp2lut.v
@@ -0,0 +1,105 @@ +// Certain arithmetic operations between a signal of width n and a constant can be directly mapped +// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process +// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often +// cannot be optimized further. +// +// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells +// with n <= k inputs should be techmapped in this way, because this shortens the critical path +// from n to 1 by avoiding carry chains. + +(* techmap_celltype = "$eq $ne $lt $le $gt $ge" *) +module _90_lut_cmp_ (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +parameter _TECHMAP_CELLTYPE_ = ""; + +parameter _TECHMAP_CONSTMSK_A_ = 0; +parameter _TECHMAP_CONSTVAL_A_ = 0; +parameter _TECHMAP_CONSTMSK_B_ = 0; +parameter _TECHMAP_CONSTVAL_B_ = 0; + +function automatic integer gen_lut; + input integer width; + input integer operation; + input integer swap; + input integer sign; + input integer operand; + integer n, i_var, i_cst, lhs, rhs, o_bit; + begin + gen_lut = width'b0; + for (n = 0; n < (1 << width); n++) begin + if (sign) + i_var = n[width-1:0]; + else + i_var = n; + i_cst = operand; + if (swap) begin + lhs = i_cst; + rhs = i_var; + end else begin + lhs = i_var; + rhs = i_cst; + end + if (operation == 0) + o_bit = (lhs < rhs); + if (operation == 1) + o_bit = (lhs <= rhs); + if (operation == 2) + o_bit = (lhs > rhs); + if (operation == 3) + o_bit = (lhs >= rhs); + if (operation == 4) + o_bit = (lhs == rhs); + if (operation == 5) + o_bit = (lhs != rhs); + gen_lut = gen_lut | (o_bit << n); + end + end +endfunction + +generate + if (_TECHMAP_CELLTYPE_ == "$lt") + localparam operation = 0; + if (_TECHMAP_CELLTYPE_ == "$le") + localparam operation = 1; + if (_TECHMAP_CELLTYPE_ == "$gt") + localparam operation = 2; + if (_TECHMAP_CELLTYPE_ == "$ge") + localparam operation = 3; + if (_TECHMAP_CELLTYPE_ == "$eq") + localparam operation = 4; + if (_TECHMAP_CELLTYPE_ == "$ne") + localparam operation = 5; + + if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) + wire _TECHMAP_FAIL_ = 1; + else if (&_TECHMAP_CONSTMSK_B_) + \$lut #( + .WIDTH(A_WIDTH), + .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) }) + ) _TECHMAP_REPLACE_ ( + .A(A), + .Y(Y) + ); + else if (&_TECHMAP_CONSTMSK_A_) + \$lut #( + .WIDTH(B_WIDTH), + .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) }) + ) _TECHMAP_REPLACE_ ( + .A(B), + .Y(Y) + ); + else + wire _TECHMAP_FAIL_ = 1; +endgenerate + +endmodule
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 897f37d..86fb4d6 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc
@@ -153,7 +153,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing PREP pass.\n"); log_push();
diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index efb2147..ccfa76e 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc
@@ -51,6 +51,9 @@ log(" -encfile <file>\n"); log(" passed to 'fsm_recode' via 'fsm'\n"); log("\n"); + log(" -lut <k>\n"); + log(" perform synthesis for a k-LUT architecture.\n"); + log("\n"); log(" -nofsm\n"); log(" do not run FSM optimization\n"); log("\n"); @@ -80,6 +83,7 @@ string top_module, fsm_opts, memory_opts; bool autotop, flatten, noalumacc, nofsm, noabc, noshare; + int lut; void clear_flags() YS_OVERRIDE { @@ -89,6 +93,7 @@ autotop = false; flatten = false; + lut = 0; noalumacc = false; nofsm = false; noabc = false; @@ -130,6 +135,10 @@ flatten = true; continue; } + if (args[argidx] == "-lut") { + lut = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-nofsm") { nofsm = true; continue; @@ -155,7 +164,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH pass.\n"); log_push(); @@ -186,19 +195,23 @@ { run("proc"); if (help_mode || flatten) - run("flatten", "(if -flatten)"); + run("flatten", " (if -flatten)"); run("opt_expr"); run("opt_clean"); run("check"); run("opt"); run("wreduce"); + if (help_mode) + run("techmap -map +/cmp2lut.v", " (if -lut)"); + else + run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut)); if (!noalumacc) - run("alumacc"); + run("alumacc", " (unless -noalumacc)"); if (!noshare) - run("share"); + run("share", " (unless -noshare)"); run("opt"); if (!nofsm) - run("fsm" + fsm_opts); + run("fsm" + fsm_opts, " (unless -nofsm)"); run("opt -fast"); run("memory -nomap" + memory_opts); run("opt_clean"); @@ -210,12 +223,33 @@ run("memory_map"); run("opt -full"); run("techmap"); + if (help_mode) + { + run("techmap -map +/gate2lut.v", "(if -noabc and -lut)"); + run("clean; opt_lut", " (if -noabc and -lut)"); + } + else if (noabc && lut) + { + run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut)); + run("clean; opt_lut"); + } run("opt -fast"); if (!noabc) { #ifdef YOSYS_ENABLE_ABC - run("abc -fast"); - run("opt -fast"); + if (help_mode) + { + run("abc -fast", " (unless -noabc, unless -lut)"); + run("abc -fast -lut k", "(unless -noabc, if -lut)"); + } + else + { + if (lut) + run(stringf("abc -fast -lut %d", lut)); + else + run("abc -fast"); + } + run("opt -fast", " (unless -noabc)"); #endif } }
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc index a5dac35..810380d 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cc +++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -111,7 +111,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n"); log_push();
diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc index b5ed93b..dd9e3da 100644 --- a/techlibs/easic/synth_easic.cc +++ b/techlibs/easic/synth_easic.cc
@@ -117,7 +117,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_EASIC pass.\n"); log_push();
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index b23d5c7..8df02be 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc
@@ -34,11 +34,11 @@ techlibs/ecp5/bram_conn_9.vh: techlibs/ecp5/brams_connect.mk techlibs/ecp5/bram_conn_18.vh: techlibs/ecp5/brams_connect.mk -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_init_1_2_4.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_init_9_18_36.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_1_2_4.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_9_18_36.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_conn_1.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_conn_2.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_conn_4.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_conn_9.vh)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram_conn_18.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_1.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_2.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_4.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_9.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_18.vh))
diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 057f9d7..425d62d 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v
@@ -484,7 +484,7 @@ parameter D_XGE_MODE = "0b0"; // These parameters don't do anything but are -// needed for compatability with Diamond +// needed for compatibility with Diamond parameter D_TX_MAX_RATE = "2.5"; parameter D_RX_MAX_RATE = "2.5"; parameter CH0_TXAMPLITUDE = "0d1300";
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 825e131..2e9176a 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc
@@ -189,7 +189,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_ECP5 pass.\n"); log_push();
diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index e3d924e..9700b38 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc
@@ -109,7 +109,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_GOWIN pass.\n"); log_push();
diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index b91d527..eeb001b 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc
@@ -120,7 +120,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); if (part != "SLG46140V" && part != "SLG46620V" && part != "SLG46621V") log_cmd_error("Invalid part name: '%s'\n", part.c_str());
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index c2aed87..f900453 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc
@@ -198,7 +198,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -226,7 +226,7 @@ if (check_label("coarse")) { - run("synth -run coarse"); + run("synth -lut 4 -run coarse"); } if (!nobram && check_label("bram", "(skip if -nobram)"))
diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v index 5ecdabc..fa27c2c 100644 --- a/techlibs/intel/cyclonev/cells_sim.v +++ b/techlibs/intel/cyclonev/cells_sim.v
@@ -54,7 +54,7 @@ // Internal variables // Sub mask for fragmented LUTs wire [15:0] mask_a, mask_b, mask_c, mask_d; - // Independant output for fragmented LUTs + // Independent output for fragmented LUTs wire output_0, output_1, output_2, output_3; // Extended mode uses mux to define the output wire mux_0, mux_1;
diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 2676ea6..62b3cd0 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc
@@ -118,7 +118,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_SF2 pass.\n"); log_push();
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b27c085..6c11d88 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc
@@ -178,7 +178,7 @@ extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); bool active = run_from.empty();
diff --git a/tests/lut/check_map.ys b/tests/lut/check_map.ys index dc0aaff..46854e8 100644 --- a/tests/lut/check_map.ys +++ b/tests/lut/check_map.ys
@@ -1,4 +1,6 @@ simplemap -equiv_opt -assert techmap -map +/gate2lut.v -D LUT_WIDTH=4 +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/cmp2lut.v design -load postopt -select -assert-count 1 t:$lut +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/gate2lut.v +design -load postopt +select -assert-count 0 t:* t:$lut %d
diff --git a/tests/lut/map_cmp.v b/tests/lut/map_cmp.v new file mode 100644 index 0000000..5e413f8 --- /dev/null +++ b/tests/lut/map_cmp.v
@@ -0,0 +1,29 @@ +module top(...); + input [3:0] a; + + output o1_1 = 4'b1010 <= a; + output o1_2 = 4'b1010 < a; + output o1_3 = 4'b1010 >= a; + output o1_4 = 4'b1010 > a; + output o1_5 = 4'b1010 == a; + output o1_6 = 4'b1010 != a; + + output o2_1 = a <= 4'b1010; + output o2_2 = a < 4'b1010; + output o2_3 = a >= 4'b1010; + output o2_4 = a > 4'b1010; + output o2_5 = a == 4'b1010; + output o2_6 = a != 4'b1010; + + output o3_1 = 4'sb0101 <= $signed(a); + output o3_2 = 4'sb0101 < $signed(a); + output o3_3 = 4'sb0101 >= $signed(a); + output o3_4 = 4'sb0101 > $signed(a); + output o3_5 = 4'sb0101 == $signed(a); + output o3_6 = 4'sb0101 != $signed(a); + + output o4_1 = $signed(a) <= 4'sb0000; + output o4_2 = $signed(a) < 4'sb0000; + output o4_3 = $signed(a) >= 4'sb0000; + output o4_4 = $signed(a) > 4'sb0000; +endmodule
diff --git a/tests/lut/run-test.sh b/tests/lut/run-test.sh old mode 100644 new mode 100755
diff --git a/tests/opt/opt_lut_elim.il b/tests/opt/opt_lut_elim.il new file mode 100644 index 0000000..75675d9 --- /dev/null +++ b/tests/opt/opt_lut_elim.il
@@ -0,0 +1,19 @@ +module \test + wire input 1 \i + + wire output 2 \o1 + cell $lut $1 + parameter \LUT 16'0110100110010110 + parameter \WIDTH 4 + connect \A { \i 3'000 } + connect \Y \o1 + end + + wire output 2 \o2 + cell $lut $2 + parameter \LUT 16'0110100010010110 + parameter \WIDTH 4 + connect \A { \i 3'000 } + connect \Y \o2 + end +end
diff --git a/tests/opt/opt_lut_elim.ys b/tests/opt/opt_lut_elim.ys new file mode 100644 index 0000000..8e5e23a --- /dev/null +++ b/tests/opt/opt_lut_elim.ys
@@ -0,0 +1,3 @@ +read_ilang opt_lut_elim.il +opt_lut +select -assert-count 0 t:$lut
diff --git a/tests/opt/opt_lut_port.ys b/tests/opt/opt_lut_port.ys index 51dfd98..3cb4ecb 100644 --- a/tests/opt/opt_lut_port.ys +++ b/tests/opt/opt_lut_port.ys
@@ -1,2 +1,3 @@ read_ilang opt_lut_port.il +opt_lut select -assert-count 2 t:$lut
diff --git a/tests/sva/basic01.sv b/tests/sva/basic01.sv index 74ab934..d5ad497 100644 --- a/tests/sva/basic01.sv +++ b/tests/sva/basic01.sv
@@ -6,7 +6,7 @@ write <= ctrl; ready <= write; end - + a_rw: assert property ( @(posedge clock) !(read && write) ); `ifdef FAIL a_wr: assert property ( @(posedge clock) write |-> ready );