diff options
Diffstat (limited to 'passes/techmap')
37 files changed, 2027 insertions, 723 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index a54b4913d..5a4d84f94 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -41,7 +41,9 @@ OBJS += passes/techmap/insbuf.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o +OBJS += passes/techmap/dfflegalize.o OBJS += passes/techmap/dff2dffs.o +OBJS += passes/techmap/dffunmap.o OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/extractinv.o endif diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index fae8b2426..ce50e9a5b 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -44,6 +44,7 @@ #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" +#include "kernel/ffinit.h" #include "kernel/cost.h" #include "kernel/log.h" #include <stdlib.h> @@ -111,7 +112,7 @@ SigMap assign_map; RTLIL::Module *module; std::vector<gate_t> signal_list; std::map<RTLIL::SigBit, int> signal_map; -std::map<RTLIL::SigBit, RTLIL::State> signal_init; +FfInitVals initvals; pool<std::string> enabled_gates; bool recover_init, cmos_cost; @@ -133,10 +134,7 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, gate.in4 = -1; gate.is_port = false; gate.bit = bit; - if (signal_init.count(bit)) - gate.init = signal_init.at(bit); - else - gate.init = State::Sx; + gate.init = initvals(bit); signal_list.push_back(gate); signal_map[bit] = gate.id; } @@ -1276,7 +1274,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin struct AbcPass : public Pass { AbcPass() : Pass("abc", "use ABC for technology mapping") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1460,7 +1458,7 @@ struct AbcPass : public Pass { log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); @@ -1468,7 +1466,7 @@ struct AbcPass : public Pass { assign_map.clear(); signal_list.clear(); signal_map.clear(); - signal_init.clear(); + initvals.clear(); pi_map.clear(); po_map.clear(); @@ -1854,24 +1852,7 @@ struct AbcPass : public Pass { } assign_map.set(mod); - signal_init.clear(); - - for (Wire *wire : mod->wires()) - if (wire->attributes.count(ID::init)) { - SigSpec initsig = assign_map(wire); - Const initval = wire->attributes.at(ID::init); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - switch (initval[i]) { - case State::S0: - signal_init[initsig[i]] = State::S0; - break; - case State::S1: - signal_init[initsig[i]] = State::S1; - break; - default: - break; - } - } + initvals.set(&assign_map, mod); if (!dff_mode || !clk_str.empty()) { abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, @@ -2028,7 +2009,7 @@ struct AbcPass : public Pass { assign_map.clear(); signal_list.clear(); signal_map.clear(); - signal_init.clear(); + initvals.clear(); pi_map.clear(); po_map.clear(); diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 06097a6f7..7d017ac40 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -36,7 +36,7 @@ PRIVATE_NAMESPACE_BEGIN struct Abc9Pass : public ScriptPass { Abc9Pass() : ScriptPass("abc9", "use ABC9 for technology mapping") { } - void on_register() YS_OVERRIDE + void on_register() override { RTLIL::constpad["abc9.script.default"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -v; &mfs"; RTLIL::constpad["abc9.script.default.area"] = "+&scorr; &sweep; &dc2; &dch -f; &ps; &if {C} {W} {D} {R} -a -v; &mfs"; @@ -81,7 +81,7 @@ struct Abc9Pass : public ScriptPass "&st; &if {C} -g -K 6; &synch2; &if {C} {W} {D} {R} -v; &save; &load;"\ "&mfs"; } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -184,7 +184,7 @@ struct Abc9Pass : public ScriptPass int maxlut; std::string box_file; - void clear_flags() YS_OVERRIDE + void clear_flags() override { exe_cmd.str(""); exe_cmd << "abc9_exe"; @@ -195,7 +195,7 @@ struct Abc9Pass : public ScriptPass box_file = ""; } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { std::string run_from, run_to; clear_flags(); @@ -272,7 +272,7 @@ struct Abc9Pass : public ScriptPass log_pop(); } - void script() YS_OVERRIDE + void script() override { if (check_label("check")) { if (help_mode) @@ -294,8 +294,8 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_map"); run("proc"); run("wbflip"); - run("techmap"); - run("opt"); + run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop"); + run("opt -nodffe -nosdff"); if (dff_mode || help_mode) { if (!help_mode) active_design->scratchpad_unset("abc9_ops.prep_dff_submod.did_something"); diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 0bf547921..7355840aa 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -293,7 +293,7 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe struct Abc9ExePass : public Pass { Abc9ExePass() : Pass("abc9_exe", "use ABC9 for technology mapping") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -375,7 +375,7 @@ struct Abc9ExePass : public Pass { log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ABC9_EXE pass (technology mapping using ABC9).\n"); diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 873c37b9a..98d0207c4 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -741,7 +741,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) if (ys_debug(1)) toposort.analyze_loops = true; - bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + bool no_loops = toposort.sort(); if (ys_debug(1)) { unsigned i = 0; @@ -1453,7 +1453,7 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) for (auto driver_cell : bit_drivers.at(it.first)) for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); - bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + bool no_loops = toposort.sort(); log_assert(no_loops); for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { @@ -1530,7 +1530,7 @@ clone_lut: struct Abc9OpsPass : public Pass { Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1614,7 +1614,7 @@ struct Abc9OpsPass : public Pass { log(" inputs and outputs.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc index 2ecb2f35a..ce151c7f3 100644 --- a/passes/techmap/aigmap.cc +++ b/passes/techmap/aigmap.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct AigmapPass : public Pass { AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -43,7 +43,7 @@ struct AigmapPass : public Pass { log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { bool nand_mode = false, select_mode = false; diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 1925145d3..b16e9750e 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -550,7 +550,7 @@ struct AlumaccWorker struct AlumaccPass : public Pass { AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -560,7 +560,7 @@ struct AlumaccPass : public Pass { log("and $macc cells.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n"); diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index 5f30817d4..8643543c8 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -81,7 +81,7 @@ struct AttrmapAction { struct AttrmapTocase : AttrmapAction { string name; - bool apply(IdString &id, Const&) YS_OVERRIDE { + bool apply(IdString &id, Const&) override { if (match_name(name, id, true)) id = RTLIL::escape_id(name); return true; @@ -90,7 +90,7 @@ struct AttrmapTocase : AttrmapAction { struct AttrmapRename : AttrmapAction { string old_name, new_name; - bool apply(IdString &id, Const&) YS_OVERRIDE { + bool apply(IdString &id, Const&) override { if (match_name(old_name, id)) id = RTLIL::escape_id(new_name); return true; @@ -101,7 +101,7 @@ struct AttrmapMap : AttrmapAction { bool imap; string old_name, new_name; string old_value, new_value; - bool apply(IdString &id, Const &val) YS_OVERRIDE { + bool apply(IdString &id, Const &val) override { if (match_name(old_name, id) && match_value(old_value, val, true)) { id = RTLIL::escape_id(new_name); val = make_value(new_value); @@ -113,7 +113,7 @@ struct AttrmapMap : AttrmapAction { struct AttrmapRemove : AttrmapAction { bool has_value; string name, value; - bool apply(IdString &id, Const &val) YS_OVERRIDE { + bool apply(IdString &id, Const &val) override { return !(match_name(name, id) && (!has_value || match_value(value, val))); } }; @@ -221,7 +221,7 @@ bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &arg struct AttrmapPass : public Pass { AttrmapPass() : Pass("attrmap", "renaming attributes") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -241,7 +241,7 @@ struct AttrmapPass : public Pass { log(" -imap keep=\"false\" keep=0 -remove keep=0\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); @@ -301,7 +301,7 @@ struct AttrmapPass : public Pass { struct ParamapPass : public Pass { ParamapPass() : Pass("paramap", "renaming cell parameters") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -317,7 +317,7 @@ struct ParamapPass : public Pass { log(" paramap -tocase INIT t:LUT4\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n"); diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc index e59aa6518..b3202c587 100644 --- a/passes/techmap/attrmvcp.cc +++ b/passes/techmap/attrmvcp.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct AttrmvcpPass : public Pass { AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" attrmvcp [options] [selection]\n"); @@ -53,7 +53,7 @@ struct AttrmvcpPass : public Pass { log(" multiple times.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n"); diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 3f4b6aa66..1cbd12e3d 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * Copyright (C) 2019 Marcin KoĆcielnicki <mwk@0x04.net> + * Copyright (C) 2019 Marcelina KoĆcielnicka <mwk@0x04.net> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,33 +34,34 @@ void split_portname_pair(std::string &port1, std::string &port2) } struct ClkbufmapPass : public Pass { - ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } - void help() YS_OVERRIDE + ClkbufmapPass() : Pass("clkbufmap", "insert clock buffers on clock networks") { } + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" clkbufmap [options] [selection]\n"); log("\n"); - log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("Inserts clock buffers between nets connected to clock inputs and their drivers.\n"); log("\n"); log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); - log("attribute will be considered for global buffer insertion.\n"); + log("attribute will be considered for clock buffer insertion.\n"); log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); log("'none' or 'bufr' one would specify:\n"); log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); log("as the selection.\n"); log("\n"); log(" -buf <celltype> <portname_out>:<portname_in>\n"); - log(" Specifies the cell type to use for the global buffers\n"); + log(" Specifies the cell type to use for the clock buffers\n"); log(" and its port names. The first port will be connected to\n"); log(" the clock network sinks, and the second will be connected\n"); - log(" to the actual clock source. This option is required.\n"); + log(" to the actual clock source.\n"); log("\n"); log(" -inpad <celltype> <portname_out>:<portname_in>\n"); log(" If specified, a PAD cell of the given type is inserted on\n"); log(" clock nets that are also top module's inputs (in addition\n"); - log(" to the global buffer).\n"); + log(" to the clock buffer, if any).\n"); log("\n"); + log("At least one of -buf or -inpad should be specified.\n"); } void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) { @@ -76,9 +77,9 @@ struct ClkbufmapPass : public Pass { modules_processed.insert(module); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { - log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + log_header(design, "Executing CLKBUFMAP pass (inserting clock buffers).\n"); std::string buf_celltype, buf_portname, buf_portname2; std::string inpad_celltype, inpad_portname, inpad_portname2; @@ -109,8 +110,8 @@ struct ClkbufmapPass : public Pass { extra_args(args, argidx, design); } - if (buf_celltype.empty()) - log_error("The -buf option is required.\n"); + if (buf_celltype.empty() && inpad_celltype.empty()) + log_error("Either the -buf option or -inpad option is required.\n"); // Cell type, port name, bit index. pool<pair<IdString, pair<IdString, int>>> sink_ports; @@ -118,6 +119,16 @@ struct ClkbufmapPass : public Pass { dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_out; dict<pair<IdString, pair<IdString, int>>, pair<IdString, int>> inv_ports_in; + // If true, use both ther -buf and -inpad cell for input ports that are clocks. + bool buffer_inputs = true; + + Module *inpad_mod = design->module(RTLIL::escape_id(inpad_celltype)); + if (inpad_mod) { + Wire *buf_wire = inpad_mod->wire(RTLIL::escape_id(buf_portname)); + if (buf_wire && buf_wire->get_bool_attribute(ID::clkbuf_driver)) + buffer_inputs = false; + } + // Process submodules before module using them. std::vector<Module *> modules_sorted; pool<Module *> modules_processed; @@ -242,19 +253,30 @@ struct ClkbufmapPass : public Pass { // Clock network not yet buffered, driven by one of // our cells or a top-level input -- buffer it. - log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); - Wire *iwire = module->addWire(NEW_ID); - cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); - cell->setPort(RTLIL::escape_id(buf_portname2), iwire); - if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top)) { + Wire *iwire = nullptr; + RTLIL::Cell *cell = nullptr; + bool is_input = wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top); + if (!buf_celltype.empty() && (!is_input || buffer_inputs)) { + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + } + if (is_input) { log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); - cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + if (iwire) { + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + } else { + cell2->setPort(RTLIL::escape_id(inpad_portname), mapped_wire_bit); + cell = cell2; + } iwire = module->addWire(NEW_ID); cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); } - buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + if (iwire) + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); if (wire->port_input) { input_bits.insert(i); diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc index a7dce9c81..9a23cb90e 100644 --- a/passes/techmap/deminout.cc +++ b/passes/techmap/deminout.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct DeminoutPass : public Pass { DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" deminout [options] [selection]\n"); @@ -33,7 +33,7 @@ struct DeminoutPass : public Pass { log("\"Demote\" inout ports to input or output ports, if possible.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n"); diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc index aa9bbfe17..62ee3fea6 100644 --- a/passes/techmap/dff2dffe.cc +++ b/passes/techmap/dff2dffe.cc @@ -253,7 +253,7 @@ struct Dff2dffeWorker struct Dff2dffePass : public Pass { Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -282,13 +282,13 @@ struct Dff2dffePass : public Pass { log("\n"); log(" -direct-match <pattern>\n"); log(" like -direct for all DFF cell types matching the expression.\n"); - log(" this will use $__DFFE_* as <external_gate_type> matching the\n"); - log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n"); - log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n"); + log(" this will use $_DFFE_* as <external_gate_type> matching the\n"); + log(" internal gate type $_DFF_*_, and $_SDFFE_* for those matching\n"); + log(" $_SDFF_*_, except for $_DFF_[NP]_, which is converted to \n"); log(" $_DFFE_[NP]_.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); @@ -318,23 +318,23 @@ struct Dff2dffePass : public Pass { const char *pattern = args[++argidx].c_str(); if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict[ID($_DFF_P_) ] = ID($_DFFE_PP_); if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict[ID($_DFF_N_) ] = ID($_DFFE_NP_); - if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($__DFFE_NN0); - if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($__DFFE_NN1); - if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($__DFFE_NP0); - if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($__DFFE_NP1); - if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($__DFFE_PN0); - if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($__DFFE_PN1); - if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($__DFFE_PP0); - if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($__DFFE_PP1); - - if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict[ID($__DFFS_NN0_)] = ID($__DFFSE_NN0); - if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict[ID($__DFFS_NN1_)] = ID($__DFFSE_NN1); - if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict[ID($__DFFS_NP0_)] = ID($__DFFSE_NP0); - if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict[ID($__DFFS_NP1_)] = ID($__DFFSE_NP1); - if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict[ID($__DFFS_PN0_)] = ID($__DFFSE_PN0); - if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict[ID($__DFFS_PN1_)] = ID($__DFFSE_PN1); - if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict[ID($__DFFS_PP0_)] = ID($__DFFSE_PP0); - if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict[ID($__DFFS_PP1_)] = ID($__DFFSE_PP1); + if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($_DFFE_NN0P_); + if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($_DFFE_NN1P_); + if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($_DFFE_NP0P_); + if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($_DFFE_NP1P_); + if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($_DFFE_PN0P_); + if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($_DFFE_PN1P_); + if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($_DFFE_PP0P_); + if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($_DFFE_PP1P_); + + if (patmatch(pattern, "$_SDFF_NN0_")) found_match = true, direct_dict[ID($_SDFF_NN0_)] = ID($_SDFFE_NN0P_); + if (patmatch(pattern, "$_SDFF_NN1_")) found_match = true, direct_dict[ID($_SDFF_NN1_)] = ID($_SDFFE_NN1P_); + if (patmatch(pattern, "$_SDFF_NP0_")) found_match = true, direct_dict[ID($_SDFF_NP0_)] = ID($_SDFFE_NP0P_); + if (patmatch(pattern, "$_SDFF_NP1_")) found_match = true, direct_dict[ID($_SDFF_NP1_)] = ID($_SDFFE_NP1P_); + if (patmatch(pattern, "$_SDFF_PN0_")) found_match = true, direct_dict[ID($_SDFF_PN0_)] = ID($_SDFFE_PN0P_); + if (patmatch(pattern, "$_SDFF_PN1_")) found_match = true, direct_dict[ID($_SDFF_PN1_)] = ID($_SDFFE_PN1P_); + if (patmatch(pattern, "$_SDFF_PP0_")) found_match = true, direct_dict[ID($_SDFF_PP0_)] = ID($_SDFFE_PP0P_); + if (patmatch(pattern, "$_SDFF_PP1_")) found_match = true, direct_dict[ID($_SDFF_PP1_)] = ID($_SDFFE_PP1P_); if (!found_match) log_cmd_error("No cell types matched pattern '%s'.\n", pattern); continue; diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc index c155297d9..6c2cca4bc 100644 --- a/passes/techmap/dff2dffs.cc +++ b/passes/techmap/dff2dffs.cc @@ -26,12 +26,12 @@ PRIVATE_NAMESPACE_BEGIN struct Dff2dffsPass : public Pass { Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" dff2dffs [options] [selection]\n"); log("\n"); - log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n"); + log("Merge synchronous set/reset $_MUX_ cells to create $_SDFF_[NP][NP][01]_, to be run before\n"); log("dff2dffe for SR over CE priority.\n"); log("\n"); log(" -match-init\n"); @@ -39,7 +39,7 @@ struct Dff2dffsPass : public Pass { log(" output wire's init attribute (if any).\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n"); @@ -138,21 +138,21 @@ struct Dff2dffsPass : public Pass { if (sr_val == State::S1) { if (cell->type == ID($_DFF_N_)) { - if (invert_sr) cell->type = ID($__DFFS_NN1_); - else cell->type = ID($__DFFS_NP1_); + if (invert_sr) cell->type = ID($_SDFF_NN1_); + else cell->type = ID($_SDFF_NP1_); } else { log_assert(cell->type == ID($_DFF_P_)); - if (invert_sr) cell->type = ID($__DFFS_PN1_); - else cell->type = ID($__DFFS_PP1_); + if (invert_sr) cell->type = ID($_SDFF_PN1_); + else cell->type = ID($_SDFF_PP1_); } } else { if (cell->type == ID($_DFF_N_)) { - if (invert_sr) cell->type = ID($__DFFS_NN0_); - else cell->type = ID($__DFFS_NP0_); + if (invert_sr) cell->type = ID($_SDFF_NN0_); + else cell->type = ID($_SDFF_NP0_); } else { log_assert(cell->type == ID($_DFF_P_)); - if (invert_sr) cell->type = ID($__DFFS_PN0_); - else cell->type = ID($__DFFS_PP0_); + if (invert_sr) cell->type = ID($_SDFF_PN0_); + else cell->type = ID($_SDFF_PP0_); } } cell->setPort(ID::R, sr_sig); diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 35645582b..44af043db 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -19,13 +19,14 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct DffinitPass : public Pass { DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -54,7 +55,7 @@ struct DffinitPass : public Pass { log(" the already defined initial value.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n"); @@ -94,29 +95,10 @@ struct DffinitPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); - dict<SigBit, State> init_bits; - pool<SigBit> cleanup_bits; - pool<SigBit> used_bits; - - for (auto wire : module->selected_wires()) { - if (wire->attributes.count(ID::init)) { - Const value = wire->attributes.at(ID::init); - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - if (value[i] != State::Sx) - init_bits[sigmap(SigBit(wire, i))] = value[i]; - } - if (wire->port_output) - for (auto bit : sigmap(wire)) - used_bits.insert(bit); - } + FfInitVals initvals(&sigmap, module); for (auto cell : module->selected_cells()) { - for (auto it : cell->connections()) - if (!cell->known() || cell->input(it.first)) - for (auto bit : sigmap(it.second)) - used_bits.insert(bit); - if (ff_types.count(cell->type) == 0) continue; @@ -131,17 +113,18 @@ struct DffinitPass : public Pass { if (cell->hasParam(it.second)) value = cell->getParam(it.second); + Const initval = initvals(sig); + initvals.remove_init(sig); for (int i = 0; i < GetSize(sig); i++) { - if (init_bits.count(sig[i]) == 0) + if (initval[i] == State::Sx) 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])) + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != initval[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]); + value.bits[i] = initval[i]; } if (highlow_mode && GetSize(value) != 0) { @@ -161,23 +144,6 @@ struct DffinitPass : public Pass { } } } - - for (auto wire : module->selected_wires()) - if (wire->attributes.count(ID::init)) { - Const &value = wire->attributes.at(ID::init); - bool do_cleanup = true; - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { - SigBit bit = sigmap(SigBit(wire, i)); - if (cleanup_bits.count(bit) || !used_bits.count(bit)) - value[i] = State::Sx; - else if (value[i] != State::Sx) - do_cleanup = false; - } - if (do_cleanup) { - log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase(ID::init); - } - } } } } DffinitPass; diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc new file mode 100644 index 000000000..8ad65493f --- /dev/null +++ b/passes/techmap/dfflegalize.cc @@ -0,0 +1,1319 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina KoĆcielnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/ffinit.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +enum FfType { + FF_DFF, + FF_DFFE, + FF_ADFF0, + FF_ADFF1, + FF_ADFFE0, + FF_ADFFE1, + FF_DFFSR, + FF_DFFSRE, + FF_SDFF0, + FF_SDFF1, + FF_SDFFE0, + FF_SDFFE1, + FF_SDFFCE0, + FF_SDFFCE1, + FF_SR, + FF_DLATCH, + FF_ADLATCH0, + FF_ADLATCH1, + FF_DLATCHSR, + NUM_FFTYPES, +}; + +enum FfNeg { + NEG_R = 0x1, + NEG_S = 0x2, + NEG_E = 0x4, + NEG_C = 0x8, + NUM_NEG = 0x10, +}; + +enum FfInit { + INIT_X = 0x1, + INIT_0 = 0x2, + INIT_1 = 0x4, +}; + +struct DffLegalizePass : public Pass { + DffLegalizePass() : Pass("dfflegalize", "convert FFs to types supported by the target") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dfflegalize [options] [selection]\n"); + log("\n"); + log("Converts FFs to types supported by the target.\n"); + log("\n"); + log(" -cell <cell_type_pattern> <init_values>\n"); + log(" specifies a supported group of FF cells. <cell_type_pattern>\n"); + log(" is a yosys internal fine cell name, where ? characters can be\n"); + log(" as a wildcard matching any character. <init_values> specifies\n"); + log(" which initialization values these FF cells can support, and can\n"); + log(" be one of:\n"); + log("\n"); + log(" - x (no init value supported)\n"); + log(" - 0\n"); + log(" - 1\n"); + log(" - r (init value has to match reset value, only for some FF types)\n"); + log(" - 01 (both 0 and 1 supported).\n"); + log("\n"); + log(" -mince <num>\n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" clock enable signal. If a clock enable signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log(" -minsrst <num>\n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" sync set/reset signal. If a sync set/reset signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log("The following cells are supported by this pass (ie. will be ingested,\n"); + log("and can be specified as allowed targets):\n"); + log("\n"); + log("- $_DFF_[NP]_\n"); + log("- $_DFFE_[NP][NP]_\n"); + log("- $_DFF_[NP][NP][01]_\n"); + log("- $_DFFE_[NP][NP][01][NP]_\n"); + log("- $_DFFSR_[NP][NP][NP]_\n"); + log("- $_DFFSRE_[NP][NP][NP][NP]_\n"); + log("- $_SDFF_[NP][NP][01]_\n"); + log("- $_SDFFE_[NP][NP][01][NP]_\n"); + log("- $_SDFFCE_[NP][NP][01][NP]_\n"); + log("- $_SR_[NP][NP]_\n"); + log("- $_DLATCH_[NP]_\n"); + log("- $_DLATCH_[NP][NP][01]_\n"); + log("- $_DLATCHSR_[NP][NP][NP]_\n"); + log("\n"); + log("The following transformations are performed by this pass:"); + log("\n"); + log("- upconversion from a less capable cell to a more capable cell, if the less"); + log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)"); + log("\n"); + log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)"); + log("\n"); + log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)"); + log("\n"); + log("- adding inverters on the control pins (due to unsupported polarity)"); + log("\n"); + log("- adding inverters on the D and Q pins and inverting the init/reset values\n"); + log(" (due to unsupported init or reset value)"); + log("\n"); + log("- converting sr into adlatch (by tying D to 1 and using E as set input)"); + log("\n"); + log("- emulating unsupported dffsr cell by adff + adff + sr + mux"); + log("\n"); + log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux"); + log("\n"); + log("- emulating adff when the (reset, init) value combination is unsupported by\n"); + log(" dff + adff + dlatch + mux"); + log("\n"); + log("- emulating adlatch when the (reset, init) value combination is unsupported by\n"); + log("- dlatch + adlatch + dlatch + mux"); + log("\n"); + log("If the pass is unable to realize a given cell type (eg. adff when only plain dff"); + log("is available), an error is raised."); + } + + // Table of all supported cell types. + // First index in the array is one of the FF_* values, second + // index is the set of negative-polarity inputs (OR of NEG_* + // values), and the value is the set of supported init values + // (OR of INIT_* values). + int supported_cells_neg[NUM_FFTYPES][NUM_NEG]; + // Aggregated table ignoring signal polarity. + int supported_cells[NUM_FFTYPES]; + // Aggregated for all *dff* cells. + int supported_dff; + // Aggregated for all dffsr* cells. + int supported_dffsr; + // Aggregated for all adff* cells. + int supported_adff0; + int supported_adff1; + // Aggregated for all sdff* cells. + int supported_sdff0; + int supported_sdff1; + // Aggregated for all ways to obtain a SR latch. + int supported_sr; + // Aggregated for all *dlatch* cells. + int supported_dlatch; + + int mince; + int minsrst; + + dict<SigBit, int> ce_used; + dict<SigBit, int> srst_used; + + SigMap sigmap; + FfInitVals initvals; + + int flip_initmask(int mask) { + int res = mask & INIT_X; + if (mask & INIT_0) + res |= INIT_1; + if (mask & INIT_1) + res |= INIT_0; + return res; + } + + void handle_ff(Cell *cell) { + std::string type_str = cell->type.str(); + + FfType ff_type; + int ff_neg = 0; + SigSpec sig_d; + SigSpec sig_q; + SigSpec sig_c; + SigSpec sig_e; + SigSpec sig_r; + SigSpec sig_s; + bool has_srst = false; + + if (cell->hasPort(ID::D)) + sig_d = cell->getPort(ID::D); + if (cell->hasPort(ID::Q)) + sig_q = cell->getPort(ID::Q); + if (cell->hasPort(ID::C)) + sig_c = cell->getPort(ID::C); + if (cell->hasPort(ID::E)) + sig_e = cell->getPort(ID::E); + if (cell->hasPort(ID::R)) + sig_r = cell->getPort(ID::R); + if (cell->hasPort(ID::S)) + sig_s = cell->getPort(ID::S); + + if (type_str.substr(0, 5) == "$_SR_") { + ff_type = FF_SR; + if (type_str[5] == 'N') + ff_neg |= NEG_S; + if (type_str[6] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) { + ff_type = FF_DFF; + if (type_str[6] == 'N') + ff_neg |= NEG_C; + } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) { + ff_type = FF_DFFE; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) { + ff_type = type_str[8] == '1' ? FF_ADFF1 : FF_ADFF0; + if (type_str[6] == 'N') + ff_neg |= NEG_C; + if (type_str[7] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) { + ff_type = type_str[9] == '1' ? FF_ADFFE1 : FF_ADFFE0; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_R; + if (type_str[10] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) { + ff_type = FF_DFFSR; + if (type_str[8] == 'N') + ff_neg |= NEG_C; + if (type_str[9] == 'N') + ff_neg |= NEG_S; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) { + ff_type = FF_DFFSRE; + if (type_str[9] == 'N') + ff_neg |= NEG_C; + if (type_str[10] == 'N') + ff_neg |= NEG_S; + if (type_str[11] == 'N') + ff_neg |= NEG_R; + if (type_str[12] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) { + ff_type = type_str[9] == '1' ? FF_SDFF1 : FF_SDFF0; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_R; + has_srst = true; + } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) { + ff_type = type_str[10] == '1' ? FF_SDFFE1 : FF_SDFFE0; + if (type_str[8] == 'N') + ff_neg |= NEG_C; + if (type_str[9] == 'N') + ff_neg |= NEG_R; + if (type_str[11] == 'N') + ff_neg |= NEG_E; + has_srst = true; + } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) { + ff_type = type_str[11] == '1' ? FF_SDFFCE1 : FF_SDFFCE0; + if (type_str[9] == 'N') + ff_neg |= NEG_C; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + if (type_str[12] == 'N') + ff_neg |= NEG_E; + has_srst = true; + } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) { + ff_type = FF_DLATCH; + if (type_str[9] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) { + ff_type = type_str[11] == '1' ? FF_ADLATCH1 : FF_ADLATCH0; + if (type_str[9] == 'N') + ff_neg |= NEG_E; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) { + ff_type = FF_DLATCHSR; + if (type_str[11] == 'N') + ff_neg |= NEG_E; + if (type_str[12] == 'N') + ff_neg |= NEG_S; + if (type_str[13] == 'N') + ff_neg |= NEG_R; + } else { + log_warning("Ignoring unknown ff type %s [%s.%s].\n", log_id(cell->type), log_id(cell->module->name), log_id(cell->name)); + return; + } + + State initval = initvals(sig_q[0]); + + FfInit initmask = INIT_X; + if (initval == State::S0) + initmask = INIT_0; + else if (initval == State::S1) + initmask = INIT_1; + const char *reason; + + bool kill_ce = mince && GetSize(sig_c) && GetSize(sig_e) && sig_e[0].wire && ce_used[sig_e[0]] < mince; + bool kill_srst = minsrst && has_srst && sig_r[0].wire && srst_used[sig_r[0]] < minsrst; + + while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) { + // Well, cell is not directly supported. Decide how to deal with it. + + if (ff_type == FF_DFF || ff_type == FF_DFFE) { + if (kill_ce) { + ff_type = FF_DFF; + goto unmap_enable; + } + if (!(supported_dff & initmask)) { + // This init value is not supported at all... + if (supported_dff & flip_initmask(initmask)) { + // The other one is, though. Negate D, Q, and init. +flip_dqi: + if (initval == State::S0) { + initval = State::S1; + initmask = INIT_1; + } else if (initval == State::S1) { + initval = State::S0; + initmask = INIT_0; + } + if (ff_type != FF_SR) + sig_d = cell->module->NotGate(NEW_ID, sig_d[0]); + SigBit new_q = SigSpec(cell->module->addWire(NEW_ID))[0]; + cell->module->addNotGate(NEW_ID, new_q, sig_q[0]); + initvals.remove_init(sig_q[0]); + initvals.set_init(new_q, initval); + sig_q = new_q; + continue; + } + if (!supported_dff) + reason = "dffs are not supported"; + else + reason = "initialized dffs are not supported"; + goto error; + } + + // Some DFF is supported with this init val. Just pick a type. + if (ff_type == FF_DFF) { + // Try adding a set or reset pin. + for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1}) + if (supported_cells[new_type] & initmask) { + ff_type = new_type; + sig_r = State::S0; + goto cell_ok; + } + // Try adding both. + if (supported_cells[FF_DFFSR] & initmask) { + ff_type = FF_DFFSR; + sig_r = State::S0; + sig_s = State::S0; + break; + } + // Nope. Will need to add enable and go the DFFE route. + sig_e = State::S1; + if (supported_cells[FF_DFFE] & initmask) { + ff_type = FF_DFFE; + break; + } + } + // Try adding a set or reset pin. + for (auto new_type: {FF_SDFFE0, FF_SDFFE1, FF_SDFFCE0, FF_SDFFCE1, FF_ADFFE0, FF_ADFFE1}) + if (supported_cells[new_type] & initmask) { + ff_type = new_type; + sig_r = State::S0; + goto cell_ok; + } + // Try adding both. + if (supported_cells[FF_DFFSRE] & initmask) { + ff_type = FF_DFFSRE; + sig_r = State::S0; + sig_s = State::S0; + break; + } + + // Seems that no DFFs with enable are supported. + // The enable input needs to be unmapped. + // This should not be reached if we started from plain DFF. + log_assert(ff_type == FF_DFFE); + ff_type = FF_DFF; +unmap_enable: + if (ff_neg & NEG_E) + sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], sig_q[0], sig_e[0]); + else + sig_d = cell->module->MuxGate(NEW_ID, sig_q[0], sig_d[0], sig_e[0]); + ff_neg &= ~NEG_E; + sig_e = SigSpec(); + kill_ce = false; + // Now try again as plain DFF. + continue; + } else if (ff_type == FF_ADFF0 || ff_type == FF_ADFF1 || ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1) { + bool has_set = ff_type == FF_ADFF1 || ff_type == FF_ADFFE1; + bool has_en = ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1; + if (kill_ce) { + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + if (!has_en && (supported_cells[has_set ? FF_ADFFE1 : FF_ADFFE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0; + break; + } + if (supported_dffsr & initmask) { + // Throw in a set/reset, retry in DFFSR/DFFSRE branch. + if (has_set) { + sig_s = sig_r; + sig_r = State::S0; + if (ff_neg & NEG_R) { + ff_neg &= ~NEG_R; + ff_neg |= NEG_S; + } + } else { + sig_s = State::S0; + } + if (has_en) + ff_type = FF_DFFSRE; + else + ff_type = FF_DFFSR; + continue; + } + if (has_en && (supported_cells[has_set ? FF_ADFF1 : FF_ADFF0] & initmask)) { + // Unmap enable. + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + log_assert(!((has_set ? supported_adff1 : supported_adff0) & initmask)); + // Alright, so this particular combination of initval and + // resetval is not natively supported. First, try flipping + // them both to see whether this helps. + int flipmask = flip_initmask(initmask); + if ((has_set ? supported_adff0 : supported_adff1) & flipmask) { + // Checks out, do it. + ff_type = has_en ? (has_set ? FF_ADFFE0 : FF_ADFFE1) : (has_set ? FF_ADFF0 : FF_ADFF1); + goto flip_dqi; + } + + if (!supported_adff0 && !supported_adff1) { + reason = "dffs with async set or reset are not supported"; + goto error; + } + if (!(supported_dff & ~INIT_X)) { + reason = "initialized dffs are not supported"; + goto error; + } + // If we got here, initialized dff is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adff + dff + dlatch + mux. + if (!(supported_dlatch & ~INIT_X)) { + reason = "unsupported initial value and async reset value combination"; + goto error; + } + + // If we have to unmap enable anyway, do it before breakdown. + if (has_en && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) { + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + + log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + initvals.remove_init(sig_q[0]); + Wire *adff_q = cell->module->addWire(NEW_ID); + Wire *dff_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + initvals.set_init(SigBit(dff_q, 0), initval); + initvals.set_init(SigBit(sel_q, 0), State::S0); + Cell *cell_dff; + Cell *cell_adff; + Cell *cell_sel; + if (!has_en) { + cell_dff = cell->module->addDffGate(NEW_ID, sig_c, sig_d, dff_q, !(ff_neg & NEG_C)); + cell_adff = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_R)); + } else { + cell_dff = cell->module->addDffeGate(NEW_ID, sig_c, sig_e, sig_d, dff_q, !(ff_neg & NEG_C), !(ff_neg & NEG_E)); + cell_adff = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + } + cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, dff_q, adff_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_dff); + handle_ff(cell_adff); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_DFFSR || ff_type == FF_DFFSRE) { + if (kill_ce) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + // First, see if mapping/unmapping enable will help. + if (supported_cells[FF_DFFSRE] & initmask) { + ff_type = FF_DFFSRE; + sig_e = State::S1; + break; + } + if (supported_cells[FF_DFFSR] & initmask) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + if (supported_dffsr & flip_initmask(initmask)) { +flip_dqisr:; + log_warning("Flipping D/Q/init and inserting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type)); + SigSpec new_r; + bool neg_r = (ff_neg & NEG_R); + bool neg_s = (ff_neg & NEG_S); + if (!(ff_neg & NEG_S)) { + if (!(ff_neg & NEG_R)) + new_r = cell->module->AndnotGate(NEW_ID, sig_s, sig_r); + else + new_r = cell->module->AndGate(NEW_ID, sig_s, sig_r); + } else { + if (!(ff_neg & NEG_R)) + new_r = cell->module->OrGate(NEW_ID, sig_s, sig_r); + else + new_r = cell->module->OrnotGate(NEW_ID, sig_s, sig_r); + } + ff_neg &= ~(NEG_R | NEG_S); + if (neg_r) + ff_neg |= NEG_S; + if (neg_s) + ff_neg |= NEG_R; + sig_s = sig_r; + sig_r = new_r; + goto flip_dqi; + } + // No native DFFSR. However, if we can conjure + // a SR latch and ADFF, it can still be emulated. + int flipmask = flip_initmask(initmask); + bool init0 = true; + bool init1 = true; + State initsel = State::Sx; + if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && ((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && supported_sr) { + // OK + } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_0)) { + init1 = false; + initsel = State::S0; + } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_1)) { + init0 = false; + initsel = State::S1; + } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_1)) { + init1 = false; + initsel = State::S0; + } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_0)) { + init0 = false; + initsel = State::S1; + } else { + if (!supported_dffsr) + reason = "dffs with async set and reset are not supported"; + else + reason = "initialized dffs with async set and reset are not supported"; + goto error; + } + + // If we have to unmap enable anyway, do it before breakdown. + if (ff_type == FF_DFFSRE && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + + log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + initvals.remove_init(sig_q[0]); + Wire *adff0_q = cell->module->addWire(NEW_ID); + Wire *adff1_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + if (init0) + initvals.set_init(SigBit(adff0_q, 0), initval); + if (init1) + initvals.set_init(SigBit(adff1_q, 0), initval); + initvals.set_init(SigBit(sel_q, 0), initsel); + Cell *cell_adff0; + Cell *cell_adff1; + Cell *cell_sel; + if (ff_type == FF_DFFSR) { + cell_adff0 = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_R)); + cell_adff1 = cell->module->addAdffGate(NEW_ID, sig_c, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_S)); + } else { + cell_adff0 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_adff1 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_S)); + } + cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, adff0_q, adff1_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_adff0); + handle_ff(cell_adff1); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_SR) { + if (supported_cells[FF_ADLATCH0] & initmask || supported_cells[FF_ADLATCH1] & flip_initmask(initmask)) { + // Convert to ADLATCH0. May get converted to ADLATCH1. + ff_type = FF_ADLATCH0; + sig_e = sig_s; + sig_d = State::S1; + if (ff_neg & NEG_S) { + ff_neg &= ~NEG_S; + ff_neg |= NEG_E; + } + continue; + } else if (supported_cells[FF_DLATCHSR] & initmask) { + // Upgrade to DLATCHSR. + ff_type = FF_DLATCHSR; + sig_e = State::S0; + sig_d = State::Sx; + break; + } else if (supported_dffsr & initmask) { + // Upgrade to DFFSR. May get further upgraded to DFFSRE. + ff_type = FF_DFFSR; + sig_c = State::S0; + sig_d = State::Sx; + continue; + } else if (supported_sr & flip_initmask(initmask)) { + goto flip_dqisr; + } else { + if (!supported_sr) + reason = "sr latches are not supported"; + else + reason = "initialized sr latches are not supported"; + goto error; + } + } else if (ff_type == FF_DLATCH) { + if (!(supported_dlatch & initmask)) { + // This init value is not supported at all... + if (supported_dlatch & flip_initmask(initmask)) + goto flip_dqi; + + if ((sig_d == State::S0 && (supported_adff0 & initmask)) || + (sig_d == State::S1 && (supported_adff1 & initmask)) || + (sig_d == State::S0 && (supported_adff1 & flip_initmask(initmask))) || + (sig_d == State::S1 && (supported_adff0 & flip_initmask(initmask))) + ) { + // Special case: const-D dlatch can be converted into adff with const clock. + ff_type = (sig_d == State::S0) ? FF_ADFF0 : FF_ADFF1; + if (ff_neg & NEG_E) { + ff_neg &= ~NEG_E; + ff_neg |= NEG_R; + } + sig_r = sig_e; + sig_d = State::Sx; + sig_c = State::S1; + continue; + } + + if (!supported_dlatch) + reason = "dlatch are not supported"; + else + reason = "initialized dlatch are not supported"; + goto error; + } + + // Some DLATCH is supported with this init val. Just pick a type. + if (supported_cells[FF_ADLATCH0] & initmask) { + ff_type = FF_ADLATCH0; + sig_r = State::S0; + break; + } + if (supported_cells[FF_ADLATCH1] & initmask) { + ff_type = FF_ADLATCH1; + sig_r = State::S0; + break; + } + if (supported_cells[FF_DLATCHSR] & initmask) { + ff_type = FF_DLATCHSR; + sig_r = State::S0; + sig_s = State::S0; + break; + } + log_assert(0); + } else if (ff_type == FF_ADLATCH0 || ff_type == FF_ADLATCH1) { + if (supported_cells[FF_DLATCHSR] & initmask) { + if (ff_type == FF_ADLATCH1) { + sig_s = sig_r; + sig_r = State::S0; + if (ff_neg & NEG_R) { + ff_neg &= ~NEG_R; + ff_neg |= NEG_S; + } + } else { + sig_s = State::S0; + } + ff_type = FF_DLATCHSR; + break; + } + FfType flip_type = ff_type == FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0; + if ((supported_cells[flip_type] | supported_cells[FF_DLATCHSR]) & flip_initmask(initmask)) { + ff_type = flip_type; + goto flip_dqi; + } + + if (!supported_cells[FF_ADLATCH0] && !supported_cells[FF_ADLATCH1] && !supported_cells[FF_DLATCHSR]) { + reason = "dlatch with async set or reset are not supported"; + goto error; + } + if (!(supported_dlatch & ~INIT_X)) { + reason = "initialized dlatch are not supported"; + goto error; + } + + if (!(supported_dlatch & ~INIT_X)) { + reason = "initialized dlatch are not supported"; + goto error; + } + // If we got here, initialized dlatch is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adff + dff + dlatch + mux. + + log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + initvals.remove_init(sig_q[0]); + Wire *adlatch_q = cell->module->addWire(NEW_ID); + Wire *dlatch_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + initvals.set_init(SigBit(dlatch_q, 0), initval); + initvals.set_init(SigBit(sel_q, 0), State::S0); + Cell *cell_dlatch; + Cell *cell_adlatch; + Cell *cell_sel; + cell_dlatch = cell->module->addDlatchGate(NEW_ID, sig_e, sig_d, dlatch_q, !(ff_neg & NEG_E)); + cell_adlatch = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch_q, ff_type == FF_ADLATCH1, !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, dlatch_q, adlatch_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_dlatch); + handle_ff(cell_adlatch); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_DLATCHSR) { + if (supported_cells[FF_DLATCHSR] & flip_initmask(initmask)) { + goto flip_dqisr; + } + // No native DFFSR. However, if we can conjure + // a SR latch and ADFF, it can still be emulated. + int flipmask = flip_initmask(initmask); + bool init0 = true; + bool init1 = true; + State initsel = State::Sx; + if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && ((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && supported_sr) { + // OK + } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_0)) { + init1 = false; + initsel = State::S0; + } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_1)) { + init0 = false; + initsel = State::S1; + } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_1)) { + init1 = false; + initsel = State::S0; + } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_0)) { + init0 = false; + initsel = State::S1; + } else { + if (!supported_cells[FF_DLATCHSR]) + reason = "dlatch with async set and reset are not supported"; + else + reason = "initialized dlatch with async set and reset are not supported"; + goto error; + } + + log_warning("Emulating async set + reset with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + initvals.remove_init(sig_q[0]); + Wire *adlatch0_q = cell->module->addWire(NEW_ID); + Wire *adlatch1_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + if (init0) + initvals.set_init(SigBit(adlatch0_q, 0), initval); + if (init1) + initvals.set_init(SigBit(adlatch1_q, 0), initval); + initvals.set_init(SigBit(sel_q, 0), initsel); + Cell *cell_adlatch0; + Cell *cell_adlatch1; + Cell *cell_sel; + cell_adlatch0 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch0_q, false, !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_adlatch1 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_s, sig_d, adlatch1_q, true, !(ff_neg & NEG_E), !(ff_neg & NEG_S)); + cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, adlatch0_q, adlatch1_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_adlatch0); + handle_ff(cell_adlatch1); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_SDFF0 || ff_type == FF_SDFF1 || ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1) { + bool has_set = ff_type == FF_SDFF1 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE1; + bool has_en = ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1; + bool has_ce = ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1; + + if (has_en) { + if (kill_ce || kill_srst) { + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } + } else if (has_ce) { + if (kill_ce || kill_srst) + goto unmap_srst; + } else { + log_assert(!kill_ce); + if (kill_srst) + goto unmap_srst; + } + + if (!has_ce) { + if (!has_en && (supported_cells[has_set ? FF_SDFFE1 : FF_SDFFE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0; + break; + } + if (!has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0; + break; + } + if (has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) { + // Convert sdffe to sdffce + if (!(ff_neg & NEG_E)) { + if (!(ff_neg & NEG_R)) + sig_e = cell->module->OrGate(NEW_ID, sig_e, sig_r); + else + sig_e = cell->module->OrnotGate(NEW_ID, sig_e, sig_r); + } else { + if (!(ff_neg & NEG_R)) + sig_e = cell->module->AndnotGate(NEW_ID, sig_e, sig_r); + else + sig_e = cell->module->AndGate(NEW_ID, sig_e, sig_r); + } + ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0; + break; + } + if (has_en && (supported_cells[has_set ? FF_SDFF1 : FF_SDFF0] & initmask)) { + // Unmap enable. + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } + log_assert(!((has_set ? supported_sdff1 : supported_sdff0) & initmask)); + } else { + if ((has_set ? supported_sdff1 : supported_sdff0) & initmask) { + // Convert sdffce to sdffe, which may be further converted to sdff. + if (!(ff_neg & NEG_R)) { + if (!(ff_neg & NEG_E)) + sig_r = cell->module->AndGate(NEW_ID, sig_r, sig_e); + else + sig_r = cell->module->AndnotGate(NEW_ID, sig_r, sig_e); + } else { + if (!(ff_neg & NEG_E)) + sig_r = cell->module->OrnotGate(NEW_ID, sig_r, sig_e); + else + sig_r = cell->module->OrGate(NEW_ID, sig_r, sig_e); + } + ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0; + continue; + } + } + // Alright, so this particular combination of initval and + // resetval is not natively supported. First, try flipping + // them both to see whether this helps. + if ((has_set ? supported_sdff0 : supported_sdff1) & flip_initmask(initmask)) { + // Checks out, do it. + ff_type = has_ce ? (has_set ? FF_SDFFCE0 : FF_SDFFCE1) : has_en ? (has_set ? FF_SDFFE0 : FF_SDFFE1) : (has_set ? FF_SDFF0 : FF_SDFF1); + goto flip_dqi; + } + + // Nope. No way to get SDFF* of the right kind, so unmap it. + // For SDFFE, the enable has to be unmapped first. + if (has_en) { + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } +unmap_srst: + if (has_ce) + ff_type = FF_DFFE; + else + ff_type = FF_DFF; + if (ff_neg & NEG_R) + sig_d = cell->module->MuxGate(NEW_ID, has_set ? State::S1 : State::S0, sig_d[0], sig_r[0]); + else + sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], has_set ? State::S1 : State::S0, sig_r[0]); + ff_neg &= ~NEG_R; + sig_r = SigSpec(); + kill_srst = false; + continue; + } else { + log_assert(0); + } + } +cell_ok: + + if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) { + // Cell is supported, but not with those polarities. + // Will need to add some inverters. + + // Find the smallest value that xored with the neg mask + // results in a supported one â this results in preferentially + // inverting resets before clocks, etc. + int xneg; + for (xneg = 0; xneg < NUM_NEG; xneg++) + if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask) + break; + log_assert(xneg < NUM_NEG); + if (xneg & NEG_R) + sig_r = cell->module->NotGate(NEW_ID, sig_r[0]); + if (xneg & NEG_S) + sig_s = cell->module->NotGate(NEW_ID, sig_s[0]); + if (xneg & NEG_E) + sig_e = cell->module->NotGate(NEW_ID, sig_e[0]); + if (xneg & NEG_C) + sig_c = cell->module->NotGate(NEW_ID, sig_c[0]); + ff_neg ^= xneg; + } + + cell->unsetPort(ID::D); + cell->unsetPort(ID::Q); + cell->unsetPort(ID::C); + cell->unsetPort(ID::E); + cell->unsetPort(ID::S); + cell->unsetPort(ID::R); + switch (ff_type) { + case FF_DFF: + cell->type = IdString(stringf("$_DFF_%c_", + (ff_neg & NEG_C) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + break; + case FF_DFFE: + cell->type = IdString(stringf("$_DFFE_%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + break; + case FF_ADFF0: + case FF_ADFF1: + cell->type = IdString(stringf("$_DFF_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADFF1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::R, sig_r); + break; + case FF_ADFFE0: + case FF_ADFFE1: + cell->type = IdString(stringf("$_DFFE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADFFE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DFFSR: + cell->type = IdString(stringf("$_DFFSR_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_DFFSRE: + cell->type = IdString(stringf("$_DFFSRE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFF0: + case FF_SDFF1: + cell->type = IdString(stringf("$_SDFF_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFF1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFFE0: + case FF_SDFFE1: + cell->type = IdString(stringf("$_SDFFE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFFE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFFCE0: + case FF_SDFFCE1: + cell->type = IdString(stringf("$_SDFFCE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFFCE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DLATCH: + cell->type = IdString(stringf("$_DLATCH_%c_", + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + break; + case FF_ADLATCH0: + case FF_ADLATCH1: + cell->type = IdString(stringf("$_DLATCH_%c%c%c_", + (ff_neg & NEG_E) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADLATCH1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DLATCHSR: + cell->type = IdString(stringf("$_DLATCHSR_%c%c%c_", + (ff_neg & NEG_E) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_SR: + cell->type = IdString(stringf("$_SR_%c%c_", + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + default: + log_assert(0); + } + return; + +error: + log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type), reason); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + + log_header(design, "Executing DFFLEGALIZE pass (convert FFs to types supported by the target).\n"); + + for (int i = 0; i < NUM_FFTYPES; i++) { + for (int j = 0; j < NUM_NEG; j++) + supported_cells_neg[i][j] = 0; + supported_cells[i] = 0; + } + mince = 0; + minsrst = 0; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-cell" && argidx + 2 < args.size()) { + std::string celltype = args[++argidx]; + std::string inittype = args[++argidx]; + enum FfType ff_type[2] = {NUM_FFTYPES, NUM_FFTYPES}; + char pol_c = 0; + char pol_e = 0; + char pol_s = 0; + char pol_r = 0; + char srval = 0; + if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type[0] = FF_SR; + pol_s = celltype[5]; + pol_r = celltype[6]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type[0] = FF_DFF; + pol_c = celltype[6]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type[0] = FF_DFFE; + pol_c = celltype[7]; + pol_e = celltype[8]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type[0] = FF_ADFF0; + ff_type[1] = FF_ADFF1; + pol_c = celltype[6]; + pol_r = celltype[7]; + srval = celltype[8]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type[0] = FF_ADFFE0; + ff_type[1] = FF_ADFFE1; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + pol_e = celltype[10]; + } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type[0] = FF_DFFSR; + pol_c = celltype[8]; + pol_s = celltype[9]; + pol_r = celltype[10]; + } else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type[0] = FF_DFFSRE; + pol_c = celltype[9]; + pol_s = celltype[10]; + pol_r = celltype[11]; + pol_e = celltype[12]; + } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type[0] = FF_SDFF0; + ff_type[1] = FF_SDFF1; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + } else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type[0] = FF_SDFFE0; + ff_type[1] = FF_SDFFE1; + pol_c = celltype[8]; + pol_r = celltype[9]; + srval = celltype[10]; + pol_e = celltype[11]; + } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type[0] = FF_SDFFCE0; + ff_type[1] = FF_SDFFCE1; + pol_c = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + pol_e = celltype[12]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type[0] = FF_DLATCH; + pol_e = celltype[9]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type[0] = FF_ADLATCH0; + ff_type[1] = FF_ADLATCH1; + pol_e = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') { + ff_type[0] = FF_DLATCHSR; + pol_e = celltype[11]; + pol_s = celltype[12]; + pol_r = celltype[13]; + } else { +unrecognized: + log_error("unrecognized cell type %s.\n", celltype.c_str()); + } + int mask = 0; + int match = 0; + for (auto pair : { + std::make_pair(pol_c, NEG_C), + std::make_pair(pol_e, NEG_E), + std::make_pair(pol_s, NEG_S), + std::make_pair(pol_r, NEG_R), + }) { + if (pair.first == 'N') { + mask |= pair.second; + match |= pair.second; + } else if (pair.first == 'P' || pair.first == 0) { + mask |= pair.second; + } else if (pair.first != '?') { + goto unrecognized; + } + } + if (srval == '0') { + ff_type[1] = NUM_FFTYPES; + } else if (srval == '1') { + ff_type[0] = NUM_FFTYPES; + } else if (srval != 0 && srval != '?') { + goto unrecognized; + } + for (int i = 0; i < 2; i++) { + if (ff_type[i] == NUM_FFTYPES) + continue; + int initmask; + if (inittype == "x") { + initmask = INIT_X; + } else if (inittype == "0") { + initmask = INIT_X | INIT_0; + } else if (inittype == "1") { + initmask = INIT_X | INIT_1; + } else if (inittype == "r") { + if (srval == 0) + log_error("init type r not valid for cell type %s.\n", celltype.c_str()); + if (i == 0) + initmask = INIT_X | INIT_0; + else + initmask = INIT_X | INIT_1; + } else if (inittype == "01") { + initmask = INIT_X | INIT_0 | INIT_1; + } else { + log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str()); + } + for (int neg = 0; neg < NUM_NEG; neg++) + if ((neg & mask) == match) + supported_cells_neg[ff_type[i]][neg] |= initmask; + supported_cells[ff_type[i]] |= initmask; + } + continue; + } else if (args[argidx] == "-mince" && argidx + 1 < args.size()) { + mince = atoi(args[++argidx].c_str()); + continue; + } else if (args[argidx] == "-minsrst" && argidx + 1 < args.size()) { + minsrst = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE]; + supported_adff0 = supported_cells[FF_ADFF0] | supported_cells[FF_ADFFE0] | supported_dffsr; + supported_adff1 = supported_cells[FF_ADFF1] | supported_cells[FF_ADFFE1] | supported_dffsr; + supported_sdff0 = supported_cells[FF_SDFF0] | supported_cells[FF_SDFFE0] | supported_cells[FF_SDFFCE0]; + supported_sdff1 = supported_cells[FF_SDFF1] | supported_cells[FF_SDFFE1] | supported_cells[FF_SDFFCE1]; + supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1; + supported_sr = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR] | supported_cells[FF_ADLATCH0] | flip_initmask(supported_cells[FF_ADLATCH1]); + supported_dlatch = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH0] | supported_cells[FF_ADLATCH1] | supported_cells[FF_DLATCHSR]; + + for (auto module : design->selected_modules()) + { + sigmap.set(module); + initvals.set(&sigmap, module); + + if (mince || minsrst) { + ce_used.clear(); + srst_used.clear(); + + for (auto cell : module->cells()) { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + if (cell->hasPort(ID::C) && cell->hasPort(ID::E)) { + SigSpec sig = cell->getPort(ID::E); + // Do not count const enable signals. + if (GetSize(sig) == 1 && sig[0].wire) + ce_used[sig[0]]++; + } + if (cell->type.str().substr(0, 6) == "$_SDFF") { + SigSpec sig = cell->getPort(ID::R); + // Do not count const srst signals. + if (GetSize(sig) == 1 && sig[0].wire) + srst_used[sig[0]]++; + } + } + } + + // First gather FF cells, then iterate over them later. + // We may need to split an FF into several cells. + std::vector<Cell *> ff_cells; + + for (auto cell : module->selected_cells()) + { + // Early exit for non-FFs. + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + ff_cells.push_back(cell); + } + + for (auto cell: ff_cells) + handle_ff(cell); + } + + sigmap.clear(); + initvals.clear(); + ce_used.clear(); + srst_used.clear(); + } +} DffLegalizePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index aa344cf8a..78a6f1c0d 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, return false; } -static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) +static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) { LibertyAst *best_cell = nullptr; std::map<std::string, char> best_cell_ports; @@ -222,21 +222,12 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - if (has_reset) - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) +static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol) { LibertyAst *best_cell = nullptr; std::map<std::string, char> best_cell_ports; @@ -339,141 +330,12 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - cell_mappings[cell_type].ports["S"] = 'S'; - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static bool expand_cellmap_worker(std::string from, std::string to, std::string inv) -{ - if (cell_mappings.count(to) > 0) - return false; - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - char cmp_ch = it.second; - if ('a' <= cmp_ch && cmp_ch <= 'z') - cmp_ch -= 'a' - 'A'; - if (inv.find(cmp_ch) == std::string::npos) - continue; - if ('a' <= it.second && it.second <= 'z') - it.second -= 'a' - 'A'; - else if ('A' <= it.second && it.second <= 'Z') - it.second += 'a' - 'A'; - } - return true; -} - -static bool expand_cellmap(std::string pattern, std::string inv) -{ - std::vector<std::pair<std::string, std::string>> from_to_list; - bool return_status = false; - - for (auto &it : cell_mappings) { - std::string from = it.first.str(), to = it.first.str(); - if (from.size() != pattern.size()) - continue; - for (size_t i = 0; i < from.size(); i++) { - if (pattern[i] == '*') { - to[i] = from[i] == 'P' ? 'N' : - from[i] == 'N' ? 'P' : - from[i] == '1' ? '0' : - from[i] == '0' ? '1' : '*'; - } else - if (pattern[i] != '?' && pattern[i] != from[i]) - goto pattern_failed; - } - from_to_list.push_back(std::pair<std::string, std::string>(from, to)); - pattern_failed:; - } - - for (auto &it : from_to_list) - return_status = return_status || expand_cellmap_worker(it.first, it.second, inv); - return return_status; -} - -static void map_sr_to_arst(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol YS_ATTRIBUTE(unused) = from[8]; - char from_set_pol = from[9]; - char from_clr_pol = from[10]; - char to_clk_pol YS_ATTRIBUTE(unused) = to[6]; - char to_rst_pol YS_ATTRIBUTE(unused) = to[7]; - char to_rst_val = to[8]; - - log_assert(from_clk_pol == to_clk_pol); - log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) - { - bool is_set_pin = it.second == 'S' || it.second == 's'; - bool is_clr_pin = it.second == 'R' || it.second == 'r'; - - if (!is_set_pin && !is_clr_pin) - continue; - - if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin)) - { - // this is the unused set/clr pin -- deactivate it - if (is_set_pin) - it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1'; - else - it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1'; - } - else - { - // this is the used set/clr pin -- rename it to 'reset' - if (it.second == 'S') - it.second = 'R'; - if (it.second == 's') - it.second = 'r'; - } - } -} - -static void map_adff_to_dff(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol YS_ATTRIBUTE(unused) = from[6]; - char from_rst_pol = from[7]; - char to_clk_pol YS_ATTRIBUTE(unused) = to[6]; - - log_assert(from_clk_pol == to_clk_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - if (it.second == 'S' || it.second == 'R') - it.second = from_rst_pol == 'P' ? '0' : '1'; - if (it.second == 's' || it.second == 'r') - it.second = from_rst_pol == 'P' ? '1' : '0'; - } -} - -static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode) +static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) { log("Mapping DFF cells in module `%s':\n", module->name.c_str()); @@ -499,7 +361,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare module->remove(cell); cell_mapping &cm = cell_mappings[cell_type]; - RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name); + RTLIL::Cell *new_cell = module->addCell(cell_name, cm.cell_name); new_cell->set_src_attribute(src); @@ -549,10 +411,10 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare struct DfflibmapPass : public Pass { DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { } - void help() YS_OVERRIDE + void help() override { log("\n"); - log(" dfflibmap [-prepare] -liberty <file> [selection]\n"); + log(" dfflibmap [-prepare] [-map-only] [-info] -liberty <file> [selection]\n"); log("\n"); log("Map internal flip-flop cells to the flip-flop cells in the technology\n"); log("library specified in the given liberty file.\n"); @@ -562,15 +424,27 @@ struct DfflibmapPass : public Pass { log("\n"); log("When called with -prepare, this command will convert the internal FF cells\n"); log("to the internal cell types that best match the cells found in the given\n"); - log("liberty file.\n"); + log("liberty file, but won't actually map them to the target cells.\n"); + log("\n"); + log("When called with -map-only, this command will only map internal cell\n"); + log("types that are already of exactly the right type to match the target\n"); + log("cells, leaving remaining internal cells untouched.\n"); + log("\n"); + log("When called with -info, this command will only print the target cell\n"); + log("list, along with their associated internal cell types, and the arguments"); + log("that would be passed to the dfflegalize pass. The design will not be\n"); + log("changed.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); + log_push(); std::string liberty_file; bool prepare_mode = false; + bool map_only_mode = false; + bool info_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -585,10 +459,28 @@ struct DfflibmapPass : public Pass { prepare_mode = true; continue; } + if (arg == "-map-only") { + map_only_mode = true; + continue; + } + if (arg == "-info") { + info_mode = true; + continue; + } break; } extra_args(args, argidx, design); + int modes = 0; + if (prepare_mode) + modes++; + if (map_only_mode) + modes++; + if (info_mode) + modes++; + if (modes > 1) + log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n"); + if (liberty_file.empty()) log_cmd_error("Missing `-liberty liberty_file' option!\n"); @@ -599,74 +491,49 @@ struct DfflibmapPass : public Pass { LibertyParser libparser(f); f.close(); - find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode); - - find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); - - find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); - - // try to implement as many cells as possible just by inverting - // the SET and RESET pins. If necessary, implement cell types - // by inverting both D and Q. Only invert clock pins if there - // is no other way of implementing the cell. - while (1) - { - if (expand_cellmap("$_DFF_?*?_", "R") || - expand_cellmap("$_DFFSR_?*?_", "S") || - expand_cellmap("$_DFFSR_??*_", "R")) - continue; - - if (expand_cellmap("$_DFF_??*_", "DQ")) - continue; - - if (expand_cellmap("$_DFF_*_", "C") || - expand_cellmap("$_DFF_*??_", "C") || - expand_cellmap("$_DFFSR_*??_", "C")) - continue; - - break; - } - - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_)); - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_)); - - map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_)); + find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false); + find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false); + + find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false); + find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true); + find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false); + find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true); + find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false); + find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true); + find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false); + find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true); + + find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true); log(" final dff cell mappings:\n"); logmap_all(); - for (auto module : design->selected_modules()) - if (!module->get_blackbox_attribute()) - dfflibmap(design, module, prepare_mode); + if (!map_only_mode) { + std::string dfflegalize_cmd = "dfflegalize"; + for (auto it : cell_mappings) + dfflegalize_cmd += stringf(" -cell %s 01", it.first.c_str()); + dfflegalize_cmd += " t:$_DFF* t:$_SDFF*"; + if (info_mode) { + log("dfflegalize command line: %s\n", dfflegalize_cmd.c_str()); + } else { + Pass::call(design, dfflegalize_cmd); + } + } + + if (!prepare_mode && !info_mode) { + for (auto module : design->selected_modules()) + if (!module->get_blackbox_attribute()) + dfflibmap(design, module); + } + log_pop(); cell_mappings.clear(); } } DfflibmapPass; diff --git a/passes/techmap/dffunmap.cc b/passes/techmap/dffunmap.cc new file mode 100644 index 000000000..fb107ff75 --- /dev/null +++ b/passes/techmap/dffunmap.cc @@ -0,0 +1,107 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina KoĆcielnicka <mwk@0x04.net> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/ff.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DffunmapPass : public Pass { + DffunmapPass() : Pass("dffunmap", "unmap clock enable and synchronous reset from FFs") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dffunmap [options] [selection]\n"); + log("\n"); + log("This pass transforms FF types with clock enable and/or synchronous reset into\n"); + log("their base type (with neither clock enable nor sync reset) by emulating the clock\n"); + log("enable and synchronous reset with multiplexers on the cell input.\n"); + log("\n"); + log(" -ce-only\n"); + log(" unmap only clock enables, leave synchronous resets alone.\n"); + log("\n"); + log(" -srst-only\n"); + log(" unmap only synchronous resets, leave clock enables alone.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) override + { + log_header(design, "Executing DFFUNMAP pass (unmap clock enable and synchronous reset from FFs).\n"); + + bool ce_only = false; + bool srst_only = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-ce-only") { + ce_only = true; + continue; + } + if (args[argidx] == "-srst-only") { + srst_only = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (ce_only && srst_only) + log_cmd_error("Options -ce-only and -srst-only are mutually exclusive!\n"); + + for (auto mod : design->selected_modules()) + { + SigMap sigmap(mod); + FfInitVals initvals(&sigmap, mod); + + for (auto cell : mod->selected_cells()) + { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + FfData ff(&initvals, cell); + IdString name = cell->name; + + if (!ff.has_clk) + continue; + + if (ce_only) { + if (!ff.has_en) + continue; + ff.unmap_ce(mod); + } else if (srst_only) { + if (!ff.has_srst) + continue; + ff.unmap_srst(mod); + } else { + if (!ff.has_en && !ff.has_srst) + continue; + ff.unmap_ce_srst(mod); + } + + mod->remove(cell); + ff.emit(mod, name); + } + } + } +} DffunmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index f29044790..7278cb680 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -345,7 +345,7 @@ bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right) struct ExtractPass : public Pass { ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -433,7 +433,7 @@ struct ExtractPass : public Pass { log("See 'help techmap' for a pass that does the opposite thing.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n"); log_push(); diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc index 68b338143..56b2ea584 100644 --- a/passes/techmap/extract_counter.cc +++ b/passes/techmap/extract_counter.cc @@ -760,7 +760,7 @@ void counter_worker( struct ExtractCounterPass : public Pass { ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -788,18 +788,18 @@ struct ExtractCounterPass : public Pass { log("\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n"); pool<RTLIL::IdString> _parallel_cells; CounterExtractionSettings settings { - .parallel_cells = _parallel_cells, - .maxwidth = 64, - .minwidth = 2, - .allow_arst = true, - .allowed_dirs = 0, + _parallel_cells, // parallel_cells + 64, // maxwidth + 2, // minwidth + true, // allow_arst + 0, // allowed_dirs }; size_t argidx; diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 9023d8687..3fcff01c3 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -539,7 +539,7 @@ struct ExtractFaWorker struct ExtractFaPass : public Pass { ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -561,7 +561,7 @@ struct ExtractFaPass : public Pass { log(" Verbose output\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { ExtractFaConfig config; diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc index 2d63e413f..07b4200cc 100644 --- a/passes/techmap/extract_reduce.cc +++ b/passes/techmap/extract_reduce.cc @@ -34,7 +34,7 @@ struct ExtractReducePass : public Pass ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -63,7 +63,7 @@ struct ExtractReducePass : public Pass (cell->type == ID($_XOR_) && gt == GateType::Xor); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing EXTRACT_REDUCE pass.\n"); log_push(); diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc index 269fe5c6c..11463380c 100644 --- a/passes/techmap/extractinv.cc +++ b/passes/techmap/extractinv.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> - * Copyright (C) 2019 Marcin KoĆcielnicki <mwk@0x04.net> + * Copyright (C) 2019 Marcelina KoĆcielnicka <mwk@0x04.net> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,7 +35,7 @@ void split_portname_pair(std::string &port1, std::string &port2) struct ExtractinvPass : public Pass { ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -57,7 +57,7 @@ struct ExtractinvPass : public Pass { log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n"); diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 027bb137d..b5f55cffa 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -28,24 +28,48 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void apply_prefix(IdString prefix, IdString &id) +IdString concat_name(RTLIL::Cell *cell, IdString object_name) { - if (id[0] == '\\') - id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); - else - id = stringf("$flatten%s.%s", prefix.c_str(), id.c_str()); + if (object_name[0] == '\\') + return stringf("%s.%s", cell->name.c_str(), object_name.c_str() + 1); + else { + std::string object_name_str = object_name.str(); + if (object_name_str.substr(0, 8) == "$flatten") + object_name_str.erase(0, 8); + return stringf("$flatten%s.%s", cell->name.c_str(), object_name_str.c_str()); + } +} + +template<class T> +IdString map_name(RTLIL::Cell *cell, T *object) +{ + return cell->module->uniquify(concat_name(cell, object->name)); +} + +template<class T> +void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name) +{ + if (object->has_attribute(ID::src)) + object->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + + // Preserve original names via the hdlname attribute, but only for objects with a fully public name. + if (cell->name[0] == '\\' && (object->has_attribute(ID::hdlname) || orig_object_name[0] == '\\')) { + std::vector<std::string> hierarchy; + if (object->has_attribute(ID::hdlname)) + hierarchy = object->get_hdlname_attribute(); + else + hierarchy.push_back(orig_object_name.str().substr(1)); + hierarchy.insert(hierarchy.begin(), cell->name.str().substr(1)); + object->set_hdlname_attribute(hierarchy); + } } -void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) +void map_sigspec(const dict<RTLIL::Wire*, RTLIL::Wire*> &map, RTLIL::SigSpec &sig, RTLIL::Module *into = nullptr) { vector<SigChunk> chunks = sig; for (auto &chunk : chunks) - if (chunk.wire != nullptr) { - IdString wire_name = chunk.wire->name; - apply_prefix(prefix, wire_name); - log_assert(module->wire(wire_name) != nullptr); - chunk.wire = module->wire(wire_name); - } + if (chunk.wire != nullptr && chunk.wire->module != into) + chunk.wire = map.at(chunk.wire); sig = chunks; } @@ -55,191 +79,143 @@ struct FlattenWorker void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, std::vector<RTLIL::Cell*> &new_cells) { - if (tpl->processes.size() != 0) { - log("Flattening yielded processes:"); - for (auto &it : tpl->processes) - log(" %s",log_id(it.first)); - log("\n"); - log_error("Flattening yielded processes -> this is not supported.\n"); - } - - pool<string> extra_src_attrs = cell->get_strpool_attribute(ID::src); - - dict<IdString, IdString> memory_renames; - - for (auto &it : tpl->memories) { - IdString m_name = it.first; - apply_prefix(cell->name, m_name); - RTLIL::Memory *m = module->addMemory(m_name, it.second); - if (m->attributes.count(ID::src)) - m->add_strpool_attribute(ID::src, extra_src_attrs); - memory_renames[it.first] = m->name; - design->select(module, m); + // Copy the contents of the flattened cell + + dict<IdString, IdString> memory_map; + for (auto &tpl_memory_it : tpl->memories) { + RTLIL::Memory *new_memory = module->addMemory(map_name(cell, tpl_memory_it.second), tpl_memory_it.second); + map_attributes(cell, new_memory, tpl_memory_it.second->name); + memory_map[tpl_memory_it.first] = new_memory->name; + design->select(module, new_memory); } + dict<RTLIL::Wire*, RTLIL::Wire*> wire_map; dict<IdString, IdString> positional_ports; - dict<Wire*, IdString> temp_renamed_wires; - - for (auto tpl_w : tpl->wires()) - { - if (tpl_w->port_id > 0) - { - IdString posportname = stringf("$%d", tpl_w->port_id); - positional_ports.emplace(posportname, tpl_w->name); - } - IdString w_name = tpl_w->name; - apply_prefix(cell->name, w_name); - RTLIL::Wire *w = module->wire(w_name); - if (w != nullptr) { - if (!w->get_bool_attribute(ID::hierconn)) { - temp_renamed_wires[w] = w->name; - module->rename(w, NEW_ID); - w = nullptr; - } else { - w->attributes.erase(ID::hierconn); - if (GetSize(w) < GetSize(tpl_w)) { - log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), - log_id(tpl), log_id(tpl_w), log_id(module), log_id(cell)); - w->width = GetSize(tpl_w); + for (auto tpl_wire : tpl->wires()) { + if (tpl_wire->port_id > 0) + positional_ports.emplace(stringf("$%d", tpl_wire->port_id), tpl_wire->name); + + RTLIL::Wire *new_wire = nullptr; + if (tpl_wire->name[0] == '\\') { + RTLIL::Wire *hier_wire = module->wire(concat_name(cell, tpl_wire->name)); + if (hier_wire != nullptr && hier_wire->get_bool_attribute(ID::hierconn)) { + hier_wire->attributes.erase(ID::hierconn); + if (GetSize(hier_wire) < GetSize(tpl_wire)) { + log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", + log_id(module), log_id(hier_wire), log_id(tpl), log_id(tpl_wire), log_id(module), log_id(cell)); + hier_wire->width = GetSize(tpl_wire); } + new_wire = hier_wire; } } - if (w == nullptr) { - w = module->addWire(w_name, tpl_w); - w->port_input = false; - w->port_output = false; - w->port_id = 0; - if (w->attributes.count(ID::src)) - w->add_strpool_attribute(ID::src, extra_src_attrs); + if (new_wire == nullptr) { + new_wire = module->addWire(map_name(cell, tpl_wire), tpl_wire); + new_wire->port_input = new_wire->port_output = false; + new_wire->port_id = false; } - design->select(module, w); + + map_attributes(cell, new_wire, tpl_wire->name); + wire_map[tpl_wire] = new_wire; + design->select(module, new_wire); } - SigMap sigmap(module); + for (auto &tpl_proc_it : tpl->processes) { + RTLIL::Process *new_proc = module->addProcess(map_name(cell, tpl_proc_it.second), tpl_proc_it.second); + map_attributes(cell, new_proc, tpl_proc_it.second->name); + auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); }; + new_proc->rewrite_sigspecs(rewriter); + design->select(module, new_proc); + } - SigMap tpl_sigmap(tpl); - pool<SigBit> tpl_written_bits; + for (auto tpl_cell : tpl->cells()) { + RTLIL::Cell *new_cell = module->addCell(map_name(cell, tpl_cell), tpl_cell); + map_attributes(cell, new_cell, tpl_cell->name); + if (new_cell->type.in(ID($memrd), ID($memwr), ID($meminit))) { + IdString memid = new_cell->getParam(ID::MEMID).decode_string(); + new_cell->setParam(ID::MEMID, Const(memory_map.at(memid).str())); + } else if (new_cell->type == ID($mem)) { + IdString memid = new_cell->getParam(ID::MEMID).decode_string(); + new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid).str())); + } + auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); }; + new_cell->rewrite_sigspecs(rewriter); + design->select(module, new_cell); + new_cells.push_back(new_cell); + } - for (auto tpl_cell : tpl->cells()) - for (auto &conn : tpl_cell->connections()) - if (tpl_cell->output(conn.first)) - for (auto bit : tpl_sigmap(conn.second)) - tpl_written_bits.insert(bit); - for (auto &conn : tpl->connections()) - for (auto bit : tpl_sigmap(conn.first)) - tpl_written_bits.insert(bit); + for (auto &tpl_conn_it : tpl->connections()) { + RTLIL::SigSig new_conn = tpl_conn_it; + map_sigspec(wire_map, new_conn.first); + map_sigspec(wire_map, new_conn.second); + module->connect(new_conn); + } + + // Attach port connections of the flattened cell - SigMap port_signal_map; + SigMap tpl_sigmap(tpl); + pool<SigBit> tpl_driven; + for (auto tpl_cell : tpl->cells()) + for (auto &tpl_conn : tpl_cell->connections()) + if (tpl_cell->output(tpl_conn.first)) + for (auto bit : tpl_sigmap(tpl_conn.second)) + tpl_driven.insert(bit); + for (auto &tpl_conn : tpl->connections()) + for (auto bit : tpl_sigmap(tpl_conn.first)) + tpl_driven.insert(bit); - for (auto &it : cell->connections()) + SigMap sigmap(module); + for (auto &port_it : cell->connections()) { - IdString portname = it.first; - if (positional_ports.count(portname) > 0) - portname = positional_ports.at(portname); - if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { - if (portname.begins_with("$")) - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); + IdString port_name = port_it.first; + if (positional_ports.count(port_name) > 0) + port_name = positional_ports.at(port_name); + if (tpl->wire(port_name) == nullptr || tpl->wire(port_name)->port_id == 0) { + if (port_name.begins_with("$")) + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", + port_name.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; } - if (GetSize(it.second) == 0) + if (GetSize(port_it.second) == 0) continue; - RTLIL::Wire *w = tpl->wire(portname); - RTLIL::SigSig c; - - if (w->port_output && !w->port_input) { - c.first = it.second; - c.second = RTLIL::SigSpec(w); - apply_prefix(cell->name, c.second, module); - } else if (!w->port_output && w->port_input) { - c.first = RTLIL::SigSpec(w); - c.second = it.second; - apply_prefix(cell->name, c.first, module); + RTLIL::Wire *tpl_wire = tpl->wire(port_name); + RTLIL::SigSig new_conn; + if (tpl_wire->port_output && !tpl_wire->port_input) { + new_conn.first = port_it.second; + new_conn.second = tpl_wire; + } else if (!tpl_wire->port_output && tpl_wire->port_input) { + new_conn.first = tpl_wire; + new_conn.second = port_it.second; } else { - SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; - apply_prefix(cell->name, sig_tpl_pf, module); + SigSpec sig_tpl = tpl_wire, sig_mod = port_it.second; for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { - if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) { - c.first.append(sig_mod[i]); - c.second.append(sig_tpl_pf[i]); + if (tpl_driven.count(tpl_sigmap(sig_tpl[i]))) { + new_conn.first.append(sig_mod[i]); + new_conn.second.append(sig_tpl[i]); } else { - c.first.append(sig_tpl_pf[i]); - c.second.append(sig_mod[i]); + new_conn.first.append(sig_tpl[i]); + new_conn.second.append(sig_mod[i]); } } } + map_sigspec(wire_map, new_conn.first, module); + map_sigspec(wire_map, new_conn.second, module); - if (c.second.size() > c.first.size()) - c.second.remove(c.first.size(), c.second.size() - c.first.size()); - - if (c.second.size() < c.first.size()) - c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size())); + if (new_conn.second.size() > new_conn.first.size()) + new_conn.second.remove(new_conn.first.size(), new_conn.second.size() - new_conn.first.size()); + if (new_conn.second.size() < new_conn.first.size()) + new_conn.second.append(RTLIL::SigSpec(RTLIL::State::S0, new_conn.first.size() - new_conn.second.size())); + log_assert(new_conn.first.size() == new_conn.second.size()); - log_assert(c.first.size() == c.second.size()); - - // connect internal and external wires - - if (sigmap(c.first).has_const()) + if (sigmap(new_conn.first).has_const()) log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n", - log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second)); + log_id(module), log_id(cell), log_id(port_it.first), log_signal(new_conn.first), log_signal(new_conn.second)); - module->connect(c); - } - - for (auto tpl_cell : tpl->cells()) - { - IdString c_name = tpl_cell->name; - apply_prefix(cell->name, c_name); - - RTLIL::Cell *c = module->addCell(c_name, tpl_cell); - new_cells.push_back(c); - design->select(module, c); - - for (auto &conn : c->connections()) - { - RTLIL::SigSpec new_conn = conn.second; - apply_prefix(cell->name, new_conn, module); - port_signal_map.apply(new_conn); - c->setPort(conn.first, std::move(new_conn)); - } - - if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { - IdString memid = c->getParam(ID::MEMID).decode_string(); - log_assert(memory_renames.count(memid) != 0); - c->setParam(ID::MEMID, Const(memory_renames[memid].str())); - } - - if (c->type == ID($mem)) { - IdString memid = c->getParam(ID::MEMID).decode_string(); - apply_prefix(cell->name, memid); - c->setParam(ID::MEMID, Const(memid.c_str())); - } - - if (c->attributes.count(ID::src)) - c->add_strpool_attribute(ID::src, extra_src_attrs); - } - - for (auto &it : tpl->connections()) { - RTLIL::SigSig c = it; - apply_prefix(cell->name.str(), c.first, module); - apply_prefix(cell->name.str(), c.second, module); - port_signal_map.apply(c.first); - port_signal_map.apply(c.second); - module->connect(c); + module->connect(new_conn); } module->remove(cell); - - for (auto &it : temp_renamed_wires) - { - Wire *w = it.first; - IdString name = it.second; - IdString altname = module->uniquify(name); - Wire *other_w = module->wire(name); - module->rename(other_w, altname); - module->rename(w, name); - } } void flatten_module(RTLIL::Design *design, RTLIL::Module *module, pool<RTLIL::Module*> &used_modules) @@ -277,7 +253,7 @@ struct FlattenWorker struct FlattenPass : public Pass { FlattenPass() : Pass("flatten", "flatten design") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -294,7 +270,7 @@ struct FlattenPass : public Pass { log(" Ignore the 'whitebox' attribute on cell implementations.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing FLATTEN pass (flatten design).\n"); log_push(); diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index 72947237b..dfdbe6b88 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -1470,7 +1470,7 @@ static void split(std::vector<std::string> &tokens, const std::string &text, cha struct FlowmapPass : public Pass { FlowmapPass() : Pass("flowmap", "pack LUTs with FlowMap") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1511,7 +1511,7 @@ struct FlowmapPass : public Pass { log(" explain decisions performed during depth relaxation.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { int order = 3; int minlut = 1; diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index 5aeb5ea79..b808a8d8e 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -55,7 +55,7 @@ void hilomap_worker(RTLIL::SigSpec &sig) struct HilomapPass : public Pass { HilomapPass() : Pass("hilomap", "technology mapping of constant hi- and/or lo-drivers") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" hilomap [options] [selection]\n"); @@ -74,7 +74,7 @@ struct HilomapPass : public Pass { log(" each constant bit.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n"); diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc index 0686c0f2b..a3b5b698d 100644 --- a/passes/techmap/insbuf.cc +++ b/passes/techmap/insbuf.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct InsbufPass : public Pass { InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" insbuf [options] [selection]\n"); @@ -37,7 +37,7 @@ struct InsbufPass : public Pass { log(" call to \"clean\" will remove all $_BUF_ in the design.)\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n"); diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index a18d02652..e8530a034 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -34,7 +34,7 @@ void split_portname_pair(std::string &port1, std::string &port2) struct IopadmapPass : public Pass { IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { } - void help() YS_OVERRIDE + void help() override { log("\n"); log(" iopadmap [options] [selection]\n"); @@ -97,7 +97,7 @@ struct IopadmapPass : public Pass { modules_processed.insert(module); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n"); diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc index 703bf6ff6..f56eff3e5 100644 --- a/passes/techmap/lut2mux.cc +++ b/passes/techmap/lut2mux.cc @@ -56,7 +56,7 @@ int lut2mux(Cell *cell) struct Lut2muxPass : public Pass { Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -65,7 +65,7 @@ struct Lut2muxPass : public Pass { log("This pass converts $lut cells to $_MUX_ gates.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n"); diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 3bb929009..43f2d97f5 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -365,7 +365,7 @@ PRIVATE_NAMESPACE_BEGIN struct MaccmapPass : public Pass { MaccmapPass() : Pass("maccmap", "mapping macc cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -375,7 +375,7 @@ struct MaccmapPass : public Pass { log("is used then the $macc cell is mapped to $add, $sub, etc. cells instead.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { bool unmap_mode = false; diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index bd049d86d..24109b579 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -623,7 +623,7 @@ struct MuxcoverWorker struct MuxcoverPass : public Pass { MuxcoverPass() : Pass("muxcover", "cover trees of MUX cells with wider MUXes") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -656,7 +656,7 @@ struct MuxcoverPass : public Pass { log(" than <N> different signals.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n"); diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc index 798d82248..e1ebfcad8 100644 --- a/passes/techmap/nlutmap.cc +++ b/passes/techmap/nlutmap.cc @@ -129,7 +129,7 @@ struct NlutmapWorker struct NlutmapPass : public Pass { NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -149,7 +149,7 @@ struct NlutmapPass : public Pass { log("to generic logic gates ($_AND_, etc.).\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { NlutmapConfig config; diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index 2810b7f2d..b937d3fb0 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -67,7 +67,7 @@ static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data, struct PmuxtreePass : public Pass { PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -76,7 +76,7 @@ struct PmuxtreePass : public Pass { log("This pass transforms $pmux cells to trees of $mux cells.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing PMUXTREE pass.\n"); diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index d7a381e0a..b971068f7 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -100,9 +101,8 @@ struct ShregmapWorker int dff_count, shreg_count; pool<Cell*> remove_cells; - pool<SigBit> remove_init; - dict<SigBit, bool> sigbit_init; + FfInitVals initvals; dict<SigBit, Cell*> sigbit_chain_next; dict<SigBit, Cell*> sigbit_chain_prev; pool<SigBit> sigbit_with_non_chain_users; @@ -116,16 +116,6 @@ struct ShregmapWorker for (auto bit : sigmap(wire)) sigbit_with_non_chain_users.insert(bit); } - - if (wire->attributes.count(ID::init)) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (initval[i] == State::S0 && !opts.zinit) - sigbit_init[initsig[i]] = false; - else if (initval[i] == State::S1) - sigbit_init[initsig[i]] = true; - } } for (auto cell : module->cells()) @@ -137,8 +127,9 @@ struct ShregmapWorker SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + State initval = initvals(q_bit); - if (opts.init || sigbit_init.count(q_bit) == 0) + if (opts.init || initval == State::Sx || (opts.zinit && initval == State::S0)) { auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); if (!r.second) { @@ -310,22 +301,17 @@ struct ShregmapWorker if (opts.init) { vector<State> initval; for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - if (sigbit_init.count(bit) == 0) - initval.push_back(State::Sx); - else if (sigbit_init.at(bit)) - initval.push_back(State::S1); - else - initval.push_back(State::S0); - remove_init.insert(bit); + SigBit bit = chain[cursor+i]->getPort(q_port).as_bit(); + initval.push_back(initvals(bit)); + initvals.remove_init(bit); } first_cell->setParam(ID::INIT, initval); } if (opts.zinit) for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - remove_init.insert(bit); + SigBit bit = chain[cursor+i]->getPort(q_port).as_bit(); + initvals.remove_init(bit); } if (opts.params) @@ -364,22 +350,6 @@ struct ShregmapWorker for (auto cell : remove_cells) module->remove(cell); - for (auto wire : module->wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec initsig = sigmap(wire); - Const &initval = wire->attributes.at(ID::init); - - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (remove_init.count(initsig[i])) - initval[i] = State::Sx; - - if (SigSpec(initval).is_fully_undef()) - wire->attributes.erase(ID::init); - } - remove_cells.clear(); sigbit_chain_next.clear(); sigbit_chain_prev.clear(); @@ -389,6 +359,7 @@ struct ShregmapWorker ShregmapWorker(Module *module, const ShregmapOptions &opts) : module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) { + initvals.set(&sigmap, module); make_sigbit_chain_next_prev(); find_chain_start_cells(); @@ -403,7 +374,7 @@ struct ShregmapWorker struct ShregmapPass : public Pass { ShregmapPass() : Pass("shregmap", "map shift registers") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -461,7 +432,7 @@ struct ShregmapPass : public Pass { log(" map to greenpak4 shift registers.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { ShregmapOptions opts; string clkpol, enpol; diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 214157a64..b9d337da4 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -474,29 +474,93 @@ void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) } } -void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_dffsre(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at(ID::WIDTH).as_int(); char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; - char rst_pol = cell->parameters.at(ID::ARST_POLARITY).as_bool() ? 'P' : 'N'; + char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; + char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; + char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; - std::vector<RTLIL::State> rst_val = cell->parameters.at(ID::ARST_VALUE).bits; + RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); + RTLIL::SigSpec sig_s = cell->getPort(ID::SET); + RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); + RTLIL::SigSpec sig_e = cell->getPort(ID::EN); + RTLIL::SigSpec sig_d = cell->getPort(ID::D); + RTLIL::SigSpec sig_q = cell->getPort(ID::Q); + + IdString gate_type = stringf("$_DFFSRE_%c%c%c%c_", clk_pol, set_pol, clr_pol, en_pol); + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->setPort(ID::C, sig_clk); + gate->setPort(ID::S, sig_s[i]); + gate->setPort(ID::R, sig_r[i]); + gate->setPort(ID::E, sig_e); + gate->setPort(ID::D, sig_d[i]); + gate->setPort(ID::Q, sig_q[i]); + } +} + +void simplemap_adff_sdff(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at(ID::WIDTH).as_int(); + bool is_async = cell->type == ID($adff); + char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; + char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N'; + const char *type = is_async ? "DFF" : "SDFF"; + + std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits; while (int(rst_val.size()) < width) rst_val.push_back(RTLIL::State::S0); RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); - RTLIL::SigSpec sig_rst = cell->getPort(ID::ARST); + RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST); + RTLIL::SigSpec sig_d = cell->getPort(ID::D); + RTLIL::SigSpec sig_q = cell->getPort(ID::Q); + + IdString gate_type_0 = stringf("$_%s_%c%c0_", type, clk_pol, rst_pol); + IdString gate_type_1 = stringf("$_%s_%c%c1_", type, clk_pol, rst_pol); + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); + gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->setPort(ID::C, sig_clk); + gate->setPort(ID::R, sig_rst); + gate->setPort(ID::D, sig_d[i]); + gate->setPort(ID::Q, sig_q[i]); + } +} + +void simplemap_adffe_sdffe_sdffce(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at(ID::WIDTH).as_int(); + bool is_async = cell->type == ID($adffe); + char clk_pol = cell->parameters.at(ID::CLK_POLARITY).as_bool() ? 'P' : 'N'; + char rst_pol = cell->parameters.at(is_async ? ID::ARST_POLARITY : ID::SRST_POLARITY).as_bool() ? 'P' : 'N'; + char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; + const char *type = is_async ? "DFFE" : cell->type == ID($sdffe) ? "SDFFE" : "SDFFCE"; + + std::vector<RTLIL::State> rst_val = cell->parameters.at(is_async ? ID::ARST_VALUE : ID::SRST_VALUE).bits; + while (int(rst_val.size()) < width) + rst_val.push_back(RTLIL::State::S0); + + RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK); + RTLIL::SigSpec sig_rst = cell->getPort(is_async ? ID::ARST : ID::SRST); + RTLIL::SigSpec sig_e = cell->getPort(ID::EN); RTLIL::SigSpec sig_d = cell->getPort(ID::D); RTLIL::SigSpec sig_q = cell->getPort(ID::Q); - IdString gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol); - IdString gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol); + IdString gate_type_0 = stringf("$_%s_%c%c0%c_", type, clk_pol, rst_pol, en_pol); + IdString gate_type_1 = stringf("$_%s_%c%c1%c_", type, clk_pol, rst_pol, en_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); gate->setPort(ID::C, sig_clk); gate->setPort(ID::R, sig_rst); + gate->setPort(ID::E, sig_e); gate->setPort(ID::D, sig_d[i]); gate->setPort(ID::Q, sig_q[i]); } @@ -522,6 +586,60 @@ void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) } } +void simplemap_adlatch(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at(ID::WIDTH).as_int(); + char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; + char rst_pol = cell->parameters.at(ID::ARST_POLARITY).as_bool() ? 'P' : 'N'; + + std::vector<RTLIL::State> rst_val = cell->parameters.at(ID::ARST_VALUE).bits; + while (int(rst_val.size()) < width) + rst_val.push_back(RTLIL::State::S0); + + RTLIL::SigSpec sig_en = cell->getPort(ID::EN); + RTLIL::SigSpec sig_rst = cell->getPort(ID::ARST); + RTLIL::SigSpec sig_d = cell->getPort(ID::D); + RTLIL::SigSpec sig_q = cell->getPort(ID::Q); + + IdString gate_type_0 = stringf("$_DLATCH_%c%c0_", en_pol, rst_pol); + IdString gate_type_1 = stringf("$_DLATCH_%c%c1_", en_pol, rst_pol); + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); + gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->setPort(ID::E, sig_en); + gate->setPort(ID::R, sig_rst); + gate->setPort(ID::D, sig_d[i]); + gate->setPort(ID::Q, sig_q[i]); + } +} + +void simplemap_dlatchsr(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at(ID::WIDTH).as_int(); + char en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N'; + char set_pol = cell->parameters.at(ID::SET_POLARITY).as_bool() ? 'P' : 'N'; + char clr_pol = cell->parameters.at(ID::CLR_POLARITY).as_bool() ? 'P' : 'N'; + + RTLIL::SigSpec sig_en = cell->getPort(ID::EN); + RTLIL::SigSpec sig_s = cell->getPort(ID::SET); + RTLIL::SigSpec sig_r = cell->getPort(ID::CLR); + RTLIL::SigSpec sig_d = cell->getPort(ID::D); + RTLIL::SigSpec sig_q = cell->getPort(ID::Q); + + IdString gate_type = stringf("$_DLATCHSR_%c%c%c_", en_pol, set_pol, clr_pol); + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->setPort(ID::E, sig_en); + gate->setPort(ID::S, sig_s[i]); + gate->setPort(ID::R, sig_r[i]); + gate->setPort(ID::D, sig_d[i]); + gate->setPort(ID::Q, sig_q[i]); + } +} + void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers) { mappers[ID($not)] = simplemap_not; @@ -553,8 +671,15 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers[ID($dff)] = simplemap_dff; mappers[ID($dffe)] = simplemap_dffe; mappers[ID($dffsr)] = simplemap_dffsr; - mappers[ID($adff)] = simplemap_adff; + mappers[ID($dffsre)] = simplemap_dffsre; + mappers[ID($adff)] = simplemap_adff_sdff; + mappers[ID($sdff)] = simplemap_adff_sdff; + mappers[ID($adffe)] = simplemap_adffe_sdffe_sdffce; + mappers[ID($sdffe)] = simplemap_adffe_sdffe_sdffce; + mappers[ID($sdffce)] = simplemap_adffe_sdffe_sdffce; mappers[ID($dlatch)] = simplemap_dlatch; + mappers[ID($adlatch)] = simplemap_adlatch; + mappers[ID($dlatchsr)] = simplemap_dlatchsr; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) @@ -575,7 +700,7 @@ PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -587,10 +712,10 @@ struct SimplemapPass : public Pass { log(" $not, $pos, $and, $or, $xor, $xnor\n"); log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n"); log(" $logic_not, $logic_and, $logic_or, $mux, $tribuf\n"); - log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n"); + log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 535db9465..c22ae8ef0 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -20,6 +20,7 @@ #include "kernel/yosys.h" #include "kernel/utils.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include "libs/sha1/sha1.h" #include <stdlib.h> @@ -328,8 +329,9 @@ struct TechmapWorker for (auto tpl_cell : tpl->cells()) { IdString c_name = tpl_cell->name; + bool techmap_replace_cell = (c_name == ID::_TECHMAP_REPLACE_); - if (c_name == ID::_TECHMAP_REPLACE_) + if (techmap_replace_cell) c_name = orig_cell_name; else if (tpl_cell->name.begins_with("\\_TECHMAP_REPLACE_.")) c_name = stringf("%s%s", orig_cell_name.c_str(), c_name.c_str() + strlen("\\_TECHMAP_REPLACE_")); @@ -384,7 +386,7 @@ struct TechmapWorker if (c->attributes.count(ID::src)) c->add_strpool_attribute(ID::src, extra_src_attrs); - if (c_name == ID::_TECHMAP_REPLACE_) + if (techmap_replace_cell) for (auto attr : cell->attributes) if (!c->attributes.count(attr.first)) c->attributes[attr.first] = attr.second; @@ -425,18 +427,7 @@ struct TechmapWorker LogMakeDebugHdl mkdebug; SigMap sigmap(module); - - dict<SigBit, State> init_bits; - pool<SigBit> remove_init_bits; - - for (auto wire : module->wires()) { - if (wire->attributes.count(ID::init)) { - Const value = wire->attributes.at(ID::init); - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - if (value[i] != State::Sx) - init_bits[sigmap(SigBit(wire, i))] = value[i]; - } - } + FfInitVals initvals(&sigmap, module); TopoSort<RTLIL::Cell*, IdString::compare_ptr_by_name<RTLIL::Cell>> cells; dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_inbit; @@ -642,6 +633,8 @@ struct TechmapWorker if (tpl->avail_parameters.count(ID::_TECHMAP_CELLTYPE_) != 0) parameters.emplace(ID::_TECHMAP_CELLTYPE_, RTLIL::unescape_id(cell->type)); + if (tpl->avail_parameters.count(ID::_TECHMAP_CELLNAME_) != 0) + parameters.emplace(ID::_TECHMAP_CELLNAME_, RTLIL::unescape_id(cell->name)); for (auto &conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first))) != 0) { @@ -658,15 +651,7 @@ struct TechmapWorker parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { - auto sig = sigmap(conn.second); - RTLIL::Const value(State::Sx, sig.size()); - for (int i = 0; i < sig.size(); i++) { - auto it = init_bits.find(sig[i]); - if (it != init_bits.end()) { - value[i] = it->second; - } - } - parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), value); + parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); } } @@ -911,7 +896,7 @@ struct TechmapWorker auto sig = sigmap(it->second); for (int i = 0; i < sig.size(); i++) if (val[i] == State::S1) - remove_init_bits.insert(sig[i]); + initvals.remove_init(sig[i]); } } } @@ -960,25 +945,6 @@ struct TechmapWorker handled_cells.insert(cell); } - if (!remove_init_bits.empty()) { - for (auto wire : module->wires()) - if (wire->attributes.count(ID::init)) { - Const &value = wire->attributes.at(ID::init); - bool do_cleanup = true; - for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { - SigBit bit = sigmap(SigBit(wire, i)); - if (remove_init_bits.count(bit)) - value[i] = State::Sx; - else if (value[i] != State::Sx) - do_cleanup = false; - } - if (do_cleanup) { - log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase(ID::init); - } - } - } - if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; @@ -991,7 +957,7 @@ struct TechmapWorker struct TechmapPass : public Pass { TechmapPass() : Pass("techmap", "generic technology mapper") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1110,6 +1076,10 @@ struct TechmapPass : public Pass { log(" When a parameter with this name exists, it will be set to the type name\n"); log(" of the cell that matches the module.\n"); log("\n"); + log(" _TECHMAP_CELLNAME_\n"); + log(" When a parameter with this name exists, it will be set to the name\n"); + log(" of the cell that matches the module.\n"); + log("\n"); log(" _TECHMAP_CONSTMSK_<port-name>_\n"); log(" _TECHMAP_CONSTVAL_<port-name>_\n"); log(" When this pair of parameters is available in a module for a port, then\n"); @@ -1151,7 +1121,7 @@ struct TechmapPass : public Pass { log("essentially techmap but using the design itself as map library).\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { log_header(design, "Executing TECHMAP pass (map to technology primitives).\n"); log_push(); diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index 90f3a9d6f..79ddb4bd7 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -143,7 +143,7 @@ struct TribufWorker { struct TribufPass : public Pass { TribufPass() : Pass("tribuf", "infer tri-state buffers") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -160,7 +160,7 @@ struct TribufPass : public Pass { log(" to non-tristate logic. this option implies -merge.\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { TribufConfig config; diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc index 74604ba3b..e3b4ae573 100644 --- a/passes/techmap/zinit.cc +++ b/passes/techmap/zinit.cc @@ -19,13 +19,14 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/ffinit.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct ZinitPass : public Pass { ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { } - void help() YS_OVERRIDE + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -37,7 +38,7 @@ struct ZinitPass : public Pass { log(" also add zero initialization to uninitialized FFs\n"); log("\n"); } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) override { bool all_mode = false; @@ -57,54 +58,35 @@ struct ZinitPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); - dict<SigBit, std::pair<State,SigBit>> initbits; - - for (auto wire : module->selected_wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) - { - SigBit bit = wirebits[i]; - State val = initval[i]; - - if (val != State::S0 && val != State::S1 && bit.wire != nullptr) - continue; - - if (initbits.count(bit)) { - if (initbits.at(bit).first != val) - log_error("Conflicting init values for signal %s (%s = %s != %s).\n", - log_signal(bit), log_signal(SigBit(wire, i)), - log_signal(val), log_signal(initbits.at(bit).first)); - continue; - } - - initbits[bit] = std::make_pair(val,SigBit(wire,i)); - } - } + FfInitVals initvals(&sigmap, module); pool<IdString> dff_types = { // FIXME: It would appear that supporting // $dffsr/$_DFFSR_* would require a new // cell type where S has priority over R - ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), + ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), ID($adffe), + ID($sdff), ID($sdffe), ID($sdffce), ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), /*ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),*/ ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), // Async set/reset - ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), - ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1), + ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_), + ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_), + ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_), + ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_), // Sync set/reset - ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_), - ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_), - ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1), - ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1) + ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_), + ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_), + ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_), + ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_), + ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_), + ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_), + ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_), + ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_), + ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_), + ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_) }; for (auto cell : module->selected_cells()) @@ -118,46 +100,48 @@ struct ZinitPass : public Pass { if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; - Const initval; + Const initval = initvals(sig_q); + Const newval = initval; + initvals.remove_init(sig_q); - for (int i = 0; i < GetSize(sig_q); i++) { - if (initbits.count(sig_q[i])) { - const auto &d = initbits.at(sig_q[i]); - initval.bits.push_back(d.first); - const auto &b = d.second; - b.wire->attributes.at(ID::init)[b.offset] = State::Sx; - } else - initval.bits.push_back(all_mode ? State::S0 : State::Sx); - } - - Wire *initwire = module->addWire(NEW_ID, GetSize(initval)); - initwire->attributes[ID::init] = initval; + Wire *initwire = module->addWire(NEW_ID, GetSize(sig_q)); for (int i = 0; i < GetSize(initwire); i++) if (initval[i] == State::S1) { sig_d[i] = module->NotGate(NEW_ID, sig_d[i]); module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]); - initwire->attributes[ID::init][i] = State::S0; + newval[i] = State::S0; } else { module->connect(sig_q[i], SigSpec(initwire, i)); + if (all_mode) + newval[i] = State::S0; } + initvals.set_init(initwire, newval); + log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type), log_signal(sig_q), log_signal(initval)); cell->setPort(ID::D, sig_d); cell->setPort(ID::Q, initwire); - if (cell->type == ID($adff)) { + if (cell->type.in(ID($adff), ID($adffe))) { auto val = cell->getParam(ID::ARST_VALUE); for (int i = 0; i < GetSize(initwire); i++) if (initval[i] == State::S1) val[i] = (val[i] == State::S1 ? State::S0 : State::S1); cell->setParam(ID::ARST_VALUE, std::move(val)); } + else if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) { + auto val = cell->getParam(ID::SRST_VALUE); + for (int i = 0; i < GetSize(initwire); i++) + if (initval[i] == State::S1) + val[i] = (val[i] == State::S1 ? State::S0 : State::S1); + cell->setParam(ID::SRST_VALUE, std::move(val)); + } else if (initval == State::S1) { std::string t = cell->type.str(); if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), @@ -165,15 +149,29 @@ struct ZinitPass : public Pass { { t[8] = (t[8] == '0' ? '1' : '0'); } - else if (cell->type.in(ID($__DFFE_NN0), ID($__DFFE_NN1), ID($__DFFE_NP0), ID($__DFFE_NP1), - ID($__DFFE_PN0), ID($__DFFE_PN1), ID($__DFFE_PP0), ID($__DFFE_PP1), - ID($__DFFS_NN0_), ID($__DFFS_NN1_), ID($__DFFS_NP0_), ID($__DFFS_NP1_), - ID($__DFFS_PN0_), ID($__DFFS_PN1_), ID($__DFFS_PP0_), ID($__DFFS_PP1_))) + else if (cell->type.in(ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_), + ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_))) + { + t[9] = (t[9] == '0' ? '1' : '0'); + } + else if (cell->type.in(ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_), + ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_), + ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_), + ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_))) + { + t[9] = (t[9] == '0' ? '1' : '0'); + } + else if (cell->type.in(ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_), + ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_), + ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_), + ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_))) { t[10] = (t[10] == '0' ? '1' : '0'); } - else if (cell->type.in(ID($__DFFSE_NN0), ID($__DFFSE_NN1), ID($__DFFSE_NP0), ID($__DFFSE_NP1), - ID($__DFFSE_PN0), ID($__DFFSE_PN1), ID($__DFFSE_PP0), ID($__DFFSE_PP1))) + else if (cell->type.in(ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_), + ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_), + ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_), + ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_))) { t[11] = (t[11] == '0' ? '1' : '0'); } |