aboutsummaryrefslogtreecommitdiffstats
path: root/passes/techmap
diff options
context:
space:
mode:
Diffstat (limited to 'passes/techmap')
-rw-r--r--passes/techmap/Makefile.inc6
-rw-r--r--passes/techmap/abc.cc124
-rw-r--r--passes/techmap/abc9.cc28
-rw-r--r--passes/techmap/abc9_exe.cc15
-rw-r--r--passes/techmap/abc9_ops.cc183
-rw-r--r--passes/techmap/aigmap.cc2
-rw-r--r--passes/techmap/alumacc.cc2
-rw-r--r--passes/techmap/attrmap.cc2
-rw-r--r--passes/techmap/attrmvcp.cc2
-rw-r--r--passes/techmap/bmuxmap.cc76
-rw-r--r--passes/techmap/clkbufmap.cc60
-rw-r--r--passes/techmap/deminout.cc2
-rw-r--r--passes/techmap/demuxmap.cc80
-rw-r--r--passes/techmap/dff2dffe.cc414
-rw-r--r--passes/techmap/dff2dffs.cc165
-rw-r--r--passes/techmap/dffinit.cc50
-rw-r--r--passes/techmap/dfflegalize.cc1235
-rw-r--r--passes/techmap/dfflibmap.cc291
-rw-r--r--passes/techmap/dffunmap.cc106
-rw-r--r--passes/techmap/extract.cc13
-rw-r--r--passes/techmap/extract_counter.cc2
-rw-r--r--passes/techmap/extract_fa.cc4
-rw-r--r--passes/techmap/extract_reduce.cc107
-rw-r--r--passes/techmap/extractinv.cc4
-rw-r--r--passes/techmap/flatten.cc30
-rw-r--r--passes/techmap/hilomap.cc2
-rw-r--r--passes/techmap/insbuf.cc2
-rw-r--r--passes/techmap/iopadmap.cc33
-rw-r--r--passes/techmap/libparse.cc6
-rw-r--r--passes/techmap/libparse.h2
-rw-r--r--passes/techmap/lut2mux.cc2
-rw-r--r--passes/techmap/maccmap.cc2
-rw-r--r--passes/techmap/muxcover.cc2
-rw-r--r--passes/techmap/nlutmap.cc2
-rw-r--r--passes/techmap/pmuxtree.cc2
-rw-r--r--passes/techmap/shregmap.cc51
-rw-r--r--passes/techmap/simplemap.cc334
-rw-r--r--passes/techmap/simplemap.h9
-rw-r--r--passes/techmap/techmap.cc179
-rw-r--r--passes/techmap/tribuf.cc2
-rw-r--r--passes/techmap/zinit.cc161
41 files changed, 2096 insertions, 1698 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index a54b4913d..98ccfc303 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -27,9 +27,10 @@ OBJS += passes/techmap/extract_fa.o
OBJS += passes/techmap/extract_counter.o
OBJS += passes/techmap/extract_reduce.o
OBJS += passes/techmap/alumacc.o
-OBJS += passes/techmap/dff2dffe.o
OBJS += passes/techmap/dffinit.o
OBJS += passes/techmap/pmuxtree.o
+OBJS += passes/techmap/bmuxmap.o
+OBJS += passes/techmap/demuxmap.o
OBJS += passes/techmap/muxcover.o
OBJS += passes/techmap/aigmap.o
OBJS += passes/techmap/tribuf.o
@@ -41,7 +42,8 @@ OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
-OBJS += passes/techmap/dff2dffs.o
+OBJS += passes/techmap/dfflegalize.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 0a58fdcc0..80c6282c4 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -38,12 +38,13 @@
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
-#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_SOP "strash; dretime; cover {I} {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#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>
@@ -53,6 +54,7 @@
#include <cerrno>
#include <sstream>
#include <climits>
+#include <vector>
#ifndef _WIN32
# include <unistd.h>
@@ -111,7 +113,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 +135,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;
}
@@ -656,8 +655,9 @@ struct abc_output_filter
};
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
- std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
- bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
+ std::vector<std::string> &liberty_files, std::vector<std::string> &genlib_files, std::string constr_file,
+ bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target,
+ std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress)
{
module = current_module;
@@ -711,8 +711,11 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
std::string abc_script = stringf("read_blif %s/input.blif; ", tempdir_name.c_str());
- if (!liberty_file.empty()) {
- abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ if (!liberty_files.empty() || !genlib_files.empty()) {
+ for (std::string liberty_file : liberty_files)
+ abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+ for (std::string liberty_file : genlib_files)
+ abc_script += stringf("read_library %s; ", liberty_file.c_str());
if (!constr_file.empty())
abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
} else
@@ -740,7 +743,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
if (all_luts_cost_same && !fast_mode)
abc_script += "; lutpack {S}";
- } else if (!liberty_file.empty())
+ } else if (!liberty_files.empty() || !genlib_files.empty())
abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
else if (sop_mode)
abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
@@ -1021,7 +1024,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (ifs.fail())
log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
- bool builtin_lib = liberty_file.empty();
+ bool builtin_lib = liberty_files.empty() && genlib_files.empty();
RTLIL::Design *mapped_design = new RTLIL::Design;
parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode);
@@ -1303,10 +1306,10 @@ struct AbcPass : public Pass {
log("\n");
log(" if no -script parameter is given, the following scripts are used:\n");
log("\n");
- log(" for -liberty without -constr:\n");
+ log(" for -liberty/-genlib without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
log("\n");
- log(" for -liberty with -constr:\n");
+ log(" for -liberty/-genlib with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts (only one LUT size):\n");
@@ -1325,10 +1328,10 @@ struct AbcPass : public Pass {
log(" use different default scripts that are slightly faster (at the cost\n");
log(" of output quality):\n");
log("\n");
- log(" for -liberty without -constr:\n");
+ log(" for -liberty/-genlib without -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
log("\n");
- log(" for -liberty with -constr:\n");
+ log(" for -liberty/-genlib with -constr:\n");
log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
log("\n");
log(" for -lut/-luts:\n");
@@ -1344,8 +1347,13 @@ struct AbcPass : public Pass {
log(" generate netlists for the specified cell library (using the liberty\n");
log(" file format).\n");
log("\n");
+ log(" -genlib <file>\n");
+ log(" generate netlists for the specified cell library (using the SIS Genlib\n");
+ log(" file format).\n");
+ log("\n");
log(" -constr <file>\n");
- log(" pass this file with timing constraints to ABC. use with -liberty.\n");
+ log(" pass this file with timing constraints to ABC.\n");
+ log(" use with -liberty/-genlib.\n");
log("\n");
log(" a constr file contains two lines:\n");
log(" set_driving_cell <cell_name>\n");
@@ -1391,7 +1399,7 @@ struct AbcPass : public Pass {
log("\n");
// log(" -mux4, -mux8, -mux16\n");
// log(" try to extract 4-input, 8-input, and/or 16-input muxes\n");
- // log(" (ignored when used with -liberty or -lut)\n");
+ // log(" (ignored when used with -liberty/-genlib or -lut)\n");
// log("\n");
log(" -g type1,type2,...\n");
log(" Map to the specified list of gate types. Supported gates types are:\n");
@@ -1447,7 +1455,7 @@ struct AbcPass : public Pass {
log(" preserve naming by an equivalence check between the original and post-ABC\n");
log(" netlists (experimental).\n");
log("\n");
- log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
+ log("When no target cell library is specified the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
@@ -1468,16 +1476,13 @@ struct AbcPass : public Pass {
assign_map.clear();
signal_list.clear();
signal_map.clear();
- signal_init.clear();
+ initvals.clear();
pi_map.clear();
po_map.clear();
-#ifdef ABCEXTERNAL
- std::string exe_file = ABCEXTERNAL;
-#else
- std::string exe_file = proc_self_dirname() + proc_program_prefix() + "yosys-abc";
-#endif
- std::string script_file, liberty_file, constr_file, clk_str;
+ std::string exe_file = yosys_abc_executable;
+ std::string script_file, default_liberty_file, constr_file, clk_str;
+ std::vector<std::string> liberty_files, genlib_files;
std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
bool show_tempdir = false, sop_mode = false;
@@ -1491,18 +1496,11 @@ struct AbcPass : public Pass {
enabled_gates.clear();
cmos_cost = false;
-#ifdef _WIN32
-#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix()+ "yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
-#endif
-#endif
-
// get arguments from scratchpad first, then override by command arguments
std::string lut_arg, luts_arg, g_arg;
exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */);
script_file = design->scratchpad_get_string("abc.script", script_file);
- liberty_file = design->scratchpad_get_string("abc.liberty", liberty_file);
+ default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file);
constr_file = design->scratchpad_get_string("abc.constr", constr_file);
if (design->scratchpad.count("abc.D")) {
delay_target = "-D " + design->scratchpad_get_string("abc.D");
@@ -1564,7 +1562,11 @@ struct AbcPass : public Pass {
continue;
}
if (arg == "-liberty" && argidx+1 < args.size()) {
- liberty_file = args[++argidx];
+ liberty_files.push_back(args[++argidx]);
+ continue;
+ }
+ if (arg == "-genlib" && argidx+1 < args.size()) {
+ genlib_files.push_back(args[++argidx]);
continue;
}
if (arg == "-constr" && argidx+1 < args.size()) {
@@ -1656,12 +1658,22 @@ struct AbcPass : public Pass {
}
extra_args(args, argidx, design);
+ if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty())
+ liberty_files.push_back(default_liberty_file);
+
rewrite_filename(script_file);
if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
script_file = std::string(pwd) + "/" + script_file;
- rewrite_filename(liberty_file);
- if (!liberty_file.empty() && !is_absolute_path(liberty_file))
- liberty_file = std::string(pwd) + "/" + liberty_file;
+ for (int i = 0; i < GetSize(liberty_files); i++) {
+ rewrite_filename(liberty_files[i]);
+ if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i]))
+ liberty_files[i] = std::string(pwd) + "/" + liberty_files[i];
+ }
+ for (int i = 0; i < GetSize(genlib_files); i++) {
+ rewrite_filename(genlib_files[i]);
+ if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i]))
+ genlib_files[i] = std::string(pwd) + "/" + genlib_files[i];
+ }
rewrite_filename(constr_file);
if (!constr_file.empty() && !is_absolute_path(constr_file))
constr_file = std::string(pwd) + "/" + constr_file;
@@ -1807,6 +1819,7 @@ struct AbcPass : public Pass {
gate_list.push_back("OAI4");
gate_list.push_back("MUX");
gate_list.push_back("NMUX");
+ goto ok_alias;
}
if (g_arg_from_cmd)
cmd_error(args, g_argidx, stringf("Unsupported gate type: %s", g.c_str()));
@@ -1824,10 +1837,10 @@ struct AbcPass : public Pass {
}
}
- if (!lut_costs.empty() && !liberty_file.empty())
- log_cmd_error("Got -lut and -liberty! These two options are exclusive.\n");
- if (!constr_file.empty() && liberty_file.empty())
- log_cmd_error("Got -constr but no -liberty!\n");
+ if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty()))
+ log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n");
+ if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty()))
+ log_cmd_error("Got -constr but no -liberty/-genlib!\n");
if (enabled_gates.empty()) {
enabled_gates.insert("AND");
@@ -1854,27 +1867,10 @@ 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,
+ abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress);
continue;
}
@@ -2019,7 +2015,7 @@ struct AbcPass : public Pass {
clk_sig = assign_map(std::get<1>(it.first));
en_polarity = std::get<2>(it.first);
en_sig = assign_map(std::get<3>(it.first));
- abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+ abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress);
assign_map.set(mod);
}
@@ -2028,7 +2024,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 127f8934e..1f00fc3e7 100644
--- a/passes/techmap/abc9.cc
+++ b/passes/techmap/abc9.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* (C) 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -283,9 +283,16 @@ struct Abc9Pass : public ScriptPass
if (check_label("map")) {
if (help_mode)
- run("abc9_ops -prep_hier -prep_bypass [-prep_dff -dff]", "(option if -dff)");
+ run("abc9_ops -prep_hier [-dff]", "(option if -dff)");
else
- run(stringf("abc9_ops -prep_hier -prep_bypass %s", dff_mode ? "-prep_dff -dff" : ""));
+ run(stringf("abc9_ops -prep_hier %s", dff_mode ? "-dff" : ""));
+ run("scc -specify -set_attr abc9_scc_id {}");
+ if (help_mode)
+ run("abc9_ops -prep_bypass [-prep_dff]", "(option if -dff)");
+ else {
+ active_design->scratchpad_unset("abc9_ops.prep_bypass.did_something");
+ run(stringf("abc9_ops -prep_bypass %s", dff_mode ? "-prep_dff" : ""));
+ }
if (dff_mode) {
run("design -copy-to $abc9_map @$abc9_flops", "(only if -dff)");
run("select -unset $abc9_flops", " (only if -dff)");
@@ -294,8 +301,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");
@@ -330,20 +337,20 @@ struct Abc9Pass : public ScriptPass
run("design -stash $abc9_map");
run("design -load $abc9");
run("design -delete $abc9");
+ // Insert bypass modules (and perform +/abc9_map.v transformations), except for those cells part of a SCC
if (help_mode)
run("techmap -wb -max_iter 1 -map %$abc9_map -map +/abc9_map.v [-D DFF]", "(option if -dff)");
else
- run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s", dff_mode ? "-D DFF" : ""));
+ run(stringf("techmap -wb -max_iter 1 -map %%$abc9_map -map +/abc9_map.v %s a:abc9_scc_id %%n", dff_mode ? "-D DFF" : ""));
run("design -delete $abc9_map");
}
if (check_label("pre")) {
run("read_verilog -icells -lib -specify +/abc9_model.v");
- run("scc -set_attr abc9_scc_id {}");
if (help_mode)
- run("abc9_ops -mark_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
+ run("abc9_ops -break_scc -prep_delays -prep_xaiger [-dff]", "(option for -dff)");
else
- run("abc9_ops -mark_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
+ run("abc9_ops -break_scc -prep_delays -prep_xaiger" + std::string(dff_mode ? " -dff" : ""));
if (help_mode)
run("abc9_ops -prep_lut <maxlut>", "(skip if -lut or -luts)");
else if (!lut_mode)
@@ -445,6 +452,9 @@ struct Abc9Pass : public ScriptPass
run("design -delete $abc9_unmap");
if (saved_designs.count("$abc9_holes") || help_mode)
run("design -delete $abc9_holes");
+ if (help_mode || active_design->scratchpad_get_bool("abc9_ops.prep_bypass.did_something"))
+ run("delete =*_$abc9_byp");
+ run("setattr -mod -unset abc9_box_id");
}
}
} Abc9Pass;
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index 7355840aa..a66e95e21 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -379,11 +379,7 @@ struct Abc9ExePass : public Pass {
{
log_header(design, "Executing ABC9_EXE pass (technology mapping using ABC9).\n");
-#ifdef ABCEXTERNAL
- std::string exe_file = ABCEXTERNAL;
-#else
- std::string exe_file = proc_self_dirname() + proc_program_prefix()+ "yosys-abc";
-#endif
+ std::string exe_file = yosys_abc_executable;
std::string script_file, clk_str, box_file, lut_file;
std::string delay_target, lutin_shared = "-S 1", wire_delay;
std::string tempdir_name;
@@ -396,13 +392,6 @@ struct Abc9ExePass : public Pass {
show_tempdir = true;
#endif
-#ifdef _WIN32
-#ifndef ABCEXTERNAL
- if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc.exe"))
- exe_file = proc_self_dirname() + "..\\" + proc_program_prefix() + "yosys-abc";
-#endif
-#endif
-
std::string lut_arg, luts_arg;
exe_file = design->scratchpad_get_string("abc9.exe", exe_file /* inherit default value if not set */);
script_file = design->scratchpad_get_string("abc9.script", script_file);
diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc
index 98d0207c4..29fe74ec7 100644
--- a/passes/techmap/abc9_ops.cc
+++ b/passes/techmap/abc9_ops.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
* 2019 Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -155,21 +155,6 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
r.first->second = new Design;
Design *unmap_design = r.first->second;
- static const pool<IdString> seq_types{
- ID($dff), ID($dffsr), ID($adff),
- ID($dlatch), ID($dlatchsr), ID($sr),
- ID($mem),
- ID($_DFF_N_), ID($_DFF_P_),
- 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_),
- ID($_DLATCH_N_), ID($_DLATCH_P_),
- ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_),
- ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_),
- ID($_SR_NN_), ID($_SR_NP_), ID($_SR_PN_), ID($_SR_PP_)
- };
-
for (auto module : design->selected_modules())
for (auto cell : module->cells()) {
auto inst_module = design->module(cell->type);
@@ -189,16 +174,22 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
derived_type = inst_module->derive(design, cell->parameters);
derived_module = design->module(derived_type);
}
- if (derived_module->get_blackbox_attribute(true /* ignore_wb */))
- continue;
if (derived_module->get_bool_attribute(ID::abc9_flop)) {
if (!dff_mode)
continue;
}
else {
- if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass))
+ if (!derived_module->get_bool_attribute(ID::abc9_box) && !derived_module->get_bool_attribute(ID::abc9_bypass)) {
+ if (unmap_design->module(derived_type)) {
+ // If derived_type is present in unmap_design, it means that it was processed previously, but found to be incompatible -- e.g. if
+ // it contained a non-zero initial state. In this case, continue to replace the cell type/parameters so that it has the same properties
+ // as a compatible type, yet will be safely unmapped later
+ cell->type = derived_type;
+ cell->parameters.clear();
+ }
continue;
+ }
}
if (!unmap_design->module(derived_type)) {
@@ -223,7 +214,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
}
else if (derived_module->get_bool_attribute(ID::abc9_box)) {
for (auto derived_cell : derived_module->cells())
- if (seq_types.count(derived_cell->type)) {
+ if (derived_cell->is_mem_cell() || RTLIL::builtin_ff_cell_types().count(derived_cell->type)) {
derived_module->set_bool_attribute(ID::abc9_box, false);
derived_module->set_bool_attribute(ID::abc9_bypass);
break;
@@ -441,6 +432,8 @@ void prep_bypass(RTLIL::Design *design)
}
}
unmap_module->fixup_ports();
+
+ design->scratchpad_set_bool("abc9_ops.prep_bypass.did_something", true);
}
}
@@ -459,7 +452,14 @@ void prep_dff(RTLIL::Design *design)
if (!inst_module->get_bool_attribute(ID::abc9_flop))
continue;
log_assert(!inst_module->get_blackbox_attribute(true /* ignore_wb */));
- log_assert(cell->parameters.empty());
+ if (!cell->parameters.empty())
+ {
+ // At this stage of the ABC9 flow, cells instantiating (* abc9_flop *) modules must not contain any parameters -- instead it should
+ // be instantiating the derived module which will have had any parameters constant-propagated.
+ // This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design.
+ // Please file a bug report!
+ log_error("Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_flop *)\n", log_id(cell->name), log_id(cell->type));
+ }
modules_sel.select(inst_module);
}
}
@@ -544,18 +544,31 @@ void prep_dff_unmap(RTLIL::Design *design)
}
}
-void mark_scc(RTLIL::Module *module)
+void break_scc(RTLIL::Module *module)
{
// For every unique SCC found, (arbitrarily) find the first
- // cell in the component, and replace its output connections
- // with a new wire driven by the old connection but with a
- // special (* abc9_keep *) attribute set (which is used by
- // write_xaiger to break this wire into PI and POs)
+ // cell in the component, and interrupt all its output connections
+ // with the $__ABC9_SCC_BREAKER cell
+
+ // Do not break SCCs which have a cell instantiating an abc9_bypass-able
+ // module (but which wouldn't have been bypassed)
+ auto design = module->design;
+ pool<RTLIL::Cell*> scc_cells;
pool<RTLIL::Const> ids_seen;
for (auto cell : module->cells()) {
auto it = cell->attributes.find(ID::abc9_scc_id);
if (it == cell->attributes.end())
continue;
+ scc_cells.insert(cell);
+ auto inst_module = design->module(cell->type);
+ if (inst_module && inst_module->has_attribute(ID::abc9_bypass))
+ ids_seen.insert(it->second);
+ }
+
+ SigSpec I, O;
+ for (auto cell : scc_cells) {
+ auto it = cell->attributes.find(ID::abc9_scc_id);
+ log_assert(it != cell->attributes.end());
auto id = it->second;
auto r = ids_seen.insert(id);
cell->attributes.erase(it);
@@ -565,12 +578,21 @@ void mark_scc(RTLIL::Module *module)
if (c.second.is_fully_const()) continue;
if (cell->output(c.first)) {
Wire *w = module->addWire(NEW_ID, GetSize(c.second));
- w->set_bool_attribute(ID::abc9_keep);
- module->connect(w, c.second);
+ I.append(w);
+ O.append(c.second);
c.second = w;
}
}
}
+
+ if (!I.empty())
+ {
+ auto cell = module->addCell(NEW_ID, ID($__ABC9_SCC_BREAKER));
+ log_assert(GetSize(I) == GetSize(O));
+ cell->setParam(ID::WIDTH, GetSize(I));
+ cell->setPort(ID::I, std::move(I));
+ cell->setPort(ID::O, std::move(O));
+ }
}
void prep_delays(RTLIL::Design *design, bool dff_mode)
@@ -626,40 +648,38 @@ void prep_delays(RTLIL::Design *design, bool dff_mode)
auto inst_module = design->module(cell->type);
log_assert(inst_module);
- auto &t = timing.at(cell->type).required;
- for (auto &conn : cell->connections_) {
- auto port_wire = inst_module->wire(conn.first);
+ for (auto &i : timing.at(cell->type).required) {
+ auto port_wire = inst_module->wire(i.first.name);
if (!port_wire)
log_error("Port %s in cell %s (type %s) from module %s does not actually exist",
- log_id(conn.first), log_id(cell), log_id(cell->type), log_id(module));
- if (!port_wire->port_input)
- continue;
- if (conn.second.is_fully_const())
+ log_id(i.first.name), log_id(cell), log_id(cell->type), log_id(module));
+ log_assert(port_wire->port_input);
+
+ auto d = i.second.first;
+ if (d == 0)
continue;
- SigSpec O = module->addWire(NEW_ID, GetSize(conn.second));
- for (int i = 0; i < GetSize(conn.second); i++) {
- auto d = t.at(TimingInfo::NameBit(conn.first,i), 0);
- if (d == 0)
- continue;
+ auto offset = i.first.offset;
+ auto O = module->addWire(NEW_ID);
+ auto rhs = cell->getPort(i.first.name);
#ifndef NDEBUG
- if (ys_debug(1)) {
- static std::set<std::tuple<IdString,IdString,int>> seen;
- if (seen.emplace(cell->type, conn.first, i).second) log("%s.%s[%d] abc9_required = %d\n",
- log_id(cell->type), log_id(conn.first), i, d);
- }
+ if (ys_debug(1)) {
+ static pool<std::pair<IdString,TimingInfo::NameBit>> seen;
+ if (seen.emplace(cell->type, i.first).second) log("%s.%s[%d] abc9_required = %d\n",
+ log_id(cell->type), log_id(i.first.name), offset, d);
+ }
#endif
- auto r = box_cache.insert(d);
- if (r.second) {
- r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
- log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
- }
- auto box = module->addCell(NEW_ID, r.first->second);
- box->setPort(ID::I, conn.second[i]);
- box->setPort(ID::O, O[i]);
- conn.second[i] = O[i];
+ auto r = box_cache.insert(d);
+ if (r.second) {
+ r.first->second = delay_module->derive(design, {{ID::DELAY, d}});
+ log_assert(r.first->second.begins_with("$paramod$__ABC9_DELAY\\DELAY="));
}
+ auto box = module->addCell(NEW_ID, r.first->second);
+ box->setPort(ID::I, rhs[offset]);
+ box->setPort(ID::O, O);
+ rhs[offset] = O;
+ cell->setPort(i.first.name, rhs);
}
}
}
@@ -721,10 +741,8 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
bit_users[bit].insert(cell->name);
if (cell->output(conn.first) && !abc9_flop)
- for (const auto &chunk : conn.second.chunks())
- if (!chunk.wire->get_bool_attribute(ID::abc9_keep))
- for (auto b : sigmap(SigSpec(chunk)))
- bit_drivers[b].insert(cell->name);
+ for (auto bit : sigmap(conn.second))
+ bit_drivers[bit].insert(cell->name);
}
toposort.node(cell->name);
}
@@ -778,7 +796,14 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
continue;
if (!box_module->get_bool_attribute(ID::abc9_box))
continue;
- log_assert(cell->parameters.empty());
+ if (!cell->parameters.empty())
+ {
+ // At this stage of the ABC9 flow, cells instantiating (* abc9_box *) modules must not contain any parameters -- instead it should
+ // be instantiating the derived module which will have had any parameters constant-propagated.
+ // This task is expected to be performed by `abc9_ops -prep_hier`, but it looks like it failed to do so for this design.
+ // Please file a bug report!
+ log_error("Not expecting parameters on cell '%s' instantiating module '%s' marked (* abc9_box *)\n", log_id(cell_name), log_id(cell->type));
+ }
log_assert(box_module->get_blackbox_attribute());
cell->attributes[ID::abc9_box_seq] = box_count++;
@@ -787,7 +812,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff)
auto &holes_cell = r.first->second;
if (r.second) {
if (box_module->get_bool_attribute(ID::whitebox)) {
- holes_cell = holes_module->addCell(cell->name, cell->type);
+ holes_cell = holes_module->addCell(NEW_ID, cell->type);
if (box_module->has_processes())
Pass::call_on_module(design, box_module, "proc");
@@ -917,15 +942,8 @@ void prep_box(RTLIL::Design *design)
{
TimingInfo timing;
- std::stringstream ss;
int abc9_box_id = 1;
- for (auto module : design->modules()) {
- auto it = module->attributes.find(ID::abc9_box_id);
- if (it == module->attributes.end())
- continue;
- abc9_box_id = std::max(abc9_box_id, it->second.as_int());
- }
-
+ std::stringstream ss;
dict<IdString,std::vector<IdString>> box_ports;
for (auto module : design->modules()) {
auto it = module->attributes.find(ID::abc9_box);
@@ -986,16 +1004,16 @@ void prep_box(RTLIL::Design *design)
log_assert(GetSize(wire) == 1);
auto it = t.find(TimingInfo::NameBit(port_name,0));
if (it == t.end())
- // Assume no connectivity if no setup time
- ss << "-";
+ // Assume that no setup time means zero
+ ss << 0;
else {
- ss << it->second;
+ ss << it->second.first;
#ifndef NDEBUG
if (ys_debug(1)) {
static std::set<std::pair<IdString,IdString>> seen;
if (seen.emplace(module->name, port_name).second) log("%s.%s abc9_required = %d\n", log_id(module),
- log_id(port_name), it->second);
+ log_id(port_name), it->second.first);
}
#endif
}
@@ -1416,7 +1434,6 @@ void reintegrate(RTLIL::Module *module, bool dff_mode)
RTLIL::Wire *mapped_wire = mapped_mod->wire(port);
RTLIL::Wire *wire = module->wire(port);
log_assert(wire);
- wire->attributes.erase(ID::abc9_keep);
RTLIL::Wire *remap_wire = module->wire(remap_name(port));
RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire));
@@ -1579,11 +1596,11 @@ struct Abc9OpsPass : public Pass {
log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n");
log(" certain required times.\n");
log("\n");
- log(" -mark_scc\n");
+ log(" -break_scc\n");
log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n");
- log(" (tagged with an (* abc9_scc_id = <int> *) attribute), temporarily mark all\n");
- log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n");
- log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n");
+ log(" (tagged with an (* abc9_scc_id = <int> *) attribute) interrupt all wires\n");
+ log(" driven by this cell's outputs with a temporary $__ABC9_SCC_BREAKER cell\n");
+ log(" to break the SCC.\n");
log("\n");
log(" -prep_xaiger\n");
log(" prepare the design for XAIGER output. this includes computing the\n");
@@ -1620,7 +1637,7 @@ struct Abc9OpsPass : public Pass {
bool check_mode = false;
bool prep_delays_mode = false;
- bool mark_scc_mode = false;
+ bool break_scc_mode = false;
bool prep_hier_mode = false;
bool prep_bypass_mode = false;
bool prep_dff_mode = false, prep_dff_submod_mode = false, prep_dff_unmap_mode = false;
@@ -1642,8 +1659,8 @@ struct Abc9OpsPass : public Pass {
valid = true;
continue;
}
- if (arg == "-mark_scc") {
- mark_scc_mode = true;
+ if (arg == "-break_scc") {
+ break_scc_mode = true;
valid = true;
continue;
}
@@ -1719,7 +1736,7 @@ struct Abc9OpsPass : public Pass {
extra_args(args, argidx, design);
if (!valid)
- log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
+ log_cmd_error("At least one of -check, -break_scc, -prep_{delays,xaiger,dff[123],lut,box}, -write_{lut,box}, -reintegrate must be specified.\n");
if (dff_mode && !check_mode && !prep_hier_mode && !prep_delays_mode && !prep_xaiger_mode && !reintegrate_mode)
log_cmd_error("'-dff' option is only relevant for -prep_{hier,delay,xaiger} or -reintegrate.\n");
@@ -1756,8 +1773,8 @@ struct Abc9OpsPass : public Pass {
write_lut(mod, write_lut_dst);
if (!write_box_dst.empty())
write_box(mod, write_box_dst);
- if (mark_scc_mode)
- mark_scc(mod);
+ if (break_scc_mode)
+ break_scc(mod);
if (prep_xaiger_mode)
prep_xaiger(mod, dff_mode);
if (reintegrate_mode)
diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc
index ce151c7f3..4836ebe34 100644
--- a/passes/techmap/aigmap.cc
+++ b/passes/techmap/aigmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc
index b16e9750e..e4e70004c 100644
--- a/passes/techmap/alumacc.cc
+++ b/passes/techmap/alumacc.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc
index 8643543c8..96e65ff2e 100644
--- a/passes/techmap/attrmap.cc
+++ b/passes/techmap/attrmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc
index b3202c587..65b63daf1 100644
--- a/passes/techmap/attrmvcp.cc
+++ b/passes/techmap/attrmvcp.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/bmuxmap.cc b/passes/techmap/bmuxmap.cc
new file mode 100644
index 000000000..03673c278
--- /dev/null
+++ b/passes/techmap/bmuxmap.cc
@@ -0,0 +1,76 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct BmuxmapPass : public Pass {
+ BmuxmapPass() : Pass("bmuxmap", "transform $bmux cells to trees of $mux cells") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" bmuxmap [selection]\n");
+ log("\n");
+ log("This pass transforms $bmux cells to trees of $mux cells.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing BMUXMAP pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != ID($bmux))
+ continue;
+
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ int width = GetSize(cell->getPort(ID::Y));
+
+ for (int idx = 0; idx < GetSize(sel); idx++) {
+ SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+ for (int i = 0; i < GetSize(new_data); i += width) {
+ RTLIL::Cell *mux = module->addMux(NEW_ID,
+ data.extract(i*2, width),
+ data.extract(i*2+width, width),
+ sel[idx],
+ new_data.extract(i, width));
+ mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ }
+ data = new_data;
+ }
+
+ module->connect(cell->getPort(ID::Y), data);
+ module->remove(cell);
+ }
+ }
+} BmuxmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc
index 451325fee..a7b96a9c6 100644
--- a/passes/techmap/clkbufmap.cc
+++ b/passes/techmap/clkbufmap.cc
@@ -1,8 +1,8 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
+ * 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") { }
+ 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) {
@@ -78,7 +79,7 @@ struct ClkbufmapPass : public Pass {
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 9a23cb90e..5245331f8 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/demuxmap.cc b/passes/techmap/demuxmap.cc
new file mode 100644
index 000000000..292b18bad
--- /dev/null
+++ b/passes/techmap/demuxmap.cc
@@ -0,0 +1,80 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2022 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct DemuxmapPass : public Pass {
+ DemuxmapPass() : Pass("demuxmap", "transform $demux cells to $eq + $mux cells") { }
+ void help() override
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" demuxmap [selection]\n");
+ log("\n");
+ log("This pass transforms $demux cells to a bunch of equality comparisons.\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) override
+ {
+ log_header(design, "Executing DEMUXMAP pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type != ID($demux))
+ continue;
+
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ SigSpec out = cell->getPort(ID::Y);
+ int width = GetSize(cell->getPort(ID::A));
+
+ for (int i = 0; i < 1 << GetSize(sel); i++) {
+ if (width == 1 && data == State::S1) {
+ RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), out[i]);
+ eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ } else {
+ Wire *eq = module->addWire(NEW_ID);
+ RTLIL::Cell *eq_cell = module->addEq(NEW_ID, sel, Const(i, GetSize(sel)), eq);
+ eq_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ RTLIL::Cell *mux = module->addMux(NEW_ID,
+ Const(State::S0, width),
+ data,
+ eq,
+ out.extract(i*width, width));
+ mux->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ }
+ }
+
+ module->remove(cell);
+ }
+ }
+} DemuxmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
deleted file mode 100644
index 62ee3fea6..000000000
--- a/passes/techmap/dff2dffe.cc
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
- * 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/celltypes.h"
-#include "passes/techmap/simplemap.h"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Dff2dffeWorker
-{
- const dict<IdString, IdString> &direct_dict;
-
- RTLIL::Module *module;
- SigMap sigmap;
- CellTypes ct;
-
- typedef std::pair<RTLIL::Cell*, int> cell_int_t;
- std::map<RTLIL::SigBit, cell_int_t> bit2mux;
- std::vector<RTLIL::Cell*> dff_cells;
- std::map<RTLIL::SigBit, int> bitusers;
-
- typedef std::map<RTLIL::SigBit, bool> pattern_t;
- typedef std::set<pattern_t> patterns_t;
-
-
- Dff2dffeWorker(RTLIL::Module *module, const dict<IdString, IdString> &direct_dict) :
- direct_dict(direct_dict), module(module), sigmap(module), ct(module->design)
- {
- for (auto wire : module->wires()) {
- if (wire->port_output)
- for (auto bit : sigmap(wire))
- bitusers[bit]++;
- }
-
- for (auto cell : module->cells()) {
- if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) {
- RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y));
- for (int i = 0; i < GetSize(sig_y); i++)
- bit2mux[sig_y[i]] = cell_int_t(cell, i);
- }
- if (direct_dict.empty()) {
- if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_)))
- dff_cells.push_back(cell);
- } else {
- if (direct_dict.count(cell->type))
- dff_cells.push_back(cell);
- }
- for (auto conn : cell->connections()) {
- if (ct.cell_output(cell->type, conn.first))
- continue;
- for (auto bit : sigmap(conn.second))
- bitusers[bit]++;
- }
- }
- }
-
- patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path)
- {
- patterns_t ret;
-
- if (d == q) {
- ret.insert(path);
- return ret;
- }
-
- if (bit2mux.count(d) == 0 || bitusers[d] > 1)
- return ret;
-
- cell_int_t mux_cell_int = bit2mux.at(d);
- RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A));
- RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B));
- RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID::S));
- int width = GetSize(sig_a), index = mux_cell_int.second;
-
- for (int i = 0; i < GetSize(sig_s); i++)
- if (path.count(sig_s[i]) && path.at(sig_s[i]))
- {
- ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path);
-
- if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
- s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::B, s);
- }
-
- return ret;
- }
-
- pattern_t path_else = path;
-
- for (int i = 0; i < GetSize(sig_s); i++)
- {
- if (path.count(sig_s[i]))
- continue;
-
- pattern_t path_this = path;
- path_else[sig_s[i]] = false;
- path_this[sig_s[i]] = true;
-
- for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this))
- ret.insert(pat);
-
- if (sig_b[i*width + index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B);
- s[i*width + index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::B, s);
- }
- }
-
- for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else))
- ret.insert(pat);
-
- if (sig_a[index] == q) {
- RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A);
- s[index] = RTLIL::Sx;
- mux_cell_int.first->setPort(ID::A, s);
- }
-
- return ret;
- }
-
- void simplify_patterns(patterns_t&)
- {
- // TBD
- }
-
- RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates)
- {
- RTLIL::SigSpec or_input;
-
- for (auto pat : patterns)
- {
- RTLIL::SigSpec s1, s2;
- for (auto it : pat) {
- s1.append(it.first);
- s2.append(it.second);
- }
-
- RTLIL::SigSpec y = module->addWire(NEW_ID);
- RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y);
-
- if (make_gates) {
- simplemap(module, c);
- module->remove(c);
- }
-
- or_input.append(y);
- }
-
- if (GetSize(or_input) == 0)
- return State::S1;
-
- if (GetSize(or_input) == 1)
- return or_input;
-
- RTLIL::SigSpec y = module->addWire(NEW_ID);
- RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y);
-
- if (make_gates) {
- simplemap(module, c);
- module->remove(c);
- }
-
- return y;
- }
-
- void handle_dff_cell(RTLIL::Cell *dff_cell)
- {
- RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID::D));
- RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID::Q));
-
- std::map<patterns_t, std::set<int>> grouped_patterns;
- std::set<int> remaining_indices;
-
- for (int i = 0 ; i < GetSize(sig_d); i++) {
- patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t());
- if (!patterns.empty()) {
- simplify_patterns(patterns);
- grouped_patterns[patterns].insert(i);
- } else
- remaining_indices.insert(i);
- }
-
- for (auto &it : grouped_patterns) {
- RTLIL::SigSpec new_sig_d, new_sig_q;
- for (int i : it.second) {
- new_sig_d.append(sig_d[i]);
- new_sig_q.append(sig_q[i]);
- }
- if (!direct_dict.empty()) {
- log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q));
- dff_cell->setPort(ID::E, make_patterns_logic(it.first, true));
- dff_cell->type = direct_dict.at(dff_cell->type);
- } else
- if (dff_cell->type == ID($dff)) {
- RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID::CLK), make_patterns_logic(it.first, false),
- new_sig_d, new_sig_q, dff_cell->getParam(ID::CLK_POLARITY).as_bool(), true);
- log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
- } else {
- RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID::C), make_patterns_logic(it.first, true),
- new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true);
- log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q));
- }
- }
-
- if (!direct_dict.empty())
- return;
-
- if (remaining_indices.empty()) {
- log(" removing now obsolete cell %s.\n", log_id(dff_cell));
- module->remove(dff_cell);
- } else if (GetSize(remaining_indices) != GetSize(sig_d)) {
- log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell));
- RTLIL::SigSpec new_sig_d, new_sig_q;
- for (int i : remaining_indices) {
- new_sig_d.append(sig_d[i]);
- new_sig_q.append(sig_q[i]);
- }
- dff_cell->setPort(ID::D, new_sig_d);
- dff_cell->setPort(ID::Q, new_sig_q);
- dff_cell->setParam(ID::WIDTH, GetSize(remaining_indices));
- }
- }
-
- void run()
- {
- log("Transforming FF to FF+Enable cells in module %s:\n", log_id(module));
- for (auto dff_cell : dff_cells) {
- // log("Handling candidate %s:\n", log_id(dff_cell));
- handle_dff_cell(dff_cell);
- }
- }
-};
-
-struct Dff2dffePass : public Pass {
- Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { }
- void help() override
- {
- // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
- log("\n");
- log(" dff2dffe [options] [selection]\n");
- log("\n");
- log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n");
- log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n");
- log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n");
- log("\n");
- log(" -unmap\n");
- log(" operate in the opposite direction: replace $dffe cells with combinations\n");
- log(" of $dff and $mux cells. the options below are ignored in unmap mode.\n");
- log("\n");
- log(" -unmap-mince N\n");
- log(" Same as -unmap but only unmap $dffe where the clock enable port\n");
- log(" signal is used by less $dffe than the specified number\n");
- log("\n");
- log(" -direct <internal_gate_type> <external_gate_type>\n");
- log(" map directly to external gate type. <internal_gate_type> can\n");
- log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n");
- log(" <external_gate_type> is the cell type name for a cell with an\n");
- log(" identical interface to the <internal_gate_type>, except it\n");
- log(" also has an high-active enable port 'E'.\n");
- log(" Usually <external_gate_type> is an intermediate cell type\n");
- log(" that is then translated to the final type using 'techmap'.\n");
- 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 $_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) override
- {
- log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n");
-
- bool unmap_mode = false;
- int min_ce_use = -1;
- dict<IdString, IdString> direct_dict;
-
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++) {
- if (args[argidx] == "-unmap") {
- unmap_mode = true;
- continue;
- }
- if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) {
- unmap_mode = true;
- min_ce_use = atoi(args[++argidx].c_str());
- continue;
- }
- if (args[argidx] == "-direct" && argidx + 2 < args.size()) {
- string direct_from = RTLIL::escape_id(args[++argidx]);
- string direct_to = RTLIL::escape_id(args[++argidx]);
- direct_dict[direct_from] = direct_to;
- continue;
- }
- if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) {
- bool found_match = false;
- 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_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;
- }
- break;
- }
- extra_args(args, argidx, design);
-
- if (!direct_dict.empty()) {
- log("Selected cell types for direct conversion:\n");
- for (auto &it : direct_dict)
- log(" %s -> %s\n", log_id(it.first), log_id(it.second));
- }
-
- for (auto mod : design->selected_modules())
- if (!mod->has_processes_warn())
- {
- if (unmap_mode) {
- SigMap sigmap(mod);
- for (auto cell : mod->selected_cells()) {
- if (cell->type == ID($dffe)) {
- if (min_ce_use >= 0) {
- int ce_use = 0;
- for (auto cell_other : mod->selected_cells()) {
- if (cell_other->type != cell->type)
- continue;
- if (sigmap(cell->getPort(ID::EN)) == sigmap(cell_other->getPort(ID::EN)))
- ce_use++;
- }
- if (ce_use >= min_ce_use)
- continue;
- }
-
- RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID::D)));
- mod->addDff(NEW_ID, cell->getPort(ID::CLK), tmp, cell->getPort(ID::Q), cell->getParam(ID::CLK_POLARITY).as_bool());
- if (cell->getParam(ID::EN_POLARITY).as_bool())
- mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::EN), tmp);
- else
- mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::EN), tmp);
- mod->remove(cell);
- continue;
- }
- if (cell->type.begins_with("$_DFFE_")) {
- if (min_ce_use >= 0) {
- int ce_use = 0;
- for (auto cell_other : mod->selected_cells()) {
- if (cell_other->type != cell->type)
- continue;
- if (sigmap(cell->getPort(ID::E)) == sigmap(cell_other->getPort(ID::E)))
- ce_use++;
- }
- if (ce_use >= min_ce_use)
- continue;
- }
-
- bool clk_pol = cell->type.compare(7, 1, "P") == 0;
- bool en_pol = cell->type.compare(8, 1, "P") == 0;
- RTLIL::SigSpec tmp = mod->addWire(NEW_ID);
- mod->addDff(NEW_ID, cell->getPort(ID::C), tmp, cell->getPort(ID::Q), clk_pol);
- if (en_pol)
- mod->addMux(NEW_ID, cell->getPort(ID::Q), cell->getPort(ID::D), cell->getPort(ID::E), tmp);
- else
- mod->addMux(NEW_ID, cell->getPort(ID::D), cell->getPort(ID::Q), cell->getPort(ID::E), tmp);
- mod->remove(cell);
- continue;
- }
- }
- continue;
- }
-
- Dff2dffeWorker worker(mod, direct_dict);
- worker.run();
- }
- }
-} Dff2dffePass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
deleted file mode 100644
index 6c2cca4bc..000000000
--- a/passes/techmap/dff2dffs.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * yosys -- Yosys Open SYnthesis Suite
- *
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2018 David Shah <dave@ds0.me>
- *
- * 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"
-
-USING_YOSYS_NAMESPACE
-PRIVATE_NAMESPACE_BEGIN
-
-struct Dff2dffsPass : public Pass {
- Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
- void help() override
- {
- log("\n");
- log(" dff2dffs [options] [selection]\n");
- log("\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");
- log(" Disallow merging synchronous set/reset that has polarity opposite of the\n");
- log(" output wire's init attribute (if any).\n");
- log("\n");
- }
- 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");
-
- bool match_init = false;
- size_t argidx;
- for (argidx = 1; argidx < args.size(); argidx++)
- {
- // if (args[argidx] == "-singleton") {
- // singleton_mode = true;
- // continue;
- // }
- if (args[argidx] == "-match-init") {
- match_init = true;
- continue;
- }
- break;
- }
- extra_args(args, argidx, design);
-
- pool<IdString> dff_types;
- dff_types.insert(ID($_DFF_N_));
- dff_types.insert(ID($_DFF_P_));
-
- for (auto module : design->selected_modules())
- {
- log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
-
- SigMap sigmap(module);
- dict<SigBit, Cell*> sr_muxes;
- vector<Cell*> ff_cells;
-
- for (auto cell : module->selected_cells())
- {
- if (dff_types.count(cell->type)) {
- ff_cells.push_back(cell);
- continue;
- }
-
- if (cell->type != ID($_MUX_))
- continue;
-
- SigBit bit_a = sigmap(cell->getPort(ID::A));
- SigBit bit_b = sigmap(cell->getPort(ID::B));
-
- if (bit_a.wire == nullptr || bit_b.wire == nullptr)
- sr_muxes[sigmap(cell->getPort(ID::Y))] = cell;
- }
-
- for (auto cell : ff_cells)
- {
- SigSpec sig_d = cell->getPort(ID::D);
-
- if (GetSize(sig_d) < 1)
- continue;
-
- SigBit bit_d = sigmap(sig_d[0]);
-
- if (sr_muxes.count(bit_d) == 0)
- continue;
-
- Cell *mux_cell = sr_muxes.at(bit_d);
- SigBit bit_a = sigmap(mux_cell->getPort(ID::A));
- SigBit bit_b = sigmap(mux_cell->getPort(ID::B));
- SigBit bit_s = sigmap(mux_cell->getPort(ID::S));
-
- SigBit sr_val, sr_sig;
- bool invert_sr;
- sr_sig = bit_s;
- if (bit_a.wire == nullptr) {
- bit_d = bit_b;
- sr_val = bit_a;
- invert_sr = true;
- } else {
- log_assert(bit_b.wire == nullptr);
- bit_d = bit_a;
- sr_val = bit_b;
- invert_sr = false;
- }
-
- if (match_init) {
- SigBit bit_q = cell->getPort(ID::Q);
- if (bit_q.wire) {
- auto it = bit_q.wire->attributes.find(ID::init);
- if (it != bit_q.wire->attributes.end()) {
- auto init_val = it->second[bit_q.offset];
- if (init_val == State::S1 && sr_val != State::S1)
- continue;
- if (init_val == State::S0 && sr_val != State::S0)
- continue;
- }
- }
- }
-
- log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
- log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
-
- if (sr_val == State::S1) {
- if (cell->type == ID($_DFF_N_)) {
- 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($_SDFF_PN1_);
- else cell->type = ID($_SDFF_PP1_);
- }
- } else {
- if (cell->type == ID($_DFF_N_)) {
- 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($_SDFF_PN0_);
- else cell->type = ID($_SDFF_PP0_);
- }
- }
- cell->setPort(ID::R, sr_sig);
- cell->setPort(ID::D, bit_d);
- }
- }
- }
-} Dff2dffsPass;
-
-PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc
index c60a901c1..9cfe55947 100644
--- a/passes/techmap/dffinit.cc
+++ b/passes/techmap/dffinit.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -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..1d99caa3a
--- /dev/null
+++ b/passes/techmap/dfflegalize.cc
@@ -0,0 +1,1235 @@
+/*
+ * 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"
+#include "kernel/ff.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+enum FfType {
+ FF_DFF,
+ FF_DFFE,
+ FF_ADFF,
+ FF_ADFFE,
+ FF_ALDFF,
+ FF_ALDFFE,
+ FF_DFFSR,
+ FF_DFFSRE,
+ FF_SDFF,
+ FF_SDFFE,
+ FF_SDFFCE,
+ FF_RLATCH,
+ FF_SR,
+ FF_DLATCH,
+ FF_ADLATCH,
+ FF_DLATCHSR,
+ NUM_FFTYPES,
+};
+
+enum FfNeg {
+ NEG_CE = 0x1,
+ NEG_R = 0x2,
+ NEG_S = 0x4,
+ NEG_L = 0x8,
+ NEG_C = 0x10,
+ NUM_NEG = 0x20,
+};
+
+enum FfInit {
+ INIT_X = 0x1,
+ INIT_0 = 0x2,
+ INIT_1 = 0x4,
+ INIT_X_R0 = 0x10,
+ INIT_0_R0 = 0x20,
+ INIT_1_R0 = 0x40,
+ INIT_X_R1 = 0x100,
+ INIT_0_R1 = 0x200,
+ INIT_1_R1 = 0x400,
+};
+
+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("- $_ALDFF_[NP][NP]_\n");
+ log("- $_ALDFFE_[NP][NP][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 *dffe* cells.
+ int supported_dffe;
+ // Aggregated for all dffsr* cells.
+ int supported_dffsr;
+ // Aggregated for all aldff cells.
+ int supported_aldff;
+ // Aggregated for all aldffe cells.
+ int supported_aldffe;
+ // Aggregated for all adff* cells and trivial emulations.
+ int supported_adff;
+ // Aggregated for all adffe* cells and trivial emulations.
+ int supported_adffe;
+ // Aggregated for all sdff* cells.
+ int supported_sdff;
+ // Aggregated for all ways to obtain a SR latch.
+ int supported_sr;
+ int supported_sr_plain;
+ // Aggregated for all *dlatch* cells.
+ int supported_dlatch;
+ int supported_dlatch_plain;
+ // Aggregated for all ways to obtain an R latch.
+ int supported_rlatch;
+ // Aggregated for all adlatch cells and trivial emulations.
+ int supported_adlatch;
+
+ 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;
+ if (mask & INIT_X_R0)
+ res |= INIT_X_R1;
+ if (mask & INIT_0_R0)
+ res |= INIT_1_R1;
+ if (mask & INIT_1_R0)
+ res |= INIT_0_R1;
+ if (mask & INIT_X_R1)
+ res |= INIT_X_R0;
+ if (mask & INIT_0_R1)
+ res |= INIT_1_R0;
+ if (mask & INIT_1_R1)
+ res |= INIT_0_R0;
+ return res;
+ }
+
+ int get_ff_type(const FfData &ff) {
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ return ff.has_ce ? FF_DFFSRE : FF_DFFSR;
+ } else if (ff.has_arst) {
+ return ff.has_ce ? FF_ADFFE : FF_ADFF;
+ } else if (ff.has_aload) {
+ return ff.has_ce ? FF_ALDFFE : FF_ALDFF;
+ } else if (ff.has_srst) {
+ if (ff.has_ce)
+ return ff.ce_over_srst ? FF_SDFFCE : FF_SDFFE;
+ else
+ return FF_SDFF;
+ } else {
+ return ff.has_ce ? FF_DFFE : FF_DFF;
+ }
+ } else {
+ if (ff.has_aload) {
+ if (ff.has_sr)
+ return FF_DLATCHSR;
+ else if (ff.has_arst)
+ return FF_ADLATCH;
+ else
+ return FF_DLATCH;
+ } else {
+ if (ff.has_sr) {
+ return FF_SR;
+ } else if (ff.has_arst) {
+ return FF_RLATCH;
+ } else {
+ log_assert(0);
+ return 0;
+ }
+ }
+ }
+ }
+
+ int get_initmask(FfData &ff) {
+ int res = 0;
+ if (ff.val_init[0] == State::S0)
+ res = INIT_0;
+ else if (ff.val_init[0] == State::S1)
+ res = INIT_1;
+ else
+ res = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_arst[0] == State::S1)
+ res <<= 8;
+ } else if (ff.has_srst) {
+ if (ff.val_srst[0] == State::S0)
+ res <<= 4;
+ else if (ff.val_srst[0] == State::S1)
+ res <<= 8;
+ }
+ return res;
+ }
+
+ void fail_ff(const FfData &ff, const char *reason) {
+ log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(ff.module->name), log_id(ff.cell->name), log_id(ff.cell->type), reason);
+ }
+
+ bool try_flip(FfData &ff, int supported_mask) {
+ int initmask = get_initmask(ff);
+ if (supported_mask & initmask)
+ return true;
+ if (supported_mask & flip_initmask(initmask)) {
+ ff.flip_bits({0});
+ return true;
+ }
+ return false;
+ }
+
+ void emulate_split_init_arst(FfData &ff) {
+ ff.remove();
+
+ FfData ff_dff(ff.module, &initvals, NEW_ID);
+ ff_dff.width = ff.width;
+ ff_dff.has_aload = ff.has_aload;
+ ff_dff.sig_aload = ff.sig_aload;
+ ff_dff.pol_aload = ff.pol_aload;
+ ff_dff.sig_ad = ff.sig_ad;
+ ff_dff.has_clk = ff.has_clk;
+ ff_dff.sig_clk = ff.sig_clk;
+ ff_dff.pol_clk = ff.pol_clk;
+ ff_dff.sig_d = ff.sig_d;
+ ff_dff.has_ce = ff.has_ce;
+ ff_dff.sig_ce = ff.sig_ce;
+ ff_dff.pol_ce = ff.pol_ce;
+ ff_dff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_dff.val_init = ff.val_init;
+ ff_dff.is_fine = ff.is_fine;
+
+ FfData ff_adff(ff.module, &initvals, NEW_ID);
+ ff_adff.width = ff.width;
+ ff_adff.has_aload = ff.has_aload;
+ ff_adff.sig_aload = ff.sig_aload;
+ ff_adff.pol_aload = ff.pol_aload;
+ ff_adff.sig_ad = ff.sig_ad;
+ ff_adff.has_clk = ff.has_clk;
+ ff_adff.sig_clk = ff.sig_clk;
+ ff_adff.pol_clk = ff.pol_clk;
+ ff_adff.sig_d = ff.sig_d;
+ ff_adff.has_ce = ff.has_ce;
+ ff_adff.sig_ce = ff.sig_ce;
+ ff_adff.pol_ce = ff.pol_ce;
+ ff_adff.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_adff.val_init = Const(State::Sx, ff.width);
+ ff_adff.has_arst = true;
+ ff_adff.sig_arst = ff.sig_arst;
+ ff_adff.pol_arst = ff.pol_arst;
+ ff_adff.val_arst = ff.val_arst;
+ ff_adff.is_fine = ff.is_fine;
+
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = 1;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID);
+ ff_sel.has_arst = true;
+ ff_sel.sig_arst = ff.sig_arst;
+ ff_sel.pol_arst = ff.pol_arst;
+ ff_sel.val_arst = State::S1;
+ ff_sel.val_init = State::S0;
+ ff_sel.is_fine = ff.is_fine;
+
+ if (ff.is_fine)
+ ff.module->addMuxGate(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMux(NEW_ID, ff_dff.sig_q, ff_adff.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_dff);
+ legalize_ff(ff_adff);
+ legalize_ff(ff_sel);
+ }
+
+ void emulate_split_set_clr(FfData &ff) {
+ // No native DFFSR. However, if we can conjure
+ // a SR latch and ADFF, it can still be emulated.
+ int initmask = get_initmask(ff);
+ int flipmask = flip_initmask(initmask);
+ bool init_clr = true;
+ bool init_set = true;
+ State initsel = State::Sx;
+ int supported_arst = ff.has_clk ? supported_adff : supported_adlatch;
+ bool init_clr_ok = (supported_arst & initmask << 4) || (supported_arst & flipmask << 8);
+ bool init_set_ok = (supported_arst & initmask << 8) || (supported_arst & flipmask << 4);
+ if (init_clr_ok && init_set_ok && supported_sr) {
+ // OK
+ } else if (init_clr_ok && (supported_sr & INIT_0)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_1)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else if (init_clr_ok && (supported_sr & INIT_1)) {
+ init_set = false;
+ initsel = State::S0;
+ } else if (init_set_ok && (supported_sr & INIT_0)) {
+ init_clr = false;
+ initsel = State::S1;
+ } else {
+ if (ff.has_clk) {
+ if (!supported_dffsr)
+ fail_ff(ff, "dffs with async set and reset are not supported");
+ else
+ fail_ff(ff, "initialized dffs with async set and reset are not supported");
+ } else {
+ if (!supported_cells[FF_DLATCHSR])
+ fail_ff(ff, "dlatch with async set and reset are not supported");
+ else
+ fail_ff(ff, "initialized dlatch with async set and reset are not supported");
+ }
+ }
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
+
+ log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+
+ log_assert(ff.width == 1);
+ ff.remove();
+
+ FfData ff_clr(ff.module, &initvals, NEW_ID);
+ ff_clr.width = ff.width;
+ ff_clr.has_aload = ff.has_aload;
+ ff_clr.sig_aload = ff.sig_aload;
+ ff_clr.pol_aload = ff.pol_aload;
+ ff_clr.sig_ad = ff.sig_ad;
+ ff_clr.has_clk = ff.has_clk;
+ ff_clr.sig_clk = ff.sig_clk;
+ ff_clr.pol_clk = ff.pol_clk;
+ ff_clr.sig_d = ff.sig_d;
+ ff_clr.has_ce = ff.has_ce;
+ ff_clr.sig_ce = ff.sig_ce;
+ ff_clr.pol_ce = ff.pol_ce;
+ ff_clr.has_arst = true;
+ ff_clr.sig_arst = ff.sig_clr;
+ ff_clr.pol_arst = ff.pol_clr;
+ ff_clr.val_arst = Const(State::S0, ff.width);
+ ff_clr.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_clr.val_init = init_clr ? ff.val_init : Const(State::Sx, ff.width);
+ ff_clr.is_fine = ff.is_fine;
+
+ FfData ff_set(ff.module, &initvals, NEW_ID);
+ ff_set.width = ff.width;
+ ff_set.has_aload = ff.has_aload;
+ ff_set.sig_aload = ff.sig_aload;
+ ff_set.pol_aload = ff.pol_aload;
+ ff_set.sig_ad = ff.sig_ad;
+ ff_set.has_clk = ff.has_clk;
+ ff_set.sig_clk = ff.sig_clk;
+ ff_set.pol_clk = ff.pol_clk;
+ ff_set.sig_d = ff.sig_d;
+ ff_set.has_ce = ff.has_ce;
+ ff_set.sig_ce = ff.sig_ce;
+ ff_set.pol_ce = ff.pol_ce;
+ ff_set.has_arst = true;
+ ff_set.sig_arst = ff.sig_set;
+ ff_set.pol_arst = ff.pol_set;
+ ff_set.val_arst = Const(State::S1, ff.width);
+ ff_set.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_set.val_init = init_set ? ff.val_init : Const(State::Sx, ff.width);
+ ff_set.is_fine = ff.is_fine;
+
+ FfData ff_sel(ff.module, &initvals, NEW_ID);
+ ff_sel.width = ff.width;
+ ff_sel.has_sr = true;
+ ff_sel.pol_clr = ff.pol_clr;
+ ff_sel.pol_set = ff.pol_set;
+ ff_sel.sig_clr = ff.sig_clr;
+ ff_sel.sig_set = ff.sig_set;
+ ff_sel.sig_q = ff.module->addWire(NEW_ID, ff.width);
+ ff_sel.val_init = Const(initsel, ff.width);
+ ff_sel.is_fine = ff.is_fine;
+
+ if (!ff.is_fine)
+ ff.module->addMux(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+ else
+ ff.module->addMuxGate(NEW_ID, ff_clr.sig_q, ff_set.sig_q, ff_sel.sig_q, ff.sig_q);
+
+ legalize_ff(ff_clr);
+ legalize_ff(ff_set);
+ legalize_ff(ff_sel);
+ }
+
+ void legalize_dff(FfData &ff) {
+ if (!try_flip(ff, supported_dff)) {
+ if (!supported_dff)
+ fail_ff(ff, "D flip-flops are not supported");
+ else
+ fail_ff(ff, "initialized D flip-flops are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DFF is supported with this init val. Just pick a type.
+ if (ff.has_ce && !(supported_dffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFF] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFF] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFF] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ // Nope. Will need to add enable and go the DFFE route.
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_DFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding a set or reset pin.
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_srst();
+ ff.ce_over_srst = true;
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_srst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try adding both.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
+
+ void legalize_sdffce(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_SDFFCE] | supported_cells[FF_SDFFE])) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SDFFCE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.convert_ce_over_srst(false);
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_sdff(FfData &ff) {
+ if (!try_flip(ff, supported_sdff)) {
+ ff.unmap_srst();
+ legalize_dff(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (!ff.has_ce) {
+ if (supported_cells[FF_SDFF] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFE] & initmask) {
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.add_dummy_ce();
+ ff.ce_over_srst = true;
+ } else {
+ log_assert(0);
+ }
+ } else {
+ log_assert(!ff.ce_over_srst);
+ if (supported_cells[FF_SDFFE] & initmask) {
+ // OK
+ } else if (supported_cells[FF_SDFFCE] & initmask) {
+ ff.convert_ce_over_srst(true);
+ } else if (supported_cells[FF_SDFF] & initmask) {
+ ff.unmap_ce();
+ } else {
+ log_assert(0);
+ }
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_adff(FfData &ff) {
+ if (!try_flip(ff, supported_adff)) {
+ if (!supported_adff)
+ fail_ff(ff, "dffs with async set or reset are not supported");
+ if (!(supported_dff & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized dffs are not supported");
+
+ // 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_rlatch) & (INIT_0_R1 | INIT_1_R0)))
+ fail_ff(ff, "unsupported initial value and async reset value combination");
+
+ // If we have to unmap enable anyway, do it before breakdown.
+ if (ff.has_ce && !supported_cells[FF_ADFFE])
+ ff.unmap_ce();
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ emulate_split_init_arst(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_adffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ADFF] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFF] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ADFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ // Try converting to async load.
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.arst_to_aload();
+ legalize_finish(ff);
+ return;
+ }
+ // Try convertint to SR.
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.arst_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
+
+ void legalize_aldff(FfData &ff) {
+ if (!try_flip(ff, supported_aldff)) {
+ ff.aload_to_sr();
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_aldffe & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_ALDFF] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_DFFSR] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+ if (supported_cells[FF_ALDFFE] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ if (supported_cells[FF_DFFSRE] & initmask) {
+ ff.aload_to_sr();
+ legalize_finish(ff);
+ return;
+ }
+ log_assert(0);
+ }
+
+ void legalize_dffsr(FfData &ff) {
+ if (!try_flip(ff, supported_dffsr)) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+
+ int initmask = get_initmask(ff);
+ if (ff.has_ce && !(supported_cells[FF_DFFSRE] & initmask)) {
+ ff.unmap_ce();
+ }
+
+ if (!ff.has_ce) {
+ if (supported_cells[FF_DFFSR] & initmask) {
+ legalize_finish(ff);
+ return;
+ }
+ ff.add_dummy_ce();
+ }
+
+ log_assert(supported_cells[FF_DFFSRE] & initmask);
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatch(FfData &ff) {
+ if (!try_flip(ff, supported_dlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ // Some DLATCH is supported with this init val. Just pick a type.
+ if (supported_cells[FF_DLATCH] & initmask) {
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ADLATCH] & initmask) {
+ ff.add_dummy_arst();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.add_dummy_sr();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFF] & initmask) {
+ ff.add_dummy_clk();
+ legalize_finish(ff);
+ } else if (supported_cells[FF_ALDFFE] & initmask) {
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ legalize_finish(ff);
+ } else if (supported_sr & initmask) {
+ ff.aload_to_sr();
+ legalize_sr(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_adlatch(FfData &ff) {
+ if (!try_flip(ff, supported_adlatch)) {
+ if (!supported_adlatch)
+ fail_ff(ff, "D latches with async set or reset are not supported");
+ if (!(supported_dlatch & (INIT_0 | INIT_1)))
+ fail_ff(ff, "initialized D latches are not supported");
+
+ // 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 adlatch + dlatch + dlatch + mux.
+
+ if (ff.cell)
+ log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(ff.module->name), log_id(ff.cell->name));
+ ff.remove();
+
+ emulate_split_init_arst(ff);
+ return;
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_ADLATCH] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ ff.arst_to_sr();
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_dlatchsr(FfData &ff) {
+ if (!try_flip(ff, supported_cells[FF_DLATCHSR])) {
+ emulate_split_set_clr(ff);
+ return;
+ }
+ legalize_finish(ff);
+ }
+
+ void legalize_rlatch(FfData &ff) {
+ if (!try_flip(ff, supported_rlatch)) {
+ if (!supported_dlatch)
+ fail_ff(ff, "D latches are not supported");
+ else
+ fail_ff(ff, "initialized D latches are not supported");
+ }
+
+ int initmask = get_initmask(ff);
+ if (((supported_dlatch_plain & 7) * 0x111) & initmask) {
+ ff.arst_to_aload();
+ legalize_dlatch(ff);
+ } else if (supported_sr & initmask) {
+ ff.arst_to_sr();
+ legalize_sr(ff);
+ } else if (supported_adff & initmask) {
+ ff.add_dummy_clk();
+ legalize_adff(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+
+ void legalize_sr(FfData &ff) {
+ if (!try_flip(ff, supported_sr)) {
+ if (!supported_sr)
+ fail_ff(ff, "sr latches are not supported");
+ else
+ fail_ff(ff, "initialized sr latches are not supported");
+ }
+ int initmask = get_initmask(ff);
+ if (supported_cells[FF_SR] & initmask) {
+ // OK
+ } else if (supported_cells[FF_DLATCHSR] & initmask) {
+ // Upgrade to DLATCHSR.
+ ff.add_dummy_aload();
+ } else if (supported_cells[FF_DFFSR] & initmask) {
+ // Upgrade to DFFSR.
+ ff.add_dummy_clk();
+ } else if (supported_cells[FF_DFFSRE] & initmask) {
+ // Upgrade to DFFSRE.
+ ff.add_dummy_clk();
+ ff.add_dummy_ce();
+ } else if (supported_cells[FF_ADLATCH] & (initmask << 4)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S1;
+ ff.val_arst = State::S0;
+ } else if (supported_cells[FF_ADLATCH] & (flip_initmask(initmask) << 8)) {
+ ff.has_sr = false;
+ ff.has_aload = true;
+ ff.has_arst = true;
+ ff.pol_arst = ff.pol_clr;
+ ff.sig_arst = ff.sig_clr;
+ ff.sig_aload = ff.sig_set;
+ ff.pol_aload = ff.pol_set;
+ ff.sig_ad = State::S0;
+ ff.val_arst = State::S1;
+ ff.remove_init();
+ Wire *new_q = ff.module->addWire(NEW_ID);
+ if (ff.is_fine)
+ ff.module->addNotGate(NEW_ID, new_q, ff.sig_q);
+ else
+ ff.module->addNot(NEW_ID, new_q, ff.sig_q);
+ ff.sig_q = new_q;
+ if (ff.val_init == State::S0)
+ ff.val_init = State::S1;
+ else if (ff.val_init == State::S1)
+ ff.val_init = State::S0;
+ } else {
+ log_assert(0);
+ }
+ legalize_finish(ff);
+ }
+
+ void fixup_reset_x(FfData &ff, int supported) {
+ for (int i = 0; i < ff.width; i++) {
+ int mask;
+ if (ff.val_init[i] == State::S0)
+ mask = INIT_0;
+ else if (ff.val_init[i] == State::S1)
+ mask = INIT_1;
+ else
+ mask = INIT_X;
+ if (ff.has_arst) {
+ if (ff.val_arst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_arst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_arst[i] = State::S1;
+ }
+ }
+ if (ff.has_srst) {
+ if (ff.val_srst[i] == State::Sx) {
+ if (!(supported & (mask << 8)))
+ ff.val_srst[i] = State::S0;
+ if (!(supported & (mask << 4)))
+ ff.val_srst[i] = State::S1;
+ }
+ }
+ }
+ }
+
+ void legalize_ff(FfData &ff) {
+ if (ff.has_gclk)
+ return;
+
+ // TODO: consider supporting coarse as well.
+ if (!ff.is_fine)
+ return;
+
+ if (mince && ff.has_ce && ff.sig_ce[0].wire && ce_used[ff.sig_ce[0]] < mince)
+ ff.unmap_ce();
+ if (minsrst && ff.has_srst && ff.sig_srst[0].wire && srst_used[ff.sig_srst[0]] < minsrst)
+ ff.unmap_srst();
+
+ if (ff.has_clk) {
+ if (ff.has_sr) {
+ legalize_dffsr(ff);
+ } else if (ff.has_aload) {
+ legalize_aldff(ff);
+ } else if (ff.has_arst) {
+ legalize_adff(ff);
+ } else if (ff.has_srst) {
+ if (ff.has_ce && ff.ce_over_srst)
+ legalize_sdffce(ff);
+ else
+ legalize_sdff(ff);
+ } else {
+ legalize_dff(ff);
+ }
+ } else if (ff.has_aload) {
+ if (ff.has_sr) {
+ legalize_dlatchsr(ff);
+ } else if (ff.has_arst) {
+ legalize_adlatch(ff);
+ } else {
+ legalize_dlatch(ff);
+ }
+ } else {
+ if (ff.has_sr) {
+ legalize_sr(ff);
+ } else if (ff.has_arst) {
+ legalize_rlatch(ff);
+ } else {
+ log_assert(0);
+ }
+ }
+ }
+
+ void flip_pol(FfData &ff, SigSpec &sig, bool &pol) {
+ if (sig == State::S0) {
+ sig = State::S1;
+ } else if (sig == State::S1) {
+ sig = State::S0;
+ } else if (ff.is_fine) {
+ sig = ff.module->NotGate(NEW_ID, sig);
+ } else {
+ sig = ff.module->Not(NEW_ID, sig);
+ }
+ pol = !pol;
+ }
+
+ void legalize_finish(FfData &ff) {
+ int ff_type = get_ff_type(ff);
+ int initmask = get_initmask(ff);
+ log_assert(supported_cells[ff_type] & initmask);
+ int ff_neg = 0;
+ if (ff.has_sr) {
+ if (!ff.pol_clr)
+ ff_neg |= NEG_R;
+ if (!ff.pol_set)
+ ff_neg |= NEG_S;
+ }
+ if (ff.has_arst) {
+ if (!ff.pol_arst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_srst) {
+ if (!ff.pol_srst)
+ ff_neg |= NEG_R;
+ }
+ if (ff.has_aload) {
+ if (!ff.pol_aload)
+ ff_neg |= NEG_L;
+ }
+ if (ff.has_clk) {
+ if (!ff.pol_clk)
+ ff_neg |= NEG_C;
+ }
+ if (ff.has_ce) {
+ if (!ff.pol_ce)
+ ff_neg |= NEG_CE;
+ }
+ 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_CE)
+ flip_pol(ff, ff.sig_ce, ff.pol_ce);
+ if (ff.has_sr) {
+ if (xneg & NEG_R)
+ flip_pol(ff, ff.sig_clr, ff.pol_clr);
+ if (xneg & NEG_S)
+ flip_pol(ff, ff.sig_set, ff.pol_set);
+ }
+ if (ff.has_arst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_arst, ff.pol_arst);
+ if (ff.has_srst && xneg & NEG_R)
+ flip_pol(ff, ff.sig_srst, ff.pol_srst);
+ if (xneg & NEG_L)
+ flip_pol(ff, ff.sig_aload, ff.pol_aload);
+ if (xneg & NEG_C)
+ flip_pol(ff, ff.sig_clk, ff.pol_clk);
+ ff_neg ^= xneg;
+ }
+
+ fixup_reset_x(ff, supported_cells_neg[ff_type][ff_neg]);
+ ff.emit();
+ }
+
+ 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;
+ char pol_c = 0;
+ char pol_l = 0;
+ char pol_s = 0;
+ char pol_r = 0;
+ char pol_ce = 0;
+ char srval = 0;
+ if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') {
+ ff_type = FF_SR;
+ pol_s = celltype[5];
+ pol_r = celltype[6];
+ } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') {
+ ff_type = FF_DFF;
+ pol_c = celltype[6];
+ } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') {
+ ff_type = FF_DFFE;
+ pol_c = celltype[7];
+ pol_ce = celltype[8];
+ } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') {
+ ff_type = FF_ADFF;
+ 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 = FF_ADFFE;
+ pol_c = celltype[7];
+ pol_r = celltype[8];
+ srval = celltype[9];
+ pol_ce = celltype[10];
+ } else if (celltype.substr(0, 8) == "$_ALDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type = FF_ALDFF;
+ pol_c = celltype[8];
+ pol_l = celltype[9];
+ } else if (celltype.substr(0, 9) == "$_ALDFFE_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type = FF_ALDFFE;
+ pol_c = celltype[9];
+ pol_l = celltype[10];
+ pol_ce = celltype[11];
+ } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') {
+ ff_type = 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 = FF_DFFSRE;
+ pol_c = celltype[9];
+ pol_s = celltype[10];
+ pol_r = celltype[11];
+ pol_ce = celltype[12];
+ } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type = FF_SDFF;
+ 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 = FF_SDFFE;
+ pol_c = celltype[8];
+ pol_r = celltype[9];
+ srval = celltype[10];
+ pol_ce = celltype[11];
+ } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') {
+ ff_type = FF_SDFFCE;
+ pol_c = celltype[9];
+ pol_r = celltype[10];
+ srval = celltype[11];
+ pol_ce = celltype[12];
+ } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') {
+ ff_type = FF_DLATCH;
+ pol_l = celltype[9];
+ } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') {
+ ff_type = FF_ADLATCH;
+ pol_l = celltype[9];
+ pol_r = celltype[10];
+ srval = celltype[11];
+ } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') {
+ ff_type = FF_DLATCHSR;
+ pol_l = 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_l, NEG_L),
+ std::make_pair(pol_s, NEG_S),
+ std::make_pair(pol_r, NEG_R),
+ std::make_pair(pol_ce, NEG_CE),
+ }) {
+ 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;
+ }
+ }
+ int initmask;
+ if (inittype == "x") {
+ initmask = 0x111;
+ } else if (inittype == "0") {
+ initmask = 0x333;
+ } else if (inittype == "1") {
+ initmask = 0x555;
+ } else if (inittype == "r") {
+ if (srval == 0)
+ log_error("init type r not valid for cell type %s.\n", celltype.c_str());
+ initmask = 0x537;
+ } else if (inittype == "01") {
+ initmask = 0x777;
+ } else {
+ log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str());
+ }
+ if (srval == '0') {
+ initmask &= 0x0ff;
+ } else if (srval == '1') {
+ initmask &= 0xf0f;
+ } else if (srval != 0 && srval != '?') {
+ goto unrecognized;
+ }
+ for (int neg = 0; neg < NUM_NEG; neg++)
+ if ((neg & mask) == match)
+ supported_cells_neg[ff_type][neg] |= initmask;
+ supported_cells[ff_type] |= 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_aldff = supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE] | supported_dffsr;
+ supported_aldffe = supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_adff = supported_cells[FF_ADFF] | supported_cells[FF_ADFFE] | supported_dffsr | supported_aldff;
+ supported_adffe = supported_cells[FF_ADFFE] | supported_cells[FF_ALDFFE] | supported_cells[FF_DFFSRE];
+ supported_sdff = supported_cells[FF_SDFF] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_adff | supported_sdff;
+ supported_dffe = supported_cells[FF_DFFE] | supported_cells[FF_DFFSRE] | supported_cells[FF_ALDFFE] | supported_cells[FF_ADFFE] | supported_cells[FF_SDFFE] | supported_cells[FF_SDFFCE];
+ supported_sr_plain = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR];
+ supported_sr = supported_sr_plain;
+ supported_sr |= (supported_cells[FF_ADLATCH] >> 4 & 7) * 0x111;
+ supported_sr |= (flip_initmask(supported_cells[FF_ADLATCH]) >> 4 & 7) * 0x111;
+ supported_dlatch_plain = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH] | supported_cells[FF_DLATCHSR] | supported_cells[FF_ALDFF] | supported_cells[FF_ALDFFE];
+ supported_dlatch = supported_dlatch_plain | supported_sr_plain;
+ supported_rlatch = supported_adff | (supported_dlatch & 7) * 0x111;
+ supported_adlatch = supported_cells[FF_ADLATCH] | 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;
+
+ FfData ff(&initvals, cell);
+ if (ff.has_ce && ff.sig_ce[0].wire)
+ ce_used[ff.sig_ce[0]] += ff.width;
+ if (ff.has_srst && ff.sig_srst[0].wire)
+ srst_used[ff.sig_srst[0]] += ff.width;
+ }
+ }
+ for (auto cell : module->selected_cells())
+ {
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+ continue;
+ FfData ff(&initvals, cell);
+ legalize_ff(ff);
+ }
+ }
+
+ 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 c189d649b..252baae9a 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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 = from[8];
- char from_set_pol = from[9];
- char from_clr_pol = from[10];
- char to_clk_pol = to[6];
- char to_rst_pol = 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 = from[6];
- char from_rst_pol = from[7];
- char to_clk_pol = 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);
@@ -552,7 +414,7 @@ struct DfflibmapPass : public Pass {
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) 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..7312015f1
--- /dev/null
+++ b/passes/techmap/dffunmap.cc
@@ -0,0 +1,106 @@
+/*
+ * 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_ce)
+ continue;
+ ff.unmap_ce();
+ } else if (srst_only) {
+ if (!ff.has_srst)
+ continue;
+ ff.unmap_srst();
+ } else {
+ if (!ff.has_ce && !ff.has_srst)
+ continue;
+ ff.unmap_ce_srst();
+ }
+
+ ff.emit();
+ }
+ }
+ }
+} DffunmapPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc
index 7278cb680..137d22170 100644
--- a/passes/techmap/extract.cc
+++ b/passes/techmap/extract.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -74,6 +74,7 @@ public:
param_int(ID::CTRL_IN_WIDTH)
param_int(ID::CTRL_OUT_WIDTH)
param_int(ID::OFFSET)
+ param_int(ID::PORTID)
param_int(ID::PRIORITY)
param_int(ID::RD_PORTS)
param_int(ID::SIZE)
@@ -354,7 +355,7 @@ struct ExtractPass : public Pass {
log("\n");
log("This pass looks for subcircuits that are isomorphic to any of the modules\n");
log("in the given map file and replaces them with instances of this modules. The\n");
- log("map file can be a Verilog source file (*.v) or an ilang file (*.il).\n");
+ log("map file can be a Verilog source file (*.v) or an RTLIL source file (*.il).\n");
log("\n");
log(" -map <map_file>\n");
log(" use the modules in this file as reference. This option can be used\n");
@@ -409,7 +410,7 @@ struct ExtractPass : public Pass {
log("the following options are to be used instead of the -map option.\n");
log("\n");
log(" -mine <out_file>\n");
- log(" mine for frequent subcircuits and write them to the given ilang file\n");
+ log(" mine for frequent subcircuits and write them to the given RTLIL file\n");
log("\n");
log(" -mine_cells_span <min> <max>\n");
log(" only mine for subcircuits with the specified number of cells\n");
@@ -578,7 +579,7 @@ struct ExtractPass : public Pass {
}
if (map_filenames.empty() && mine_outfile.empty())
- log_cmd_error("Missing option -map <verilog_or_ilang_file> or -mine <output_ilang_file>.\n");
+ log_cmd_error("Missing option -map <verilog_or_rtlil_file> or -mine <output_rtlil_file>.\n");
RTLIL::Design *map = nullptr;
@@ -606,7 +607,7 @@ struct ExtractPass : public Pass {
delete map;
log_cmd_error("Can't open map file `%s'.\n", filename.c_str());
}
- Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog"));
+ Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : "verilog"));
f.close();
if (filename.size() <= 3 || filename.compare(filename.size()-3, std::string::npos, ".il") != 0) {
@@ -744,7 +745,7 @@ struct ExtractPass : public Pass {
f.open(mine_outfile.c_str(), std::ofstream::trunc);
if (f.fail())
log_error("Can't open output file `%s'.\n", mine_outfile.c_str());
- Backend::backend_call(map, &f, mine_outfile, "ilang");
+ Backend::backend_call(map, &f, mine_outfile, "rtlil");
f.close();
}
diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc
index 56b2ea584..9c814af23 100644
--- a/passes/techmap/extract_counter.cc
+++ b/passes/techmap/extract_counter.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2017 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index 3fcff01c3..117fdd54c 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,7 +33,7 @@ struct ExtractFaConfig
int maxbreadth = 6;
};
-// http://svn.clifford.at/handicraft/2016/bindec/bindec.c
+// http://svn.clairexen.net/handicraft/2016/bindec/bindec.c
int bindec(unsigned char v)
{
int r = v & 1;
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index 07b4200cc..892e9a364 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -152,10 +152,10 @@ struct ExtractReducePass : public Pass
log_assert(y.size() == 1);
// Should only continue if there is one fanout back into a cell (not to a port)
- if (sig_to_sink[y[0]].size() != 1)
+ if (sig_to_sink[y].size() != 1 || port_sigs.count(y))
break;
- x = *sig_to_sink[y[0]].begin();
+ x = *sig_to_sink[y].begin();
}
sinks.insert(head_cell);
@@ -183,13 +183,15 @@ struct ExtractReducePass : public Pass
continue;
}
+ auto xy = sigmap(x->getPort(ID::Y));
+
//If this signal drives a port, add it to the sinks
//(even though it may not be the end of a chain)
- if(port_sigs.count(x) && !consumed_cells.count(x))
+ if(port_sigs.count(xy) && !consumed_cells.count(x))
sinks.insert(x);
//It's a match, search everything out from it
- auto& next = sig_to_sink[x];
+ auto& next = sig_to_sink[xy];
for(auto z : next)
next_loads.insert(z);
}
@@ -224,89 +226,60 @@ struct ExtractReducePass : public Pass
if(consumed_cells.count(head_cell))
continue;
- pool<Cell*> cur_supercell;
+ dict<SigBit, int> sources;
+ int inner_cells = 0;
std::deque<Cell*> bfs_queue = {head_cell};
while (bfs_queue.size())
{
Cell* x = bfs_queue.front();
bfs_queue.pop_front();
- cur_supercell.insert(x);
+ for (auto port: {ID::A, ID::B}) {
+ auto bit = sigmap(x->getPort(port)[0]);
- auto a = sigmap(x->getPort(ID::A));
- log_assert(a.size() == 1);
+ bool sink_single = sig_to_sink[bit].size() == 1 && !port_sigs.count(bit);
- // Must have only one sink unless we're going off chain
- // XXX: Check that it is indeed this node?
- if( allow_off_chain || (sig_to_sink[a[0]].size() + port_sigs.count(a[0]) == 1) )
- {
- Cell* cell_a = sig_to_driver[a[0]];
- if(cell_a && IsRightType(cell_a, gt))
- {
- // The cell here is the correct type, and it's definitely driving
- // this current cell.
- bfs_queue.push_back(cell_a);
- }
- }
+ Cell* drv = sig_to_driver[bit];
+ bool drv_ok = drv && drv->type == head_cell->type;
- auto b = sigmap(x->getPort(ID::B));
- log_assert(b.size() == 1);
-
- // Must have only one sink
- // XXX: Check that it is indeed this node?
- if( allow_off_chain || (sig_to_sink[b[0]].size() + port_sigs.count(b[0]) == 1) )
- {
- Cell* cell_b = sig_to_driver[b[0]];
- if(cell_b && IsRightType(cell_b, gt))
- {
- // The cell here is the correct type, and it's definitely driving only
- // this current cell.
- bfs_queue.push_back(cell_b);
+ if (drv_ok && (allow_off_chain || sink_single)) {
+ inner_cells++;
+ bfs_queue.push_back(drv);
+ } else {
+ sources[bit]++;
}
}
}
- log(" Cells:\n");
- for (auto x : cur_supercell)
- log(" %s\n", x->name.c_str());
-
- if (cur_supercell.size() > 1)
+ if (inner_cells)
{
// Worth it to create reduce cell
log(" Creating $reduce_* cell!\n");
- pool<SigBit> input_pool;
- pool<SigBit> input_pool_intermed;
- for (auto x : cur_supercell)
- {
- input_pool.insert(sigmap(x->getPort(ID::A))[0]);
- input_pool.insert(sigmap(x->getPort(ID::B))[0]);
- input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]);
- }
- SigSpec input;
- for (auto b : input_pool)
- if (input_pool_intermed.count(b) == 0)
- input.append(b);
-
SigBit output = sigmap(head_cell->getPort(ID::Y)[0]);
- auto new_reduce_cell = module->addCell(NEW_ID,
- gt == GateType::And ? ID($reduce_and) :
- gt == GateType::Or ? ID($reduce_or) :
- gt == GateType::Xor ? ID($reduce_xor) : "");
- new_reduce_cell->setParam(ID::A_SIGNED, 0);
- new_reduce_cell->setParam(ID::A_WIDTH, input.size());
- new_reduce_cell->setParam(ID::Y_WIDTH, 1);
- new_reduce_cell->setPort(ID::A, input);
- new_reduce_cell->setPort(ID::Y, output);
-
- if(allow_off_chain)
- consumed_cells.insert(head_cell);
- else
- {
- for (auto x : cur_supercell)
- consumed_cells.insert(x);
+ SigSpec input;
+ for (auto it : sources) {
+ bool cond;
+ if (head_cell->type == ID($_XOR_))
+ cond = it.second & 1;
+ else
+ cond = it.second != 0;
+ if (cond)
+ input.append(it.first);
+ }
+
+ if (head_cell->type == ID($_AND_)) {
+ module->addReduceAnd(NEW_ID, input, output);
+ } else if (head_cell->type == ID($_OR_)) {
+ module->addReduceOr(NEW_ID, input, output);
+ } else if (head_cell->type == ID($_XOR_)) {
+ module->addReduceXor(NEW_ID, input, output);
+ } else {
+ log_assert(false);
}
+
+ consumed_cells.insert(head_cell);
}
}
}
diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc
index 9b350456f..48d9600fa 100644
--- a/passes/techmap/extractinv.cc
+++ b/passes/techmap/extractinv.cc
@@ -1,8 +1,8 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
+ * 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
diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc
index b5f55cffa..7e6df5d2c 100644
--- a/passes/techmap/flatten.cc
+++ b/passes/techmap/flatten.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -77,7 +77,7 @@ struct FlattenWorker
{
bool ignore_wb = false;
- void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, std::vector<RTLIL::Cell*> &new_cells)
+ void flatten_cell(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, SigMap &sigmap, std::vector<RTLIL::Cell*> &new_cells)
{
// Copy the contents of the flattened cell
@@ -122,6 +122,9 @@ struct FlattenWorker
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);
+ for (auto new_proc_sync : new_proc->syncs)
+ for (auto &memwr_action : new_proc_sync->mem_write_actions)
+ memwr_action.memid = memory_map.at(memwr_action.memid).str();
auto rewriter = [&](RTLIL::SigSpec &sig) { map_sigspec(wire_map, sig); };
new_proc->rewrite_sigspecs(rewriter);
design->select(module, new_proc);
@@ -130,10 +133,10 @@ struct FlattenWorker
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))) {
+ if (new_cell->has_memid()) {
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)) {
+ } else if (new_cell->is_mem_cell()) {
IdString memid = new_cell->getParam(ID::MEMID).decode_string();
new_cell->setParam(ID::MEMID, Const(concat_name(cell, memid).str()));
}
@@ -152,18 +155,16 @@ struct FlattenWorker
// Attach port connections of the flattened cell
- 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))
+ for (auto bit : tpl_conn.second)
tpl_driven.insert(bit);
for (auto &tpl_conn : tpl->connections())
- for (auto bit : tpl_sigmap(tpl_conn.first))
+ for (auto bit : tpl_conn.first)
tpl_driven.insert(bit);
- SigMap sigmap(module);
for (auto &port_it : cell->connections())
{
IdString port_name = port_it.first;
@@ -181,16 +182,19 @@ struct FlattenWorker
RTLIL::Wire *tpl_wire = tpl->wire(port_name);
RTLIL::SigSig new_conn;
+ bool is_signed = false;
if (tpl_wire->port_output && !tpl_wire->port_input) {
new_conn.first = port_it.second;
new_conn.second = tpl_wire;
+ is_signed = tpl_wire->is_signed;
} else if (!tpl_wire->port_output && tpl_wire->port_input) {
new_conn.first = tpl_wire;
new_conn.second = port_it.second;
+ is_signed = new_conn.second.is_wire() && new_conn.second.as_wire()->is_signed;
} else {
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_driven.count(tpl_sigmap(sig_tpl[i]))) {
+ if (tpl_driven.count(sig_tpl[i])) {
new_conn.first.append(sig_mod[i]);
new_conn.second.append(sig_tpl[i]);
} else {
@@ -205,14 +209,15 @@ struct FlattenWorker
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()));
+ new_conn.second.extend_u0(new_conn.first.size(), is_signed);
log_assert(new_conn.first.size() == new_conn.second.size());
if (sigmap(new_conn.first).has_const())
- log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n",
+ log_error("Cell port %s.%s.%s is driving constant bits: %s <= %s\n",
log_id(module), log_id(cell), log_id(port_it.first), log_signal(new_conn.first), log_signal(new_conn.second));
module->connect(new_conn);
+ sigmap.add(new_conn.first, new_conn.second);
}
module->remove(cell);
@@ -223,6 +228,7 @@ struct FlattenWorker
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
return;
+ SigMap sigmap(module);
std::vector<RTLIL::Cell*> worklist = module->selected_cells();
while (!worklist.empty())
{
@@ -246,7 +252,7 @@ struct FlattenWorker
// If a design is fully selected and has a top module defined, topological sorting ensures that all cells
// added during flattening are black boxes, and flattening is finished in one pass. However, when flattening
// individual modules, this isn't the case, and the newly added cells might have to be flattened further.
- flatten_cell(design, module, cell, tpl, worklist);
+ flatten_cell(design, module, cell, tpl, sigmap, worklist);
}
}
};
diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc
index b808a8d8e..c1b947221 100644
--- a/passes/techmap/hilomap.cc
+++ b/passes/techmap/hilomap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc
index a3b5b698d..68c22c317 100644
--- a/passes/techmap/insbuf.cc
+++ b/passes/techmap/insbuf.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index e8530a034..437ad5156 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -43,26 +43,28 @@ struct IopadmapPass : public Pass {
log("can only map to very simple PAD cells. Use 'techmap' to further map\n");
log("the resulting cells to more sophisticated PAD cells.\n");
log("\n");
- log(" -inpad <celltype> <portname>[:<portname>]\n");
+ log(" -inpad <celltype> <in_port>[:<ext_port>]\n");
log(" Map module input ports to the given cell type with the\n");
log(" given output port name. if a 2nd portname is given, the\n");
- log(" signal is passed through the pad call, using the 2nd\n");
+ log(" signal is passed through the pad cell, using the 2nd\n");
log(" portname as the port facing the module port.\n");
log("\n");
- log(" -outpad <celltype> <portname>[:<portname>]\n");
- log(" -inoutpad <celltype> <portname>[:<portname>]\n");
+ log(" -outpad <celltype> <out_port>[:<ext_port>]\n");
+ log(" -inoutpad <celltype> <io_port>[:<ext_port>]\n");
log(" Similar to -inpad, but for output and inout ports.\n");
log("\n");
- log(" -toutpad <celltype> <portname>:<portname>[:<portname>]\n");
+ log(" -toutpad <celltype> <oe_port>:<out_port>[:<ext_port>]\n");
log(" Merges $_TBUF_ cells into the output pad cell. This takes precedence\n");
log(" over the other -outpad cell. The first portname is the enable input\n");
- log(" of the tristate driver.\n");
+ log(" of the tristate driver, which can be prefixed with `~` for negative\n");
+ log(" polarity enable.\n");
log("\n");
- log(" -tinoutpad <celltype> <portname>:<portname>:<portname>[:<portname>]\n");
+ log(" -tinoutpad <celltype> <oe_port>:<in_port>:<out_port>[:<ext_port>]\n");
log(" Merges $_TBUF_ cells into the inout pad cell. This takes precedence\n");
log(" over the other -inoutpad cell. The first portname is the enable input\n");
log(" of the tristate driver and the 2nd portname is the internal output\n");
- log(" buffering the external signal.\n");
+ log(" buffering the external signal. Like with `-toutpad`, the enable can\n");
+ log(" be marked as negative polarity by prefixing the name with `~`.\n");
log("\n");
log(" -ignore <celltype> <portname>[:<portname>]*\n");
log(" Skips mapping inputs/outputs that are already connected to given\n");
@@ -106,6 +108,7 @@ struct IopadmapPass : public Pass {
std::string inoutpad_celltype, inoutpad_portname_io, inoutpad_portname_pad;
std::string toutpad_celltype, toutpad_portname_oe, toutpad_portname_i, toutpad_portname_pad;
std::string tinoutpad_celltype, tinoutpad_portname_oe, tinoutpad_portname_o, tinoutpad_portname_i, tinoutpad_portname_pad;
+ bool toutpad_neg_oe = false, tinoutpad_neg_oe = false;
std::string widthparam, nameparam;
pool<pair<IdString, IdString>> ignore;
bool flag_bits = false;
@@ -137,6 +140,10 @@ struct IopadmapPass : public Pass {
toutpad_portname_oe = args[++argidx];
split_portname_pair(toutpad_portname_oe, toutpad_portname_i);
split_portname_pair(toutpad_portname_i, toutpad_portname_pad);
+ if (toutpad_portname_oe[0] == '~') {
+ toutpad_neg_oe = true;
+ toutpad_portname_oe = toutpad_portname_oe.substr(1);
+ }
continue;
}
if (arg == "-tinoutpad" && argidx+2 < args.size()) {
@@ -145,6 +152,10 @@ struct IopadmapPass : public Pass {
split_portname_pair(tinoutpad_portname_oe, tinoutpad_portname_o);
split_portname_pair(tinoutpad_portname_o, tinoutpad_portname_i);
split_portname_pair(tinoutpad_portname_i, tinoutpad_portname_pad);
+ if (tinoutpad_portname_oe[0] == '~') {
+ tinoutpad_neg_oe = true;
+ tinoutpad_portname_oe = tinoutpad_portname_oe.substr(1);
+ }
continue;
}
if (arg == "-ignore" && argidx+2 < args.size()) {
@@ -318,6 +329,8 @@ struct IopadmapPass : public Pass {
module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
RTLIL::escape_id(tinoutpad_celltype));
+ if (tinoutpad_neg_oe)
+ en_sig = module->NotGate(NEW_ID, en_sig);
cell->setPort(RTLIL::escape_id(tinoutpad_portname_oe), en_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
@@ -340,6 +353,8 @@ struct IopadmapPass : public Pass {
module->uniquify(stringf("$iopadmap$%s.%s[%d]", log_id(module), log_id(wire), i)),
RTLIL::escape_id(toutpad_celltype));
+ if (toutpad_neg_oe)
+ en_sig = module->NotGate(NEW_ID, en_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname_oe), en_sig);
cell->setPort(RTLIL::escape_id(toutpad_portname_i), data_sig);
cell->attributes[ID::keep] = RTLIL::Const(1);
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 349ccc115..3d0ebaea3 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -384,7 +384,7 @@ void LibertyParser::error(const std::string &str)
exit(1);
}
-/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+/**** BEGIN: http://svn.clairexen.net/tools/trunk/examples/check.h ****/
#define CHECK_NV(result, check) \
do { \
@@ -405,7 +405,7 @@ void LibertyParser::error(const std::string &str)
} \
} while(0)
-/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
+/**** END: http://svn.clairexen.net/tools/trunk/examples/check.h ****/
LibertyAst *find_non_null(LibertyAst *node, const char *name)
{
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index c9ebd06c5..77e305f0b 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc
index f56eff3e5..ef76e0deb 100644
--- a/passes/techmap/lut2mux.cc
+++ b/passes/techmap/lut2mux.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc
index 43f2d97f5..2235bdef9 100644
--- a/passes/techmap/maccmap.cc
+++ b/passes/techmap/maccmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc
index 24109b579..a90d81985 100644
--- a/passes/techmap/muxcover.cc
+++ b/passes/techmap/muxcover.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc
index e1ebfcad8..016789157 100644
--- a/passes/techmap/nlutmap.cc
+++ b/passes/techmap/nlutmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc
index b937d3fb0..ff6bb549b 100644
--- a/passes/techmap/pmuxtree.cc
+++ b/passes/techmap/pmuxtree.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc
index 237c261ae..928182970 100644
--- a/passes/techmap/shregmap.cc
+++ b/passes/techmap/shregmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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();
diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc
index b9d337da4..7d8dba439 100644
--- a/passes/techmap/simplemap.cc
+++ b/passes/techmap/simplemap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +19,7 @@
#include "simplemap.h"
#include "kernel/sigtools.h"
+#include "kernel/ff.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -298,6 +299,30 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell)
}
}
+void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell)
+{
+ SigSpec sel = cell->getPort(ID::S);
+ SigSpec data = cell->getPort(ID::A);
+ int width = GetSize(cell->getPort(ID::Y));
+
+ for (int idx = 0; idx < GetSize(sel); idx++) {
+ SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2);
+ for (int i = 0; i < GetSize(new_data); i += width) {
+ for (int k = 0; k < width; k++) {
+ RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
+ gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src));
+ gate->setPort(ID::A, data[i*2+k]);
+ gate->setPort(ID::B, data[i*2+width+k]);
+ gate->setPort(ID::S, sel[idx]);
+ gate->setPort(ID::Y, new_data[i+k]);
+ }
+ }
+ data = new_data;
+ }
+
+ module->connect(cell->getPort(ID::Y), data);
+}
+
void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
{
SigSpec lut_ctrl = cell->getPort(ID::A);
@@ -305,7 +330,6 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell)
lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int());
for (int idx = 0; GetSize(lut_data) > 1; idx++) {
- SigSpec sig_s = lut_ctrl[idx];
SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2);
for (int i = 0; i < GetSize(lut_data); i += 2) {
RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_));
@@ -367,276 +391,13 @@ void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell)
module->connect(RTLIL::SigSig(sig_y, sig_ab));
}
-void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at(ID::WIDTH).as_int();
- 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_s = cell->getPort(ID::SET);
- RTLIL::SigSpec sig_r = cell->getPort(ID::CLR);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- std::string gate_type = stringf("$_SR_%c%c_", 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::S, sig_s[i]);
- gate->setPort(ID::R, sig_r[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell)
-{
- int width = cell->parameters.at(ID::WIDTH).as_int();
-
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = ID($_FF_);
-
- 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::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell)
+void simplemap_ff(RTLIL::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';
-
- RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DFF_%c_", clk_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::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dffe(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 en_pol = cell->parameters.at(ID::EN_POLARITY).as_bool() ? 'P' : 'N';
-
- RTLIL::SigSpec sig_clk = cell->getPort(ID::CLK);
- RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DFFE_%c%c_", clk_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::E, sig_en);
- gate->setPort(ID::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-void simplemap_dffsr(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 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_clk = cell->getPort(ID::CLK);
- 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("$_DFFSR_%c%c%c_", clk_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::C, sig_clk);
- 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_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 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';
-
- 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(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("$_%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]);
- }
-}
-
-void simplemap_dlatch(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';
-
- RTLIL::SigSpec sig_en = cell->getPort(ID::EN);
- RTLIL::SigSpec sig_d = cell->getPort(ID::D);
- RTLIL::SigSpec sig_q = cell->getPort(ID::Q);
-
- IdString gate_type = stringf("$_DLATCH_%c_", 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::E, sig_en);
- gate->setPort(ID::D, sig_d[i]);
- gate->setPort(ID::Q, sig_q[i]);
- }
-}
-
-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]);
+ FfData ff(nullptr, cell);
+ for (int i = 0; i < ff.width; i++) {
+ FfData fff = ff.slice({i});
+ fff.is_fine = true;
+ fff.emit();
}
}
@@ -662,24 +423,27 @@ void simplemap_get_mappers(dict<IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)>
mappers[ID($nex)] = simplemap_eqne;
mappers[ID($mux)] = simplemap_mux;
mappers[ID($tribuf)] = simplemap_tribuf;
+ mappers[ID($bmux)] = simplemap_bmux;
mappers[ID($lut)] = simplemap_lut;
mappers[ID($sop)] = simplemap_sop;
mappers[ID($slice)] = simplemap_slice;
mappers[ID($concat)] = simplemap_concat;
- mappers[ID($sr)] = simplemap_sr;
+ mappers[ID($sr)] = simplemap_ff;
mappers[ID($ff)] = simplemap_ff;
- mappers[ID($dff)] = simplemap_dff;
- mappers[ID($dffe)] = simplemap_dffe;
- mappers[ID($dffsr)] = simplemap_dffsr;
- 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;
+ mappers[ID($dff)] = simplemap_ff;
+ mappers[ID($dffe)] = simplemap_ff;
+ mappers[ID($dffsr)] = simplemap_ff;
+ mappers[ID($dffsre)] = simplemap_ff;
+ mappers[ID($adff)] = simplemap_ff;
+ mappers[ID($sdff)] = simplemap_ff;
+ mappers[ID($adffe)] = simplemap_ff;
+ mappers[ID($sdffe)] = simplemap_ff;
+ mappers[ID($sdffce)] = simplemap_ff;
+ mappers[ID($aldff)] = simplemap_ff;
+ mappers[ID($aldffe)] = simplemap_ff;
+ mappers[ID($dlatch)] = simplemap_ff;
+ mappers[ID($adlatch)] = simplemap_ff;
+ mappers[ID($dlatchsr)] = simplemap_ff;
}
void simplemap(RTLIL::Module *module, RTLIL::Cell *cell)
@@ -712,7 +476,7 @@ 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, $dffe, $dffsr, $dffsre, $adff, $adffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
+ log(" $sr, $ff, $dff, $dffe, $dffsr, $dffsre, $adff, $adffe, $aldff, $aldffe, $sdff, $sdffe, $sdffce, $dlatch, $adlatch, $dlatchsr\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h
index 5091050a1..c7654f68c 100644
--- a/passes/techmap/simplemap.h
+++ b/passes/techmap/simplemap.h
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* 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,12 +34,7 @@ extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell);
-extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell);
+extern void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell);
extern void simplemap_get_mappers(dict<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers);
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index f98d1564a..5cd78fe28 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -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>
@@ -117,19 +118,14 @@ struct TechmapWorker
return result;
for (auto w : module->wires()) {
- const char *p = w->name.c_str();
- if (*p == '$')
+ if (*w->name.c_str() == '$')
continue;
- const char *q = strrchr(p+1, '.');
- if (q)
- p = q;
-
- if (!strncmp(p, "\\_TECHMAP_", 10)) {
+ if (w->name.contains("_TECHMAP_") && !w->name.contains("_TECHMAP_REPLACE_")) {
TechmapWireData record;
record.wire = w;
record.value = w;
- result[p].push_back(record);
+ result[w->name].push_back(record);
w->set_bool_attribute(ID::keep);
w->set_bool_attribute(ID::_techmap_special_);
}
@@ -164,7 +160,7 @@ struct TechmapWorker
orig_cell_name = cell->name.str();
for (auto tpl_cell : tpl->cells())
- if (tpl_cell->name == ID::_TECHMAP_REPLACE_) {
+ if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) {
module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str());
break;
}
@@ -225,23 +221,21 @@ struct TechmapWorker
}
design->select(module, w);
- if (tpl_w->name.begins_with("\\_TECHMAP_REPLACE_.")) {
- IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), tpl_w->name.c_str() + strlen("\\_TECHMAP_REPLACE_"));
+ if (const char *p = strstr(tpl_w->name.c_str(), "_TECHMAP_REPLACE_.")) {
+ IdString replace_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_"));
Wire *replace_w = module->addWire(replace_name, tpl_w);
module->connect(replace_w, w);
}
}
- SigMap tpl_sigmap(tpl);
pool<SigBit> tpl_written_bits;
-
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))
+ for (auto bit : conn.second)
tpl_written_bits.insert(bit);
for (auto &conn : tpl->connections())
- for (auto bit : tpl_sigmap(conn.first))
+ for (auto bit : conn.first)
tpl_written_bits.insert(bit);
SigMap port_signal_map;
@@ -279,7 +273,7 @@ struct TechmapWorker
SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second;
apply_prefix(cell->name, sig_tpl_pf, module);
for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) {
- if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) {
+ if (tpl_written_bits.count(sig_tpl[i])) {
c.first.append(sig_mod[i]);
c.second.append(sig_tpl_pf[i]);
} else {
@@ -328,12 +322,12 @@ struct TechmapWorker
for (auto tpl_cell : tpl->cells())
{
IdString c_name = tpl_cell->name;
- bool techmap_replace_cell = (c_name == ID::_TECHMAP_REPLACE_);
+ bool techmap_replace_cell = c_name.ends_with("_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_"));
+ else if (const char *p = strstr(tpl_cell->name.c_str(), "_TECHMAP_REPLACE_."))
+ c_name = stringf("%s%s", orig_cell_name.c_str(), p + strlen("_TECHMAP_REPLACE_"));
else
apply_prefix(cell->name, c_name);
@@ -370,13 +364,11 @@ struct TechmapWorker
for (auto &it2 : autopurge_ports)
c->unsetPort(it2);
- if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) {
+ if (c->has_memid()) {
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)) {
+ } else if (c->is_mem_cell()) {
IdString memid = c->getParam(ID::MEMID).decode_string();
apply_prefix(cell->name, memid);
c->setParam(ID::MEMID, Const(memid.c_str()));
@@ -385,10 +377,12 @@ struct TechmapWorker
if (c->attributes.count(ID::src))
c->add_strpool_attribute(ID::src, extra_src_attrs);
- if (techmap_replace_cell)
+ if (techmap_replace_cell) {
for (auto attr : cell->attributes)
if (!c->attributes.count(attr.first))
c->attributes[attr.first] = attr.second;
+ c->attributes.erase(ID::reprocess_after);
+ }
}
for (auto &it : tpl->connections()) {
@@ -426,18 +420,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;
@@ -643,6 +626,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) {
@@ -659,15 +644,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));
}
}
@@ -748,12 +725,16 @@ struct TechmapWorker
for (auto &it : twd)
techmap_wire_names.insert(it.first);
- for (auto &it : twd[ID::_TECHMAP_FAIL_]) {
- RTLIL::SigSpec value = it.value;
- if (value.is_fully_const() && value.as_bool()) {
- log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
- derived_name.c_str(), log_id(it.wire->name), log_signal(value));
- techmap_do_cache[tpl] = false;
+ for (auto &it : twd) {
+ if (!it.first.ends_with("_TECHMAP_FAIL_"))
+ continue;
+ for (const TechmapWireData &elem : it.second) {
+ RTLIL::SigSpec value = elem.value;
+ if (value.is_fully_const() && value.as_bool()) {
+ log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n",
+ derived_name.c_str(), log_id(elem.wire->name), log_signal(value));
+ techmap_do_cache[tpl] = false;
+ }
}
}
@@ -762,7 +743,7 @@ struct TechmapWorker
for (auto &it : twd)
{
- if (!it.first.begins_with("\\_TECHMAP_DO_") || it.second.empty())
+ if (!it.first.contains("_TECHMAP_DO_") || it.second.empty())
continue;
auto &data = it.second.front();
@@ -774,7 +755,7 @@ struct TechmapWorker
const char *p = data.wire->name.c_str();
const char *q = strrchr(p+1, '.');
- q = q ? q : p+1;
+ q = q ? q+1 : p+1;
std::string cmd_string = data.value.as_const().decode_string();
@@ -817,11 +798,31 @@ struct TechmapWorker
}
}
+ // Handle outputs first, as these cannot be remapped.
+ for (auto &conn : cell->connections())
+ {
+ Wire *twire = tpl->wire(conn.first);
+ if (!twire->port_output)
+ continue;
+
+ for (int i = 0; i < GetSize(conn.second); i++) {
+ RTLIL::SigBit bit = sigmap(conn.second[i]);
+ RTLIL::SigBit tplbit(twire, i);
+ cellbits_to_tplbits[bit] = tplbit;
+ }
+ }
+
+ // Now handle inputs, remapping as necessary.
for (auto &conn : cell->connections())
+ {
+ Wire *twire = tpl->wire(conn.first);
+ if (twire->port_output)
+ continue;
+
for (int i = 0; i < GetSize(conn.second); i++)
{
RTLIL::SigBit bit = sigmap(conn.second[i]);
- RTLIL::SigBit tplbit(tpl->wire(conn.first), i);
+ RTLIL::SigBit tplbit(twire, i);
if (bit.wire == nullptr)
{
@@ -836,6 +837,7 @@ struct TechmapWorker
else
cellbits_to_tplbits[bit] = tplbit;
}
+ }
RTLIL::SigSig port_conn;
for (auto &it : port_connmap) {
@@ -870,7 +872,7 @@ struct TechmapWorker
TechmapWires twd = techmap_find_special_wires(tpl);
for (auto &it : twd) {
- if (it.first != ID::_TECHMAP_FAIL_ && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.begins_with("\\_TECHMAP_DO_") && !it.first.begins_with("\\_TECHMAP_DONE_"))
+ if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_"))
log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first));
if (techmap_do_cache[tpl])
for (auto &it2 : it.second)
@@ -912,7 +914,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]);
}
}
}
@@ -961,25 +963,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;
@@ -999,7 +982,7 @@ struct TechmapPass : public Pass {
log(" techmap [-map filename] [selection]\n");
log("\n");
log("This pass implements a very simple technology mapper that replaces cells in\n");
- log("the design with implementations given in form of a Verilog or ilang source\n");
+ log("the design with implementations given in form of a Verilog or RTLIL source\n");
log("file.\n");
log("\n");
log(" -map filename\n");
@@ -1042,7 +1025,9 @@ struct TechmapPass : public Pass {
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
- log("the module name will be used to match the cell.\n");
+ log("the module name will be used to match the cell. Multiple space-separated cell\n");
+ log("types can be listed, and wildcards using [] will be expanded (ie. \"$_DFF_[PN]_\"\n");
+ log("is the same as \"$_DFF_P_ $_DFF_N_\").\n");
log("\n");
log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n");
log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n");
@@ -1111,6 +1096,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");
@@ -1220,7 +1209,7 @@ struct TechmapPass : public Pass {
if (!map->module(mod->name))
map->add(mod->clone());
} else {
- Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend));
+ Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend));
}
}
@@ -1230,8 +1219,27 @@ struct TechmapPass : public Pass {
for (auto module : map->modules()) {
if (module->attributes.count(ID::techmap_celltype) && !module->attributes.at(ID::techmap_celltype).bits.empty()) {
char *p = strdup(module->attributes.at(ID::techmap_celltype).decode_string().c_str());
- for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n"))
- celltypeMap[RTLIL::escape_id(q)].insert(module->name);
+ for (char *q = strtok(p, " \t\r\n"); q; q = strtok(nullptr, " \t\r\n")) {
+ std::vector<std::string> queue;
+ queue.push_back(q);
+ while (!queue.empty()) {
+ std::string name = queue.back();
+ queue.pop_back();
+ auto pos = name.find('[');
+ if (pos == std::string::npos) {
+ // No further expansion.
+ celltypeMap[RTLIL::escape_id(name)].insert(module->name);
+ } else {
+ // Expand [] in this name.
+ auto epos = name.find(']', pos);
+ if (epos == std::string::npos)
+ log_error("Malformed techmap_celltype pattern %s\n", q);
+ for (size_t i = pos + 1; i < epos; i++) {
+ queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos));
+ }
+ }
+ }
+ }
free(p);
} else {
IdString module_name = module->name.begins_with("\\$") ?
@@ -1239,8 +1247,15 @@ struct TechmapPass : public Pass {
celltypeMap[module_name].insert(module->name);
}
}
- for (auto &i : celltypeMap)
+ log_debug("Cell type mappings to use:\n");
+ for (auto &i : celltypeMap) {
i.second.sort(RTLIL::sort_by_id_str());
+ std::string maps = "";
+ for (auto &map : i.second)
+ maps += stringf(" %s", log_id(map));
+ log_debug(" %s:%s\n", log_id(i.first), maps.c_str());
+ }
+ log_debug("\n");
for (auto module : design->modules())
worker.module_queue.insert(module);
diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc
index 79ddb4bd7..f92b4cdb0 100644
--- a/passes/techmap/tribuf.cc
+++ b/passes/techmap/tribuf.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc
index cc0b26bcc..cc208c516 100644
--- a/passes/techmap/zinit.cc
+++ b/passes/techmap/zinit.cc
@@ -1,7 +1,7 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
- * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,6 +19,8 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -57,158 +59,27 @@ 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));
- }
- }
-
- 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($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_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($_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_)
- };
+ FfInitVals initvals(&sigmap, module);
for (auto cell : module->selected_cells())
{
- if (!dff_types.count(cell->type))
+ if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;
- SigSpec sig_d = sigmap(cell->getPort(ID::D));
- SigSpec sig_q = sigmap(cell->getPort(ID::Q));
-
- if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
- continue;
-
- Const initval;
-
- 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;
-
- 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;
- }
- else
- {
- module->connect(sig_q[i], SigSpec(initwire, i));
- }
+ FfData ff(&initvals, cell);
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.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_),
- ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
- {
- t[8] = (t[8] == '0' ? '1' : '0');
- }
- 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($_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');
- }
- cell->type = t;
+ log_signal(ff.sig_q), log_signal(ff.val_init));
+
+ pool<int> bits;
+ for (int i = 0; i < ff.width; i++) {
+ if (ff.val_init.bits[i] == State::S1)
+ bits.insert(i);
+ else if (ff.val_init.bits[i] != State::S0 && all_mode)
+ ff.val_init.bits[i] = State::S0;
}
+ ff.flip_bits(bits);
+ ff.emit();
}
}
}