aboutsummaryrefslogtreecommitdiffstats
path: root/passes/techmap
diff options
context:
space:
mode:
Diffstat (limited to 'passes/techmap')
-rw-r--r--passes/techmap/Makefile.inc2
-rw-r--r--passes/techmap/abc.cc35
-rw-r--r--passes/techmap/abc9.cc14
-rw-r--r--passes/techmap/abc9_exe.cc4
-rw-r--r--passes/techmap/abc9_ops.cc8
-rw-r--r--passes/techmap/aigmap.cc4
-rw-r--r--passes/techmap/alumacc.cc4
-rw-r--r--passes/techmap/attrmap.cc16
-rw-r--r--passes/techmap/attrmvcp.cc4
-rw-r--r--passes/techmap/clkbufmap.cc62
-rw-r--r--passes/techmap/deminout.cc4
-rw-r--r--passes/techmap/dff2dffe.cc44
-rw-r--r--passes/techmap/dff2dffs.cc22
-rw-r--r--passes/techmap/dffinit.cc52
-rw-r--r--passes/techmap/dfflegalize.cc1319
-rw-r--r--passes/techmap/dfflibmap.cc293
-rw-r--r--passes/techmap/dffunmap.cc107
-rw-r--r--passes/techmap/extract.cc4
-rw-r--r--passes/techmap/extract_counter.cc14
-rw-r--r--passes/techmap/extract_fa.cc4
-rw-r--r--passes/techmap/extract_reduce.cc4
-rw-r--r--passes/techmap/extractinv.cc6
-rw-r--r--passes/techmap/flatten.cc310
-rw-r--r--passes/techmap/flowmap.cc4
-rw-r--r--passes/techmap/hilomap.cc4
-rw-r--r--passes/techmap/insbuf.cc4
-rw-r--r--passes/techmap/iopadmap.cc4
-rw-r--r--passes/techmap/lut2mux.cc4
-rw-r--r--passes/techmap/maccmap.cc4
-rw-r--r--passes/techmap/muxcover.cc4
-rw-r--r--passes/techmap/nlutmap.cc4
-rw-r--r--passes/techmap/pmuxtree.cc4
-rw-r--r--passes/techmap/shregmap.cc53
-rw-r--r--passes/techmap/simplemap.cc145
-rw-r--r--passes/techmap/techmap.cc60
-rw-r--r--passes/techmap/tribuf.cc4
-rw-r--r--passes/techmap/zinit.cc116
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');
}