Added support for multiple clock domains to "abc" pass

This commit is contained in:
Clifford Wolf 2014-12-21 16:52:05 +01:00
parent 25844b5683
commit 76fa527492
2 changed files with 124 additions and 64 deletions

View File

@ -1017,6 +1017,7 @@ public:
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; } inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
inline int size() const { return width_; } inline int size() const { return width_; }
inline bool empty() const { return width_ == 0; }
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }

View File

@ -563,20 +563,24 @@ struct abc_output_filter
void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, 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, int lut_mode, bool dff_mode, std::string clk_str, std::string liberty_file, std::string constr_file, bool cleanup, int lut_mode, bool dff_mode, std::string clk_str,
bool keepff, std::string delay_target, bool fast_mode) bool keepff, std::string delay_target, bool fast_mode, const std::vector<RTLIL::Cell*> &cells)
{ {
module = current_module; module = current_module;
map_autoidx = autoidx++; map_autoidx = autoidx++;
signal_map.clear(); signal_map.clear();
signal_list.clear(); signal_list.clear();
assign_map.set(module);
clk_polarity = true; if (clk_str != "$")
clk_sig = RTLIL::SigSpec(); {
assign_map.set(module);
en_polarity = true; clk_polarity = true;
en_sig = RTLIL::SigSpec(); clk_sig = RTLIL::SigSpec();
en_polarity = true;
en_sig = RTLIL::SigSpec();
}
std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
if (!cleanup) if (!cleanup)
@ -628,7 +632,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
fprintf(f, "%s\n", abc_script.c_str()); fprintf(f, "%s\n", abc_script.c_str());
fclose(f); fclose(f);
if (clk_str.empty()) { if (!clk_str.empty() && clk_str != "$")
{
if (clk_str.find(',') != std::string::npos) { if (clk_str.find(',') != std::string::npos) {
int pos = clk_str.find(','); int pos = clk_str.find(',');
std::string en_str = clk_str.substr(pos+1); std::string en_str = clk_str.substr(pos+1);
@ -648,57 +653,21 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
} }
if (dff_mode && clk_sig.size() == 0) if (dff_mode && clk_sig.empty())
log_error("Clock domain %s not found.\n", clk_str.c_str());
if (dff_mode || !clk_str.empty())
{ {
int best_dff_counter = 0;
typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
std::map<clkdomain_t, int> dff_counters;
for (auto &it : module->cells_)
{
RTLIL::Cell *cell = it.second;
clkdomain_t key;
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
}
else
if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
{
bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
}
else
continue;
if (++dff_counters[key] > best_dff_counter) {
best_dff_counter = dff_counters[key];
clk_polarity = std::get<0>(key);
clk_sig = std::get<1>(key);
en_polarity = std::get<2>(key);
en_sig = std::get<3>(key);
}
}
}
if (dff_mode || !clk_str.empty()) {
if (clk_sig.size() == 0) if (clk_sig.size() == 0)
log("No (matching) clock domain found. Not extracting any FF cells.\n"); log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
else { else {
log("Found (matching) %s clock domain: %s", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
if (en_sig.size() != 0) if (en_sig.size() != 0)
log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
log("\n"); log("\n");
} }
} }
std::vector<RTLIL::Cell*> cells;
cells.reserve(module->cells_.size());
for (auto &it : module->cells_)
if (design->selected(current_module, it.second))
cells.push_back(it.second);
for (auto c : cells) for (auto c : cells)
extract_cell(c, keepff); extract_cell(c, keepff);
@ -716,7 +685,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
if (en_sig.size() != 0) if (en_sig.size() != 0)
mark_port(en_sig); mark_port(en_sig);
handle_loops(); handle_loops();
std::string buffer = stringf("%s/input.blif", tempdir_name.c_str()); std::string buffer = stringf("%s/input.blif", tempdir_name.c_str());
@ -825,7 +794,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
count_gates, GetSize(signal_list), count_input, count_output); count_gates, GetSize(signal_list), count_input, count_output);
log_push(); log_push();
if (count_output > 0) if (count_output > 0)
{ {
log_header("Executing ABC.\n"); log_header("Executing ABC.\n");
@ -1139,14 +1108,13 @@ struct AbcPass : public Pass {
log(" generate netlist using luts of (max) the specified width.\n"); log(" generate netlist using luts of (max) the specified width.\n");
log("\n"); log("\n");
log(" -dff\n"); log(" -dff\n");
log(" also pass $_DFF_?_ cells through ABC (only one clock domain, if many\n"); log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
log(" clock domains are present in a module, the one with the largest number\n"); log(" clock domains are automatically partitioned in clock domains and each\n");
log(" of $_DFF_?_ cells in it is used)\n"); log(" domain is passed through ABC independently.\n");
log("\n"); log("\n");
log(" -clk [!]<signal-name>\n"); log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
log(" use the specified clock domain. (when this option is used in combination\n"); log(" use only the specified clock domain. this is like -dff, but only FF\n");
log(" with -dff, then it falls back to the automatic dection of clock domain\n"); log(" cells that belong to the specified clock domain are used.\n");
log(" if the specified clock is not found in a module.)\n");
log("\n"); log("\n");
log(" -keepff\n"); log(" -keepff\n");
log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
@ -1228,6 +1196,7 @@ struct AbcPass : public Pass {
} }
if (arg == "-clk" && argidx+1 < args.size()) { if (arg == "-clk" && argidx+1 < args.size()) {
clk_str = args[++argidx]; clk_str = args[++argidx];
dff_mode = true;
continue; continue;
} }
if (arg == "-keepff") { if (arg == "-keepff") {
@ -1247,12 +1216,102 @@ struct AbcPass : public Pass {
if (!constr_file.empty() && liberty_file.empty()) if (!constr_file.empty() && liberty_file.empty())
log_cmd_error("Got -constr but no -liberty!\n"); log_cmd_error("Got -constr but no -liberty!\n");
for (auto &mod_it : design->modules_) for (auto mod : design->selected_modules())
if (design->selected(mod_it.second)) { if (mod->processes.size() > 0)
if (mod_it.second->processes.size() > 0) log("Skipping module %s as it contains processes.\n", log_id(mod));
log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str()); else if (!dff_mode || !clk_str.empty())
else abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str, keepff, delay_target, fast_mode, mod->selected_cells());
abc_module(design, mod_it.second, script_file, exe_file, liberty_file, constr_file, cleanup, lut_mode, dff_mode, clk_str, keepff, delay_target, fast_mode); else
{
assign_map.set(mod);
std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
typedef std::tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit;
std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell;
for (auto cell : all_cells)
{
clkdomain_t key;
for (auto &conn : cell->connections())
for (auto bit : conn.second) {
bit = assign_map(bit);
if (bit.wire != nullptr) {
cell_to_bit[cell].insert(bit);
bit_to_cell[bit].insert(cell);
}
}
if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
{
key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
}
else
if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
{
bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
}
else
continue;
unassigned_cells.erase(cell);
expand_queue.insert(cell);
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
}
while (!expand_queue.empty())
{
RTLIL::Cell *cell = *expand_queue.begin();
clkdomain_t key = assigned_cells_reverse.at(cell);
expand_queue.erase(cell);
for (auto bit : cell_to_bit.at(cell)) {
for (auto c : bit_to_cell[bit])
if (unassigned_cells.count(c)) {
unassigned_cells.erase(c);
next_expand_queue.insert(c);
assigned_cells[key].push_back(c);
assigned_cells_reverse[c] = key;
}
bit_to_cell[bit].clear();
}
if (expand_queue.empty())
expand_queue.swap(next_expand_queue);
}
clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
for (auto cell : unassigned_cells) {
assigned_cells[key].push_back(cell);
assigned_cells_reverse[cell] = key;
}
log_header("Summary of detected clock domains:\n");
for (auto &it : assigned_cells)
log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
for (auto &it : assigned_cells) {
clk_polarity = std::get<0>(it.first);
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_mode,
!clk_sig.empty(), "$", keepff, delay_target, fast_mode, it.second);
assign_map.set(mod);
}
} }
assign_map.clear(); assign_map.clear();